[AUDIO] ASOC SSP I2S: migration of ALSA SSP to ASOC Framework.
authorSelma Bensaid <selma.bensaid@intel.com>
Wed, 9 May 2012 12:11:07 +0000 (14:11 +0200)
committerbuildbot <buildbot@intel.com>
Fri, 18 May 2012 17:12:40 +0000 (10:12 -0700)
BZ: 8512

Migration of the modem mix and BT/FM alsa card to Alsa Asoc
framework. It will be actived in a later patch.

Change-Id: Ida7ad09e6124a4f1457268755e8af449d3a7f184
Signed-off-by: Francois Gaffie <francoisx.gaffie@intel.com>
Signed-off-by: Selma Bensaid <selma.bensaid@intel.com>
Reviewed-on: http://android.intel.com:8080/20357
Reviewed-by: Gross, Mark <mark.gross@intel.com>
Tested-by: Mendi, EduardoX <eduardox.mendi@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/es305_codec.c [new file with mode: 0644]
sound/soc/codecs/ifx_modem_codec.c [new file with mode: 0644]
sound/soc/codecs/wl1273_uart.c [new file with mode: 0644]
sound/soc/mid-x86/Kconfig
sound/soc/mid-x86/Makefile
sound/soc/mid-x86/mfld_comms_machine.c [new file with mode: 0644]
sound/soc/mid-x86/mfld_comms_machine.h [new file with mode: 0644]
sound/soc/mid-x86/mid_ssp.c [new file with mode: 0644]
sound/soc/mid-x86/mid_ssp.h [new file with mode: 0644]

index 2e4a2ad..b4af6f9 100644 (file)
@@ -267,6 +267,15 @@ config SND_SOC_WL1273
 config SND_SOC_WM1250_EV1
        tristate
 
+config SND_SOC_WL1273_UART
+       tristate
+
+config SND_SOC_IFX1130_MODEM_CODEC
+       tristate
+
+config SND_SOC_ES305
+       tristate
+
 config SND_SOC_WM8350
        tristate
 
index 73129b4..d581815 100644 (file)
@@ -41,6 +41,9 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
+snd-soc-wl1273-uart-objs := wl1273_uart.o
+snd-soc-ifx-modem-objs := ifx_modem_codec.o
+snd-soc-es305-objs  := es305_codec.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -134,6 +137,9 @@ obj-$(CONFIG_SND_SOC_UDA134X)       += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
+obj-$(CONFIG_SND_SOC_WL1273_UART) += snd-soc-wl1273-uart.o
+obj-$(CONFIG_SND_SOC_IFX1130_MODEM_CODEC) +=ifx_modem_codec.o
+obj-$(CONFIG_SND_SOC_ES305)    +=es305_codec.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)   += snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
diff --git a/sound/soc/codecs/es305_codec.c b/sound/soc/codecs/es305_codec.c
new file mode 100644 (file)
index 0000000..b33dd53
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  es305_codec.c - ALSA ASOC [dummy] Codec driver for Audience ES305
+ *
+ *  Copyright (C) 2011 Intel Corp
+ *  Author:
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#define FORMAT(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/intel_scu_ipc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+/*
+ *
+ * DUMMY SOC CODEC DRIVER for es305
+ *
+ */
+
+static struct snd_soc_dai_driver es305_dai[] = {
+       {
+               .name = "es305 Voice",
+               .id = 0,
+               .playback = {
+                               .stream_name = "es305_Downlink",
+                               .channels_min = 1,
+                               .channels_max = 2,
+                               .rates = SNDRV_PCM_RATE_48000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                               .stream_name = "es305_Uplink",
+                               .channels_min = 1,
+                               .channels_max = 2,
+                               .rates = SNDRV_PCM_RATE_48000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = NULL,
+       },
+
+};
+
+static struct snd_soc_codec_driver soc_codec_es305 = {
+       .probe = NULL,
+       .remove = NULL,
+};
+
+
+static int __devinit es305_device_probe(struct platform_device *pdev)
+{
+       pr_info("es305: codec device probe called for %s\n",
+                       dev_name(&pdev->dev));
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_es305,
+                       es305_dai, ARRAY_SIZE(es305_dai));
+}
+
+static int __devexit es305_device_remove(struct platform_device *pdev)
+{
+       pr_info("es305: codec device remove called\n");
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver es305_codec_driver = {
+       .driver         = {
+               .name           = "es305_codec",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = es305_device_probe,
+       .remove         = es305_device_remove,
+};
+
+static int __init es305_init(void)
+{
+       pr_info("called\n");
+       return platform_driver_register(&es305_codec_driver);
+}
+module_init(es305_init);
+
+static void __exit es305_exit(void)
+{
+       pr_info("called\n");
+       platform_driver_unregister(&es305_codec_driver);
+}
+module_exit(es305_exit);
+
+MODULE_DESCRIPTION("ASoC es305 codec driver");
+MODULE_AUTHOR("Selma Bensaid <selma.bensaid@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:es305");
+
diff --git a/sound/soc/codecs/ifx_modem_codec.c b/sound/soc/codecs/ifx_modem_codec.c
new file mode 100644 (file)
index 0000000..9c1ef66
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *  ifx_modem.c - ALSA ASOC driver for IFX1130 in Combined Interface Mode
+ *
+ *  Copyright (C) 2011 Intel Corp
+ *  Author:
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#define FORMAT(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/intel_scu_ipc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+
+static struct snd_soc_dai_driver ifx_modem_dai[] = {
+       {
+               .name = "IFX_Modem_Mixing",
+               .id = 0,
+               .playback = {
+                               .stream_name = "IFX_Modem_Mix",
+                               .channels_min = 1,
+                               .channels_max = 2,
+                               .rates = SNDRV_PCM_RATE_48000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                               .stream_name = "IFX_Modem_Record",
+                               .channels_min = 1,
+                               .channels_max = 2,
+                               .rates = SNDRV_PCM_RATE_48000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = NULL,
+       },
+
+};
+
+static struct snd_soc_codec_driver soc_codec_ifx_modem = {
+       .probe = NULL,
+       .remove = NULL,
+};
+
+
+static int __devinit ifx_modem_device_probe(struct platform_device *pdev)
+{
+       pr_info("codec device probe called for %s\n",
+                       dev_name(&pdev->dev));
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_ifx_modem,
+                       ifx_modem_dai, ARRAY_SIZE(ifx_modem_dai));
+}
+
+static int __devexit ifx_modem_device_remove(struct platform_device *pdev)
+{
+       pr_info("codec device remove called\n");
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ifx_modem_codec_driver = {
+       .driver         = {
+               .name           = "ifx_modem",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = ifx_modem_device_probe,
+       .remove         = ifx_modem_device_remove,
+};
+
+static int __init ifx_modem_init(void)
+{
+       pr_info("called\n");
+       return platform_driver_register(&ifx_modem_codec_driver);
+}
+module_init(ifx_modem_init);
+
+static void __exit ifx_modem_exit(void)
+{
+       pr_info("called\n");
+       platform_driver_unregister(&ifx_modem_codec_driver);
+}
+module_exit(ifx_modem_exit);
+
+MODULE_DESCRIPTION("ASoC IFX Modem codec driver");
+MODULE_AUTHOR("Selma Bensaid <selma.bensaid@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ifx-modem");
+
diff --git a/sound/soc/codecs/wl1273_uart.c b/sound/soc/codecs/wl1273_uart.c
new file mode 100644 (file)
index 0000000..137cbf0
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  wl1273_uart.c - ALSA ASOC driver for WL1273 in Combined Interface Mode
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Author:
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#define FORMAT(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/intel_scu_ipc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#define WL1273_BT_CODEC_NAME "wl1273_BT"
+#define WL1273_FM_CODEC_NAME "wl1273_FM"
+
+static struct snd_soc_codec_driver soc_codec_wl1273_uart = {
+               .probe = NULL,
+               .remove = NULL,
+};
+
+static int wl1273_uart_startup(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       /*
+        * The FM and BT stream cannot be open in //
+        */
+       if (!strcmp(codec_dai->name, WL1273_FM_CODEC_NAME)) {
+               if (codec->active) {
+                       WARN(1, "WL1273 UART: Open %s unsupported Config\n",
+                                       codec_dai->name);
+                       return -EBUSY;
+               }
+       } else if (!strcmp(codec_dai->name, WL1273_BT_CODEC_NAME)) {
+               if (codec->active &&
+                               (!codec_dai->playback_active) &&
+                               (!codec_dai->capture_active)) {
+                       WARN(1, "WL1273 UART: Open %s unsupported Config\n",
+                                       codec_dai->name);
+                       return -EBUSY;
+               }
+       }
+       return 0;
+}
+
+static struct snd_soc_dai_ops wl1273_uart_dai_ops = {
+       .startup        = wl1273_uart_startup,
+};
+
+static struct snd_soc_dai_driver wl1273_uart_dai[] = {
+       {
+               .name = WL1273_BT_CODEC_NAME,
+               .id = 0,
+               .playback = {
+                               .stream_name = "BT_Playback",
+                               .channels_min = 1,
+                               .channels_max = 1,
+                               .rates = SNDRV_PCM_RATE_8000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                               .stream_name = "BT_Capture",
+                               .channels_min = 1,
+                               .channels_max = 1,
+                               .rates = SNDRV_PCM_RATE_8000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &wl1273_uart_dai_ops,
+       },
+       {
+               .name = WL1273_FM_CODEC_NAME,
+               .id = 1,
+               .playback = {
+                               .stream_name = "FM_Playback",
+                               .channels_min = 0,
+                               .channels_max = 0,
+                               .rates = SNDRV_PCM_RATE_48000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                               .stream_name = "FM_Capture",
+                               .channels_min = 1,
+                               .channels_max = 2,
+                               .rates = SNDRV_PCM_RATE_48000,
+                               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .ops = &wl1273_uart_dai_ops,
+       },
+};
+
+static int __devinit wl1273_uart_device_probe(struct platform_device *pdev)
+{
+       pr_info("codec device probe called for %s\n",
+                       dev_name(&pdev->dev));
+
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_wl1273_uart,
+                       wl1273_uart_dai, ARRAY_SIZE(wl1273_uart_dai));
+}
+
+static int __devexit wl1273_uart_device_remove(struct platform_device *pdev)
+{
+       pr_info("codec device remove called\n");
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wl1273_uart_codec_driver = {
+       .driver         = {
+               .name           = "wl1273_uart",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = wl1273_uart_device_probe,
+       .remove         = wl1273_uart_device_remove,
+};
+
+static int __init wl1273_uart_init(void)
+{
+       pr_info("FCT %s called\n", __func__);
+       return platform_driver_register(&wl1273_uart_codec_driver);
+}
+module_init(wl1273_uart_init);
+
+static void __exit wl1273_uart_exit(void)
+{
+       pr_info("FCT %s called\n", __func__);
+       platform_driver_unregister(&wl1273_uart_codec_driver);
+}
+module_exit(wl1273_uart_exit);
+
+MODULE_DESCRIPTION("ASoC TI WL1273 codec driver");
+MODULE_AUTHOR("Selma Bensaid <selma.bensaid@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:wl1273-uart");
+
index 45a91e8..41c073c 100644 (file)
@@ -53,3 +53,27 @@ config SND_MFLD_MONO_SPEAKER_SUPPORT
           Say Y if you have device with mono speaker. If you say N support for stereo speakers
           will be enabled.
           If unsure select "N".
+
+
+config SND_MFLD_COMMS_MACHINE
+       tristate "Audio Comms SOC Machine Audio driver for Intel Medfield MID platform"
+        depends on EXPERIMENTAL && SND_INTEL_MID_I2S
+        select SND_SOC_WL1273_UART
+        select SND_SOC_IFX1130_MODEM_CODEC
+        select SND_SOC_ES305
+        select SND_SOC_SSP
+       help
+         Say Y here to include support for ALSA SSP soundcard.
+         To compile this driver as a module, choose M here: the module
+         will be called snd-alsa-ssp.ko
+         This is a sound card driver for TI LNW1273 BT/FM Board
+         This ALSA driver offers:
+          - BT device with 1 capture and 1 playback substreams,
+          for BT SCO voice memp record and playback
+          - FM device with 1 capture substream.
+          - VOIP device with 1 capture and 1 playback substreams
+          - IFX Modem device with 1 capture and 1 playback substreams,
+          for audio/tone/alert mixing during Voice Call and Voice Call record
+
+config SND_SOC_SSP
+       tristate
index a6425e0..5a58e4e 100644 (file)
@@ -15,3 +15,9 @@ obj-$(CONFIG_SND_CLV_MACHINE) += snd-soc-clv-machine.o
 
 # DSP driver
 obj-$(CONFIG_SND_INTEL_SST) += sst/
+
+# Audio Comms
+snd-soc-comms-machine-objs := mfld_comms_machine.o
+snd-soc-ssp-objs := mfld_ssp.o
+obj-$(CONFIG_SND_MFLD_COMMS_MACHINE) += mfld_comms_machine.o
+obj-$(CONFIG_SND_SOC_SSP) += mid_ssp.o
diff --git a/sound/soc/mid-x86/mfld_comms_machine.c b/sound/soc/mid-x86/mfld_comms_machine.c
new file mode 100644 (file)
index 0000000..d270443
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ *  mfld_ssp_wl1273_machine.c - ASoc Machine driver for
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Author: Selma Bensaid <selma.bensaidl@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define FORMAT(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include "mfld_comms_machine.h"
+
+/*****************************************/
+/* Global Variables                      */
+/*****************************************/
+
+static struct snd_soc_ops mfld_comms_dai_link_ops = {
+               .startup = mfld_comms_dai_link_startup,
+               .hw_params = mfld_comms_dai_link_hw_params,
+};
+
+/*
+ * MIXER CONTROLS for BT SCO stream
+ */
+static const char * const ssp_master_mode_text[] = {"disabled", "enabled"};
+static const struct soc_enum ssp_master_mode_enum =
+       SOC_ENUM_SINGLE_EXT(2, ssp_master_mode_text);
+
+
+static int get_ssp_master_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct comms_mc_private *comms_ctx =
+                               snd_soc_card_get_drvdata(codec->card);
+       ucontrol->value.integer.value[0] = comms_ctx->ssp_master_mode;
+       return 0;
+}
+
+static int set_ssp_master_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct comms_mc_private *comms_ctx =
+                               snd_soc_card_get_drvdata(codec->card);
+
+       if (ucontrol->value.integer.value[0] == comms_ctx->ssp_master_mode)
+               return 0;
+
+       comms_ctx->ssp_master_mode = ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+
+static const struct snd_kcontrol_new ssp_snd_controls[] = {
+       SOC_ENUM_EXT("SSP Master Mode", ssp_master_mode_enum,
+                       get_ssp_master_mode, set_ssp_master_mode),
+};
+
+
+
+static int mfld_comms_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_codec *codec = runtime->codec;
+       struct comms_mc_private *comms_ctx =
+                                       snd_soc_card_get_drvdata(codec->card);
+       int ret_val;
+
+       comms_ctx->ssp_master_mode = false;
+
+       ret_val = snd_soc_add_controls(codec, ssp_snd_controls,
+                               ARRAY_SIZE(ssp_snd_controls));
+       if (ret_val)
+               pr_err("MFLD Comms Machine: Init failed %d",
+                               ret_val);
+
+
+       return ret_val;
+}
+
+/*
+ * DAI LINK DEFINITIONS
+ */
+
+
+struct snd_soc_dai_link mfld_comms_dailink[] = {
+       [BT_SCO_DEV] = {
+               .name = "BT SCO",
+               .stream_name = "BTSCO",
+               .cpu_dai_name = SSP_BT_DAI_NAME,
+               .codec_dai_name = "wl1273_BT",
+               .codec_name = "wl1273_uart",
+               .platform_name = "mid-ssp-dai",
+               .init = mfld_comms_init,
+               .ops = &mfld_comms_dai_link_ops,
+       },
+       [FM_DEV] = {
+               .name = "FM",
+               .stream_name = "FM",
+               .cpu_dai_name = SSP_BT_DAI_NAME,
+               .codec_dai_name = "wl1273_FM",
+               .codec_name = "wl1273_uart",
+               .platform_name = "mid-ssp-dai",
+               .init = mfld_comms_init,
+               .ops = &mfld_comms_dai_link_ops,
+       },
+       [MSIC_VOIP_DEV] = {
+               .name = "MSIC VOIP",
+               .stream_name = "VOIP",
+               .cpu_dai_name = SSP_BT_DAI_NAME,
+               .codec_dai_name = "es305 Voice",
+               .codec_name = "es305_codec",
+               .platform_name = "mid-ssp-dai",
+               .init = mfld_comms_init,
+               .ops = &mfld_comms_dai_link_ops,
+       },
+       [IFX_MODEM_DEV] = {
+               .name = "IFX MODEM",
+               .stream_name = "IFX_MODEM_MIXING",
+               .cpu_dai_name = SSP_MODEM_DAI_NAME,
+               .codec_dai_name = "IFX_Modem_Mixing",
+               .codec_name = "ifx_modem",
+               .platform_name = "mid-ssp-dai",
+               .init = mfld_comms_init,
+               .ops = &mfld_comms_dai_link_ops,
+       },
+};
+
+/*
+ * DAI LINK OPS
+ */
+
+static int mfld_comms_dai_link_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *str_runtime;
+
+       str_runtime = substream->runtime;
+
+       WARN(!substream->pcm, "MFLD Comms Machine: ERROR "
+                       "NULL substream->pcm\n");
+
+       if (!substream->pcm)
+               return -EINVAL;
+
+       /* set the runtime hw parameter with local snd_pcm_hardware struct */
+       switch (substream->pcm->device) {
+       case BT_SCO_DEV:
+               str_runtime->hw = BT_soc_hw_param;
+               break;
+       case FM_DEV:
+               str_runtime->hw = FM_soc_hw_param;
+               break;
+       case MSIC_VOIP_DEV:
+               str_runtime->hw = VOIP_alsa_hw_param;
+               break;
+       case IFX_MODEM_DEV:
+               str_runtime->hw = IFX_modem_alsa_hw_param;
+               break;
+       default:
+               pr_err("MFLD Comms Machine: bad PCM Device = %d\n",
+                                               substream->pcm->device);
+       }
+       return snd_pcm_hw_constraint_integer(str_runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+
+static int mfld_comms_dai_link_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 *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_card *soc_card = rtd->card;
+       struct comms_mc_private *comms_ctx =
+                                       snd_soc_card_get_drvdata(soc_card);
+
+       int ret = 0;
+       unsigned int tx_mask, rx_mask;
+       unsigned int nb_slot = 0;
+       unsigned int slot_width = 0;
+       unsigned int tristate_offset = 0;
+       unsigned int device = substream->pcm->device;
+
+
+       switch (device) {
+       case BT_SCO_DEV:
+               /*
+                * set cpu DAI configuration
+                * frame_format = PSP_FORMAT
+                * ssp_serial_clk_mode = SSP_CLK_MODE_1
+                * sspslclk_direction = SSPSCLK_MASTER_MODE
+                * sspsfrm_direction = SSPSFRM_MASTER_MODE
+                */
+
+               ret = snd_soc_dai_set_fmt(cpu_dai,
+                                       SND_SOC_DAIFMT_I2S |
+                                       SND_SOC_DAIFMT_NB_IF |
+                                       (comms_ctx->ssp_master_mode ?
+                                       SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBS_CFS));
+
+               if (ret < 0) {
+                       pr_err("MFLD Comms Machine: Set FMT Fails %d\n", ret);
+                       return -EINVAL;
+               }
+
+               /*
+                * BT SCO SSP Config
+                * ssp_active_tx_slots_map = 0x01
+                * ssp_active_rx_slots_map = 0x01
+                * frame_rate_divider_control = 1
+                * data_size = 16
+                * tristate = 1
+                * ssp_frmsync_timing_bit = 0
+                * (NEXT_FRMS_ASS_AFTER_END_OF_T4)
+                * ssp_frmsync_timing_bit = 1
+                * (NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM)
+                * ssp_psp_T2 = 1
+                * (Dummy start offset = 1 bit clock period)
+                */
+               nb_slot = SSP_BT_SLOT_NB_SLOT;
+               slot_width = SSP_BT_SLOT_WIDTH;
+               tx_mask = SSP_BT_SLOT_TX_MASK;
+               rx_mask = SSP_BT_SLOT_RX_MASK;
+
+               if (comms_ctx->ssp_master_mode)
+                       tristate_offset = BIT(TRISTATE_BIT) |
+                       BIT(DUMMY_START_ONE_PERIOD_OFFSET);
+               else
+                       tristate_offset = BIT(FRAME_SYNC_RELATIVE_TIMING_BIT);
+               break;
+       case FM_DEV:
+               /*
+                * set cpu DAI configuration
+                * frame_format = PSP_FORMAT
+                * ssp_serial_clk_mode = SSP_CLK_MODE_1
+                * sspslclk_direction = SSPSCLK_MASTER_MODE
+                * sspsfrm_direction = SSPSFRM_MASTER_MODE
+                */
+
+               ret = snd_soc_dai_set_fmt(cpu_dai,
+                               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+                               (comms_ctx->ssp_master_mode ?
+                               SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBS_CFS));
+
+               if (ret < 0) {
+                       pr_err("MFLD Comms Machine: Set FMT Fails %d\n", ret);
+                       return -EINVAL;
+               }
+
+               /*
+                * FM SSP Config
+                * ssp_active_tx_slots_map = 0x00
+                * ssp_active_rx_slots_map = 0x01
+                * frame_rate_divider_control = 1
+                * data_size = 32
+                * tristate = 1
+                * ssp_frmsync_timing_bit = 1
+                * (NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM)
+                *
+                */
+               nb_slot = SSP_FM_SLOT_NB_SLOT;
+               slot_width = SSP_FM_SLOT_WIDTH;
+               tx_mask = SSP_FM_SLOT_TX_MASK;
+               rx_mask = SSP_FM_SLOT_RX_MASK;
+               tristate_offset = BIT(TRISTATE_BIT) |
+                                       BIT(DUMMY_START_ONE_PERIOD_OFFSET);
+               break;
+       case MSIC_VOIP_DEV:
+               /*
+                * set cpu DAI configuration
+                * frame_format = PSP_FORMAT
+                * ssp_serial_clk_mode = SSP_CLK_MODE_1
+                * sspslclk_direction = SSPSCLK_SLAVE_MODE
+                * sspsfrm_direction = SSPSFRM_SLAVE_MODE
+                */
+               ret = snd_soc_dai_set_fmt(cpu_dai,
+                               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+                               (comms_ctx->ssp_master_mode ?
+                               SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBS_CFS));
+
+               if (ret < 0) {
+                       pr_err("MFLD Comms Machine: Set FMT Fails %d\n",
+                                                       ret);
+                       return -EINVAL;
+               }
+
+               /*
+                * MSIC VOIP SSP Config
+                * ssp_active_tx_slots_map = 0x01
+                * ssp_active_rx_slots_map = 0x01
+                * frame_rate_divider_control = 1
+                * data_size = 32
+                * tristate = 1
+                * ssp_frmsync_timing_bit = 0, for SLAVE
+                * (NEXT_FRMS_ASS_AFTER_END_OF_T4)
+                * ssp_frmsync_timing_bit = 1, for MASTER
+                * (NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM)
+                *
+                *
+                */
+               nb_slot = SSP_VOIP_SLOT_NB_SLOT;
+               slot_width = SSP_VOIP_SLOT_WIDTH;
+               tx_mask = SSP_VOIP_SLOT_TX_MASK;
+               rx_mask = SSP_VOIP_SLOT_RX_MASK;
+
+               if (comms_ctx->ssp_master_mode)
+                       tristate_offset = BIT(TRISTATE_BIT) |
+                                       BIT(FRAME_SYNC_RELATIVE_TIMING_BIT);
+               else
+                       tristate_offset = BIT(FRAME_SYNC_RELATIVE_TIMING_BIT);
+               break;
+       case IFX_MODEM_DEV:
+               /*
+                * set cpu DAI configuration
+                * frame_format = PSP_FORMAT
+                * ssp_serial_clk_mode = SSP_CLK_MODE_1
+                * Master:
+                *      sspslclk_direction = SSPSCLK_MASTER_MODE
+                *      sspsfrm_direction = SSPSFRM_MASTER_MODE
+                * Slave:
+                *      sspslclk_direction = SSPSCLK_SLAVE_MODE
+                *      sspsfrm_direction = SSPSFRM_SLAVE_MODE
+                */
+               ret = snd_soc_dai_set_fmt(cpu_dai,
+                               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+                               (comms_ctx->ssp_master_mode ?
+                               SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBS_CFS));
+               if (ret < 0) {
+                       pr_err("MFLD Comms Machine:  Set FMT Fails %d\n", ret);
+                       return -EINVAL;
+               }
+
+               /*
+                * IFX Modem Mixing SSP Config
+                * ssp_active_tx_slots_map = 0x01
+                * ssp_active_rx_slots_map = 0x01
+                * frame_rate_divider_control = 1
+                * data_size = 32
+                * Master:
+                *      tristate = 3
+                *      ssp_frmsync_timing_bit = 1, for MASTER
+                *      (NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM)
+                * Slave:
+                *      tristate = 1
+                *      ssp_frmsync_timing_bit = 0, for SLAVE
+                *      (NEXT_FRMS_ASS_AFTER_END_OF_T4)
+                *
+                */
+               nb_slot = SSP_IFX_SLOT_NB_SLOT;
+               slot_width = SSP_IFX_SLOT_WIDTH;
+               tx_mask = SSP_IFX_SLOT_TX_MASK;
+               rx_mask = SSP_IFX_SLOT_RX_MASK;
+
+               if (comms_ctx->ssp_master_mode)
+                       tristate_offset = BIT(TRISTATE_BIT) |
+                                       BIT(FRAME_SYNC_RELATIVE_TIMING_BIT);
+               else
+                       tristate_offset = BIT(TRISTATE_BIT);
+               break;
+       default:
+               pr_err("MFLD Comms Machine: bad PCM Device ID = %d\n", device);
+               return -EINVAL;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask,
+                       rx_mask, nb_slot, slot_width);
+
+       if (ret < 0) {
+               pr_err("MFLD Comms Machine:  Set TDM Slot Fails %d\n", ret);
+               return -EINVAL;
+       }
+
+       /* select clock source (if master) */
+       /* BT SCO: CPU DAI is master */
+       /* FM: CPU DAI is master */
+       /* BT_VOIP: CPU DAI is master */
+       if ((device == BT_SCO_DEV && comms_ctx->ssp_master_mode) ||
+               (device == FM_DEV) ||
+               ((device == MSIC_VOIP_DEV) && comms_ctx->ssp_master_mode) ||
+               ((device == IFX_MODEM_DEV) && comms_ctx->ssp_master_mode))  {
+
+               snd_soc_dai_set_sysclk(cpu_dai, SSP_CLK_ONCHIP,
+                               substream->runtime->hw.rates, 0);
+       }
+
+
+       pr_info("MFLD Comms Machine: slot_width = %d\n",
+                       slot_width);
+       pr_info("MFLD Comms Machine: tx_mask = %d\n",
+                       tx_mask);
+       pr_info("MFLD Comms Machine: rx_mask = %d\n",
+                       rx_mask);
+       pr_info("MFLD Comms Machine: tristate_offset = %d\n",
+                       tristate_offset);
+
+       ret = snd_soc_dai_set_tristate(cpu_dai, tristate_offset);
+       if (ret < 0) {
+               pr_err("MFLD Comms Machine: Set Tristate Fails %d\n",
+                                               ret);
+               return -EINVAL;
+       }
+
+
+       return 0;
+} /* mfld_comms_dai_link_hw_params*/
+
+/* SoC card */
+static struct snd_soc_card snd_comms_card_mfld = {
+       .name = "SspCommsAudio",
+       .dai_link = mfld_comms_dailink,
+       .num_links = ARRAY_SIZE(mfld_comms_dailink),
+};
+
+static int __devinit snd_mfld_comms_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+       struct comms_mc_private *comms_ctx;
+
+       pr_info("MFLD Comms Machine: FCT %s enters\n",
+                       __func__);
+
+       /* register the soc card */
+       snd_comms_card_mfld.dev = &pdev->dev;
+
+       snd_soc_initialize_card_lists(&snd_comms_card_mfld);
+
+       ret_val = snd_soc_register_card(&snd_comms_card_mfld);
+       if (ret_val) {
+               pr_err("MFLD Comms Machine: card "
+                               "registeration failed %d\n",
+                               ret_val);
+               return -EBUSY;
+       }
+
+       comms_ctx = kzalloc(sizeof(struct comms_mc_private), GFP_KERNEL);
+       if (comms_ctx == NULL) {
+               pr_err("Unable to allocate comms_ctx\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, &snd_comms_card_mfld);
+       snd_soc_card_set_drvdata(&snd_comms_card_mfld, comms_ctx);
+
+       return 0;
+} /* snd_mfld_comms_probe */
+
+static int __devexit snd_mfld_comms_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *soc_card = platform_get_drvdata(pdev);
+       struct comms_mc_private *comms_ctx = snd_soc_card_get_drvdata(soc_card);
+
+       pr_info("MFLD Comms Machine: FCT %s enters\n",
+                       __func__);
+       kfree(comms_ctx);
+       snd_soc_card_set_drvdata(soc_card, NULL);
+       snd_soc_unregister_card(&snd_comms_card_mfld);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+} /* snd_mfld_comms_remove */
+
+
+static struct platform_driver snd_mfld_comms_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "mfld-comms-audio",
+       },
+       .probe = snd_mfld_comms_probe,
+       .remove = __devexit_p(snd_mfld_comms_remove),
+};
+
+static int __init snd_mfld_comms_init(void)
+{
+       pr_info("MFLD Comms Machine: FCT %s enters\n",
+                       __func__);
+       return platform_driver_register(&snd_mfld_comms_driver);
+}
+module_init(snd_mfld_comms_init);
+
+static void __exit snd_mfld_comms_exit(void)
+{
+       pr_info("MFLD Comms Machine: FCT %s enters\n",
+                       __func__);
+       platform_driver_unregister(&snd_mfld_comms_driver);
+}
+module_exit(snd_mfld_comms_exit);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
+MODULE_AUTHOR("Selma Bensaid");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ssp-bt-fm-audio");
diff --git a/sound/soc/mid-x86/mfld_comms_machine.h b/sound/soc/mid-x86/mfld_comms_machine.h
new file mode 100644 (file)
index 0000000..d00696b
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ *  mfld_ssp_wl1273_machine.c - ASoC Machine driver for
+ *  Intel Medfield MID platform
+ *
+ *  Copyright (C) 2011 Intel Corp
+ *  Author: Selma Bensaid <selma.bensaidl@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef MFLD_SSP_WL1273_MACHINE_H_
+#define MFLD_SSP_WL1273_MACHINE_H_
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "mid_ssp.h"
+
+/*
+ * Structures Definition
+ */
+
+struct comms_mc_private {
+       bool ssp_master_mode;
+};
+
+static int mfld_comms_dai_link_startup(struct snd_pcm_substream *substream);
+static int mfld_comms_dai_link_hw_params(struct snd_pcm_substream *substream,
+                                     struct snd_pcm_hw_params *params);
+
+/* Data path functionalities */
+struct snd_pcm_hardware BT_soc_hw_param = {
+               .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_DOUBLE |
+                               SNDRV_PCM_INFO_PAUSE |
+                               SNDRV_PCM_INFO_RESUME |
+                               SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_BATCH |
+                               SNDRV_PCM_INFO_SYNC_START),
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
+               .rates = (SNDRV_PCM_RATE_8000),
+               .rate_min = 8000,
+               .rate_max = 8000,
+               .channels_min = 1,
+               .channels_max = 1,
+               .buffer_bytes_max = (320*1024),
+               .period_bytes_min = 32,
+               .period_bytes_max = (320*1024),
+               .periods_min = 2,
+               .periods_max = (1024*2),
+               .fifo_size = 0,
+};
+
+struct snd_pcm_hardware FM_soc_hw_param = {
+               .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_DOUBLE |
+                               SNDRV_PCM_INFO_PAUSE |
+                               SNDRV_PCM_INFO_RESUME |
+                               SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_BATCH |
+                               SNDRV_PCM_INFO_SYNC_START),
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
+               .rates = (SNDRV_PCM_RATE_48000),
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 1,
+               .channels_max = 2,
+               .buffer_bytes_max = (640*1024),
+               .period_bytes_min = 64,
+               .period_bytes_max = (640*1024),
+               .periods_min = 2,
+               .periods_max = (1024*2),
+               .fifo_size = 0,
+};
+
+/* Data path functionalities */
+struct snd_pcm_hardware IFX_modem_alsa_hw_param = {
+               .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_DOUBLE |
+                               SNDRV_PCM_INFO_PAUSE |
+                               SNDRV_PCM_INFO_RESUME |
+                               SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_BATCH |
+                               SNDRV_PCM_INFO_SYNC_START),
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
+               .rates = (SNDRV_PCM_RATE_48000),
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 1,
+               .channels_max = 2,
+               .buffer_bytes_max = (640*1024),
+               .period_bytes_min = 64,
+               .period_bytes_max = (640*1024),
+               .periods_min = 2,
+               .periods_max = (1024*2),
+               .fifo_size = 0,
+};
+
+/* Data path functionalities */
+struct snd_pcm_hardware VOIP_alsa_hw_param = {
+               .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_DOUBLE |
+                               SNDRV_PCM_INFO_PAUSE |
+                               SNDRV_PCM_INFO_RESUME |
+                               SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_BATCH |
+                               SNDRV_PCM_INFO_SYNC_START),
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
+               .rates = (SNDRV_PCM_RATE_48000),
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 1,
+               .channels_max = 2,
+               .buffer_bytes_max = (640*1024),
+               .period_bytes_min = 64,
+               .period_bytes_max = (640*1024),
+               .periods_min = 2,
+               .periods_max = (1024*2),
+               .fifo_size = 0,
+};
+
+
+enum {
+       BT_SCO_DEV = 0,
+       FM_DEV,
+       MSIC_VOIP_DEV,
+       IFX_MODEM_DEV,
+};
+
+/*
+ * For FM 1 slot of 32 bits is used
+ * to transfer stereo 16 bits PCM samples
+ */
+#define SSP_FM_SLOT_NB_SLOT            1
+#define SSP_FM_SLOT_WIDTH              32
+#define SSP_FM_SLOT_RX_MASK            0x1
+#define SSP_FM_SLOT_TX_MASK            0x0
+/*
+ * For BT SCO 1 slot of 16 bits is used
+ * to transfer mono 16 bits PCM samples
+ */
+#define SSP_BT_SLOT_NB_SLOT            1
+#define SSP_BT_SLOT_WIDTH              16
+#define SSP_BT_SLOT_RX_MASK            0x1
+#define SSP_BT_SLOT_TX_MASK            0x1
+
+/*
+ * For VoIP 1 slot of 32 bits is used
+ * to transfer stereo 16 bits PCM samples
+ */
+#define SSP_VOIP_SLOT_NB_SLOT  1
+#define SSP_VOIP_SLOT_WIDTH            16
+#define SSP_VOIP_SLOT_RX_MASK  0x1
+#define SSP_VOIP_SLOT_TX_MASK  0x1
+
+/*
+ * For Modem IFX 1 slot of 32 bits is used
+ * to transfer stereo 16 bits PCM samples
+ */
+#define SSP_IFX_SLOT_NB_SLOT   1
+#define SSP_IFX_SLOT_WIDTH             32
+#define SSP_IFX_SLOT_RX_MASK   0x1
+#define SSP_IFX_SLOT_TX_MASK   0x1
+
+
+#endif /* MFLD_SSP_WL1273_MACHINE_H_ */
diff --git a/sound/soc/mid-x86/mid_ssp.c b/sound/soc/mid-x86/mid_ssp.c
new file mode 100644 (file)
index 0000000..46781b1
--- /dev/null
@@ -0,0 +1,1208 @@
+/*
+ *     mid_ssp.c - ASoC CPU DAI driver for
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Author:
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#define FORMAT(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include "mid_ssp.h"
+
+/*
+ * Default I2S configuration
+ */
+/*
+ * TO BE DONE: use mixer to make it more flexible
+ */
+const struct intel_mid_i2s_settings ssp_platform_i2s_config = {
+       .master_mode_clk_selection = SSP_MASTER_CLOCK_UNDEFINED,
+       .master_mode_standard_freq = 0xFFFF,
+       .tx_tristate_phase = TXD_TRISTATE_LAST_PHASE_OFF,
+       .slave_clk_free_running_status =
+                       SLAVE_SSPCLK_ON_DURING_TRANSFER_ONLY,
+       .ssp_duplex_mode = RX_AND_TX_MODE,
+       .ssp_trailing_byte_mode = SSP_TRAILING_BYTE_HDL_BY_IA,
+       .ssp_tx_dma = SSP_TX_DMA_ENABLE,
+       .ssp_rx_dma = SSP_RX_DMA_ENABLE,
+       .rx_fifo_interrupt = SSP_RX_FIFO_OVER_INT_ENABLE,
+       .tx_fifo_interrupt = SSP_TX_FIFO_UNDER_INT_ENABLE,
+       .ssp_rx_timeout_interrupt_status = SSP_RX_TIMEOUT_INT_DISABLE,
+       .ssp_trailing_byte_interrupt_status =
+                       SSP_TRAILING_BYTE_INT_ENABLE,
+       .ssp_loopback_mode_status = SSP_LOOPBACK_OFF,
+       .ssp_rx_fifo_threshold = MID_SSP_RX_FIFO_THRESHOLD,
+       .ssp_tx_fifo_threshold = MID_SSP_TX_FIFO_THRESHOLD,
+       .ssp_frmsync_pol_bit = SSP_FRMS_ACTIVE_HIGH,
+       .ssp_end_transfer_state =
+                       SSP_END_DATA_TRANSFER_STATE_LOW,
+       .ssp_psp_T1 = 0,
+       .ssp_psp_T2 = 0,
+       .ssp_psp_T4 = 0,
+       .ssp_psp_T5 = 0,
+       .ssp_psp_T6 = 1,
+};
+
+/*
+ * SSP DAI Internal functions
+ */
+
+/**
+ * ssp_dma_req - This function programs a write or read request
+ * to the Intel I2S driver
+ *
+ * @param substream Pointer to stream structure
+ * return ret_val Status
+ */
+static int ssp_dma_req(struct snd_pcm_substream *substream)
+{
+
+       struct intel_alsa_ssp_stream_info *str_info;
+       struct intel_ssp_config *ssp_config;
+       struct snd_pcm_runtime *pl_runtime;
+       u32 *dma_addr;
+       int ret;
+       WARN(!substream, "SSP DAI: "
+                       "ERROR NULL substream\n");
+       if (!substream)
+               return -EINVAL;
+
+
+       pl_runtime = substream->runtime;
+
+       str_info = pl_runtime->private_data;
+
+       WARN(!str_info, "SSP DAI: "
+                       "ERROR NULL str_info\n");
+       if (!str_info)
+               return -EINVAL;
+
+       ssp_config = str_info->ssp_config;
+
+       WARN(!ssp_config, "SSP DAI: "
+                       "ERROR NULL ssp_config\n");
+       if (!ssp_config)
+               return -EINVAL;
+
+
+       WARN(!ssp_config->i2s_handle, "SSP DAI: "
+                       "ERROR, trying to play a stream however "
+                       "ssp_config->i2s_handle is NULL\n");
+
+       if (!ssp_config->i2s_handle)
+               return -EINVAL;
+
+       str_info->length = frames_to_bytes(pl_runtime, pl_runtime->period_size);
+
+       str_info->addr = substream->runtime->dma_area;
+       pr_debug("SSP DAI: FCT %s substream->runtime->dma_area = %p",
+                               __func__, substream->runtime->dma_area);
+
+       dma_addr = (u32 *)(str_info->addr +
+                               str_info->length * str_info->period_req_index);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ret = intel_mid_i2s_wr_req(ssp_config->i2s_handle, dma_addr,
+                       str_info->length, substream);
+       else
+               ret = intel_mid_i2s_rd_req(ssp_config->i2s_handle, dma_addr,
+                       str_info->length, substream);
+
+       if (ret == 0) {
+
+               intel_mid_i2s_command(ssp_config->i2s_handle,
+                               SSP_CMD_ENABLE_SSP, NULL);
+
+               if (test_and_set_bit(INTEL_ALSA_SSP_STREAM_RUNNING,
+                               &str_info->stream_status)) {
+
+                       pr_err("SSP DAI: "
+                               "ERROR previous requested not handled\n");
+                       return -EBUSY;
+               }
+
+               if (++(str_info->period_req_index) >= pl_runtime->periods)
+                       str_info->period_req_index = 0;
+               return 0;
+       } else {
+               pr_err("SSP DAI: FCT %s read/write req ERROR\n",
+                               __func__);
+               return -EINVAL;
+       }
+} /* ssp_dma_req */
+
+/**
+ * ssp_dma_complete - End of capture or playback callback
+ * called in DMA Complete Tasklet context
+ * This Callback has in charge of re-programming a new read or write
+ * request to Intel MID I2S Driver if the stream has not been Closed.
+ * It calls also the snd_pcm_period_elapsed if the stream is not
+ * PAUSED or SUSPENDED to inform ALSA Kernel that the Ring Buffer
+ * period has been sent or received properly
+ *
+ * @param param Pointer to a structure
+ * return status
+ */
+static int ssp_dma_complete(void *param)
+{
+       struct snd_pcm_substream *substream;
+       struct intel_alsa_ssp_stream_info *str_info;
+       struct snd_pcm_runtime *pl_runtime;
+       bool call_back = false;
+       bool reset_index = false;
+
+       substream = (struct snd_pcm_substream *)param;
+       pl_runtime = substream->runtime;
+       str_info = substream->runtime->private_data;
+
+       WARN(!str_info, "SSP DAI: ERROR NULL str_info\n");
+       if (!str_info)
+               return -EINVAL;
+
+       if (test_and_clear_bit(INTEL_ALSA_SSP_STREAM_RUNNING,
+                                       &str_info->stream_status)) {
+               bool dropped = test_and_clear_bit(INTEL_ALSA_SSP_STREAM_DROPPED,
+                                       &str_info->stream_status);
+               bool started = test_bit(INTEL_ALSA_SSP_STREAM_STARTED,
+                                       &str_info->stream_status);
+
+               if (started) {
+                       /*
+                        * Whatever dropped or not,
+                        * the stream is on going
+                        */
+                       call_back = true;
+               }
+               if (started && dropped) {
+                       /*
+                        * the stream has been dropped and restarted
+                        * before the callback occurs
+                        * in this case the we have to reprogram the
+                        * requests to SSP driver
+                        * and reset the stream's indexes
+                        */
+                       reset_index = true;
+               }
+
+               if (!started && !dropped) {
+                       pr_err("SSP DAI: FCT %s neither started nor dropped",
+                                               __func__);
+                       return -EBUSY;
+               }
+
+       } else {
+               pr_err("SSP DAI: FCT %s called while not running ",
+                                               __func__);
+               return -EBUSY;
+       }
+
+       if (call_back == true) {
+               pr_debug("SSP DAI: playback/capture (REQ=%d,CB=%d): "
+                               "DMA_REQ_COMPLETE\n",
+                               str_info->period_req_index,
+                               str_info->period_cb_index);
+
+               if (reset_index) {
+
+                       str_info->period_cb_index = 0;
+                       str_info->period_req_index = 0;
+
+               } else if (++(str_info->period_cb_index) >= pl_runtime->periods)
+                       str_info->period_cb_index = 0;
+
+               /*
+                * Launch the next Capture/Playback request if
+                * no CLOSE has been requested
+                */
+               ssp_dma_req(substream);
+
+               /*
+               * Call the snd_pcm_period_elapsed to inform ALSA kernel
+               * that a ringbuffer period has been played
+               */
+               snd_pcm_period_elapsed(substream);
+
+       }
+       return 0;
+} /* ssp_dma_complete */
+
+/**
+ * intel_mid_ssp_transfer_data - send data buffers
+ *
+ * @param work Pointer to stream structure
+ * return void
+ */
+void intel_mid_ssp_transfer_data(struct work_struct *work)
+{
+       struct intel_alsa_ssp_stream_info *str_info;
+       struct snd_pcm_substream *substream;
+
+       BUG_ON(!work);
+
+       str_info = container_of(work, struct intel_alsa_ssp_stream_info,
+                       ssp_ws);
+
+       BUG_ON(!str_info);
+
+       substream = str_info->substream;
+
+       BUG_ON(!substream);
+
+       ssp_dma_req(substream);
+
+} /* intel_mid_ssp_transfer_data */
+
+/*
+ * SSP PLATFORM
+ */
+
+/*
+ * SSP Platform functions
+ */
+static int ssp_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
+{
+       int retval = 0;
+       struct snd_soc_dai *dai;
+       struct snd_pcm *pcm;
+
+       pr_debug("SSP DAI: FCT %s enters\n",
+                       __func__);
+       /*
+        * Do pre-allocation to all substreams of the given pcm for the
+        * specified DMA type.
+        *
+        */
+       dai = soc_runtime->cpu_dai;
+       pcm = soc_runtime->pcm;
+
+       if (dai->driver->playback.channels_min ||
+                       dai->driver->capture.channels_min) {
+               retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
+                       SNDRV_DMA_TYPE_CONTINUOUS,
+                       snd_dma_continuous_data(GFP_KERNEL),
+                       SSP_MIN_BUFFER, SSP_MAX_BUFFER);
+
+               if (retval) {
+                       pr_err("DMA buffer allocation fail\n");
+                       return retval;
+               }
+       }
+       return retval;
+} /* ssp_platform_pcm_new */
+
+static void ssp_platform_pcm_free(struct snd_pcm *pcm)
+{
+       pr_debug("SSP DAI: FCT %s enter\n",
+                       __func__);
+       /*
+        * release all pre-allocated buffers on the pcm
+        *
+        */
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+
+} /* ssp_platform_pcm_free */
+
+/**
+ * ssp_platform_hw_params - Allocate memory for Ring Buffer according
+ * to hw_params.
+ * It's called in a non-atomic context
+ *
+ * @param substream Substream for which the stream function is called
+ * @param hw_params Stream command thats requested from upper layer
+ * return status 0 ==> OK
+ *
+ */
+static int ssp_platform_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params)
+{
+       int ret_val;
+
+       /*
+        * Allocates the DMA buffer for the substream
+        * This callback could be called several time
+        * snd_pcm_lib_malloc_pages allows to avoid memory leak
+        * as it release already allocated memory when already allocated
+        */
+       ret_val = snd_pcm_lib_malloc_pages(substream,
+                       params_buffer_bytes(hw_params));
+
+       if (ret_val < 0)
+               return ret_val;
+
+       memset(substream->runtime->dma_area, 0, params_buffer_bytes(hw_params));
+
+       return 0;
+} /* ssp_platform_hw_params */
+
+/*
+ * ssp_platform_pointer- to send the current buffer pointer
+ * processed by HW
+ * This function is called by ALSA framework to get the current HW buffer ptr
+ * to check the Ring Buffer Status
+ *
+ * @param substream Pointer to the substream for which the function
+ *             is called
+ *
+ * return pcm_pointer Indicates the number of samples played
+ *
+ */
+static
+snd_pcm_uframes_t ssp_platform_pointer(struct snd_pcm_substream *substream)
+{
+       struct intel_alsa_ssp_stream_info *str_info;
+       unsigned long pcm_pointer = 0;
+
+       str_info = substream->runtime->private_data;
+
+       WARN(!str_info, "SSP DAI: ERROR NULL str_info\n");
+       if (!str_info)
+               return -EINVAL;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               pcm_pointer = (unsigned long) (str_info->period_cb_index
+                               * substream->runtime->period_size);
+       else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               pcm_pointer = (unsigned long) (str_info->period_cb_index
+                               * substream->runtime->period_size);
+
+       pr_debug("SSP DAI: FCT %s Frame bits:: %d "
+                       "period_size :: %d periods :: %d\n",
+                       __func__,
+                       (int) substream->runtime->frame_bits,
+                       (int) substream->runtime->period_size,
+                       (int) substream->runtime->periods);
+
+       pr_debug("SSP DAI: FCT %s returns %ld\n",
+                       __func__, pcm_pointer);
+
+       return pcm_pointer;
+} /* ssp_platform_pointer */
+
+static struct snd_pcm_ops ssp_platform_ops = {
+       .open = NULL,
+       .close = NULL,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = ssp_platform_hw_params,
+       .hw_free = NULL,
+       .prepare = NULL,
+       .trigger = NULL,
+       .pointer = ssp_platform_pointer,
+};
+
+struct snd_soc_platform_driver soc_ssp_platform_drv = {
+       .ops            = &ssp_platform_ops,
+       .pcm_new        = ssp_platform_pcm_new,
+       .pcm_free       = ssp_platform_pcm_free,
+};
+
+/*
+ * SND SOC DAI OPs
+ */
+static int ssp_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct intel_ssp_config *ssp_config;
+
+       pr_info("SSP DAI: FCT %s enters for CPU_DAI %d\n",
+                       __func__, cpu_dai->id);
+
+       ssp_config = kzalloc(sizeof(struct intel_ssp_config), GFP_KERNEL);
+
+
+       if (ssp_config == NULL) {
+               pr_err("Unable to allocate ssp_config\n");
+               return -ENOMEM;
+       }
+
+       ssp_config->intel_mid_dma_alloc = false;
+
+       ssp_config->i2s_settings = ssp_platform_i2s_config;
+       pr_info("SSP DAI: FCT %s ssp_config %p\n",
+                               __func__, ssp_config);
+
+       cpu_dai->playback_dma_data = cpu_dai->capture_dma_data = ssp_config;
+
+       return 0;
+
+} /* ssp_probe */
+
+static int ssp_remove(struct snd_soc_dai *cpu_dai)
+{
+       struct intel_ssp_config *ssp_config;
+
+       WARN(!cpu_dai, "SSP DAI: "
+                       "ERROR NULL cpu_dai\n");
+       if (!cpu_dai)
+               return -EINVAL;
+
+       ssp_config = cpu_dai->playback_dma_data;
+
+       kfree(ssp_config);
+
+       return 0;
+} /* ssp_remove */
+
+static int ssp_dai_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *cpu_dai)
+{
+       struct intel_ssp_config *ssp_config;
+       struct snd_pcm_runtime *pl_runtime;
+       struct intel_alsa_ssp_stream_info *str_info;
+       struct snd_soc_dai_driver *cpudai_drv = cpu_dai->driver;
+       unsigned int device;
+       int ret = 0;
+       struct workqueue_struct *ssp_dai_wq;
+
+       pr_info("SSP DAI: FCT %s enters for DAI Id = %d\n",
+                       __func__, cpu_dai->driver->id);
+
+
+       pl_runtime = substream->runtime;
+
+       ssp_config = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+       WARN(!ssp_config, "SSP DAI: "
+                       "FCT %s ERROR NULL ssp_config\n",
+                       __func__);
+       if (!ssp_config)
+               return -EINVAL;
+
+       ssp_dai_wq = dev_get_drvdata(cpu_dai->dev);
+
+       WARN(!cpu_dai->driver, "SSP DAI: "
+                       "FCT %s ERROR NULL cpu_dai->driver\n",
+                       __func__);
+       if (!cpu_dai->driver)
+               return -EINVAL;
+
+       device = cpu_dai->driver->id;
+
+       /*
+        * setup the internal data structure stream pointers based on it being
+        * playback or capture stream
+        */
+       str_info = kzalloc(sizeof(*str_info), GFP_KERNEL);
+
+       if (!str_info) {
+               pr_err("SSP DAI: str_info alloc failure\n");
+               return -EINVAL;
+
+       }
+       str_info->substream = substream;
+       str_info->ssp_config = ssp_config;
+       str_info->stream_status = 0;
+
+       INIT_WORK(&str_info->ssp_ws, intel_mid_ssp_transfer_data);
+
+       /*
+        * Initialize SSPx [x=0,1] driver
+        * Store the Stream information
+        */
+       pl_runtime->private_data = str_info;
+
+       pr_debug("SSP DAI: FCT %s enters cpu_dai->card->name = %s\n",
+                       __func__, cpu_dai->card->name);
+
+       if (!cpu_dai->active) {
+               if (!strcmp(cpudai_drv->name, SSP_BT_DAI_NAME)) {
+                       ssp_config->i2s_handle =
+                               intel_mid_i2s_open(SSP_USAGE_BLUETOOTH_FM);
+                       pr_debug("opening the CPU_DAI for SSP_USAGE_BLUETOOTH_FM, i2s_handle = %p\n",
+                                                       ssp_config->i2s_handle);
+
+               } else if (!strcmp(cpudai_drv->name, SSP_MODEM_DAI_NAME)) {
+                       ssp_config->i2s_handle =
+                               intel_mid_i2s_open(SSP_USAGE_MODEM);
+                       pr_debug("opening the CPU_DAI for SSP_USAGE_MODEM, i2s_handle = %p\n",
+                                                       ssp_config->i2s_handle);
+
+               } else {
+                       pr_err("non Valid SOC CARD\n");
+                       return -EINVAL;
+               }
+
+               /* Set the Write Callback */
+               ret = intel_mid_i2s_set_wr_cb(ssp_config->i2s_handle,
+                               ssp_dma_complete);
+               if (ret)
+                       return ret;
+
+               /* Set the Default Read Callback */
+               ret = intel_mid_i2s_set_rd_cb(ssp_config->i2s_handle,
+                               ssp_dma_complete);
+               if (ret)
+                       return ret;
+
+       } else {
+               /*
+                * do nothing because already Open by sibling substream
+                */
+               pr_debug("SSP DAI: FCT %s Open DO NOTHING\n",
+                               __func__);
+       }
+       return 0;
+} /* ssp_dai_startup */
+
+static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *cpu_dai)
+{
+       struct intel_ssp_config *ssp_config;
+       struct intel_alsa_ssp_stream_info *str_info;
+       struct snd_pcm_runtime *runtime;
+
+       ssp_config = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+       BUG_ON(!ssp_config);
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               /*
+                * Only Free Tx channel if no playback streams are active
+                * Shutdown can be called right after a startup if something
+                * failed (as a concurrency issue
+                * so this case can happen
+                */
+               if ((!cpu_dai->playback_active) &&
+                       (ssp_config->i2s_settings.ssp_active_tx_slots_map)) {
+                       intel_mid_i2s_command(ssp_config->i2s_handle,
+                                       SSP_CMD_FREE_TX, NULL);
+                       pr_debug("SSP DAI: FCT %s TX DMA Channel released\n",
+                                       __func__);
+               }
+               break;
+
+       case SNDRV_PCM_STREAM_CAPTURE:
+               /*
+                * Only Free Rx channel if no capture streams are active
+                */
+               if ((!cpu_dai->capture_active) &&
+                       (ssp_config->i2s_settings.ssp_active_rx_slots_map)) {
+                       intel_mid_i2s_command(ssp_config->i2s_handle,
+                                       SSP_CMD_FREE_RX, NULL);
+                       pr_debug("SSP DAI: FCT %s RX DMA Channel released\n",
+                                       __func__);
+               }
+               break;
+
+       default:
+               pr_err("SSP DAI: FCT %s Bad stream_dir: %d\n",
+                               __func__, substream->stream);
+               break;
+       }
+
+       runtime = substream->runtime;
+       str_info = runtime->private_data;
+
+       /* Cancel pending work */
+       cancel_work_sync(&str_info->ssp_ws);
+
+       kfree(str_info);
+
+       if (!cpu_dai->active) {
+               pr_info("SSP DAI: FCT %s closing I2S\n",
+                               __func__);
+               /*
+                * Close the Intel MID I2S connection
+                */
+               intel_mid_i2s_close(ssp_config->i2s_handle);
+
+               ssp_config->i2s_handle = NULL;
+               ssp_config->intel_mid_dma_alloc = false;
+       }
+
+} /* ssp_dai_shutdown */
+
+static int ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+               unsigned int fmt)
+{
+       struct intel_ssp_config *ssp_config;
+       struct intel_mid_i2s_settings *i2s_config;
+
+       ssp_config = cpu_dai->playback_dma_data;
+
+       WARN(!ssp_config, "SSP DAI: FCT %s ssp_config=NULL\n",
+                       __func__);
+       if (!ssp_config)
+               return -EINVAL;
+
+       pr_debug("SSP DAI: FCT %s fmt = %d\n",
+                       __func__, fmt);
+
+       i2s_config = &(ssp_config->i2s_settings);
+
+       /*
+        * SSP CLK Direction
+        * SSP FRMSYNC Direction
+        */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               i2s_config->sspslclk_direction = SSPSCLK_MASTER_MODE;
+               i2s_config->sspsfrm_direction = SSPSCLK_MASTER_MODE;
+               /*
+                * Mandatory to be able to perform only RX without TX
+                * in SSP CLK Master Mode
+                *
+                */
+               i2s_config->ssp_duplex_mode = RX_WITHOUT_TX_MODE;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               i2s_config->sspslclk_direction = SSPSCLK_MASTER_MODE;
+               i2s_config->sspsfrm_direction = SSPSCLK_SLAVE_MODE;
+               /*
+                * Mandatory to be able to perform only RX without TX
+                * in SSP CLK Master Mode
+                *
+                */
+               i2s_config->ssp_duplex_mode = RX_WITHOUT_TX_MODE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               i2s_config->sspslclk_direction = SSPSCLK_SLAVE_MODE;
+               i2s_config->sspsfrm_direction = SSPSCLK_SLAVE_MODE;
+               i2s_config->ssp_duplex_mode = RX_AND_TX_MODE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               i2s_config->sspslclk_direction = SSPSCLK_SLAVE_MODE;
+               i2s_config->sspsfrm_direction = SSPSCLK_MASTER_MODE;
+               i2s_config->ssp_duplex_mode = RX_AND_TX_MODE;
+               break;
+       default:
+               pr_err("SSP DAI: %s Bad DAI CLK/FS Mode=%d\n",
+                                       __func__,
+                                       (fmt & SND_SOC_DAIFMT_MASTER_MASK));
+               return -EINVAL;
+       }
+       /*
+        * SSP Signal Inversion Mode
+        */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               i2s_config->ssp_serial_clk_mode = SSP_CLK_MODE_0;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               i2s_config->ssp_serial_clk_mode = SSP_CLK_MODE_1;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               i2s_config->ssp_serial_clk_mode = SSP_CLK_MODE_2;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               i2s_config->ssp_serial_clk_mode = SSP_CLK_MODE_3;
+               break;
+       default:
+               pr_err("SSP DAI: %s Bad DAI Signal Inversion Mode=%d\n",
+                               __func__,
+                               (fmt & SND_SOC_DAIFMT_INV_MASK));
+               return -EINVAL;
+       }
+
+       /*
+        * SSP Format Mode
+        */
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               i2s_config->frame_format = PSP_FORMAT;
+               break;
+
+       default:
+               pr_err("SSP DAI: %s Bad DAI format Mode=%d\n",
+                               __func__,
+                               (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
+               return -EINVAL;
+       }
+       return 0;
+} /* ssp_set_dai_fmt */
+
+static int ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
+       unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+       struct intel_ssp_config *ssp_config;
+       struct intel_mid_i2s_settings *i2s_config;
+
+       ssp_config = cpu_dai->playback_dma_data;
+
+       WARN(!ssp_config, "SSP DAI: FCT %s ssp_config=NULL\n",
+                       __func__);
+       if (!ssp_config)
+               return -EINVAL;
+
+
+       i2s_config = &(ssp_config->i2s_settings);
+
+       i2s_config->frame_rate_divider_control = slots;
+       i2s_config->data_size = slot_width;
+       i2s_config->mode = SSP_IN_NETWORK_MODE;
+       i2s_config->ssp_active_tx_slots_map = tx_mask;
+       i2s_config->ssp_active_rx_slots_map = rx_mask;
+
+       pr_debug("i2s_config->frame_rate_divider_control = %d\n",
+                       i2s_config->frame_rate_divider_control);
+       pr_debug("i2s_config->data_size = %d\n",
+                       i2s_config->data_size);
+       pr_debug("i2s_config->mode = %d\n",
+                       i2s_config->mode);
+       pr_debug("i2s_config->ssp_active_tx_slots_map = %d\n",
+                       i2s_config->ssp_active_tx_slots_map);
+       pr_debug("i2s_config->ssp_active_rx_slots_map = %d\n",
+                       i2s_config->ssp_active_rx_slots_map);
+
+       return 0;
+}
+
+static int ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+       int clk_id, unsigned int freq, int dir)
+{
+       struct intel_ssp_config *ssp_config;
+       struct intel_mid_i2s_settings *i2s_config;
+
+       ssp_config = cpu_dai->playback_dma_data;
+
+       BUG_ON(!ssp_config);
+
+       i2s_config = &(ssp_config->i2s_settings);
+
+       pr_debug("SSP DAI: FCT %s clk_id = %d\n",
+                       __func__, clk_id);
+
+       switch (clk_id) {
+       case SSP_CLK_ONCHIP:
+               i2s_config->master_mode_clk_selection = SSP_ONCHIP_CLOCK;
+               break;
+       case SSP_CLK_NET:
+               i2s_config->master_mode_clk_selection = SSP_NETWORK_CLOCK;
+               break;
+       case SSP_CLK_EXT:
+               i2s_config->master_mode_clk_selection = SSP_EXTERNAL_CLOCK;
+               break;
+       case SSP_CLK_AUDIO:
+               i2s_config->master_mode_clk_selection = SSP_ONCHIP_AUDIO_CLOCK;
+               break;
+       default:
+               i2s_config->master_mode_standard_freq =
+                                               SSP_MASTER_CLOCK_UNDEFINED;
+               pr_err("SSP DAI: %s Bad clk_id=%d\n",
+                               __func__,
+                               clk_id);
+               return -EINVAL;
+       }
+
+       pr_debug("SSP DAI:FCT %s freq = %d\n",
+                               __func__, freq);
+
+       switch (freq) {
+       case SNDRV_PCM_RATE_48000:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_48_000;
+               break;
+       case SNDRV_PCM_RATE_44100:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_44_100;
+               break;
+       case SNDRV_PCM_RATE_22050:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_22_050;
+               break;
+       case SNDRV_PCM_RATE_16000:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_16_000;
+               break;
+       case SNDRV_PCM_RATE_11025:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_11_025;
+               break;
+       case SNDRV_PCM_RATE_8000:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_8_000;
+               break;
+       default:
+               i2s_config->master_mode_standard_freq = SSP_FRM_FREQ_UNDEFINED;
+               pr_err("SSP DAI: %s Bad freq_out=%d\n",
+                               __func__,
+                               freq);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
+       int tristate)
+{
+       struct intel_ssp_config *ssp_config;
+       struct intel_mid_i2s_settings *i2s_config;
+
+       ssp_config = cpu_dai->playback_dma_data;
+
+       BUG_ON(!ssp_config);
+
+       i2s_config = &(ssp_config->i2s_settings);
+
+       if (IS_TRISTATE_ENABLED(tristate))
+               i2s_config->tx_tristate_enable = TXD_TRISTATE_ON;
+       else
+               i2s_config->tx_tristate_enable = TXD_TRISTATE_OFF;
+
+       if (IS_NEXT_FRMS_ASSERTED_WITH_LSB_PREVIOUS_FRM(tristate))
+               i2s_config->ssp_frmsync_timing_bit =
+                               NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM;
+       else
+               i2s_config->ssp_frmsync_timing_bit =
+                               NEXT_FRMS_ASS_AFTER_END_OF_T4;
+
+       i2s_config->ssp_psp_T2 = IS_DUMMY_START_ONE_PERIOD_OFFSET(tristate);
+       pr_debug("FCT %s tristate %x\n", __func__, tristate);
+
+       return 0;
+}
+
+/**
+ * ssp_dai_trigger- stream activities are handled here
+ * This function is called whenever a stream activity is invoked
+ * The Trigger function is called in an atomic context
+ *
+ * @param substream Substream for which the stream function is called
+ * @param cmd The stream command thats requested from upper layer
+ * return status 0 ==> OK
+ *
+ */
+static int ssp_dai_trigger(struct snd_pcm_substream *substream,
+               int cmd, struct snd_soc_dai *cpu_dai)
+{
+       int ret_val = 0;
+       struct intel_alsa_ssp_stream_info *str_info;
+       struct snd_pcm_runtime *pl_runtime;
+       struct workqueue_struct *ssp_dai_wq;
+       bool trigger_start = true;
+       int stream = 0;
+
+       pr_debug("SSP DAI: FCT %s enters\n",
+                       __func__);
+
+       stream = substream->stream;
+
+
+       pl_runtime = substream->runtime;
+
+       WARN(!pl_runtime->private_data, "SSP DAI: ERROR "
+                       "NULL pl_runtime->private_data\n");
+       if (!pl_runtime->private_data)
+               return -EINVAL;
+
+       WARN(!cpu_dai, "SSP DAI: ERROR NULL cpu_dai\n");
+       if (!cpu_dai)
+               return -EINVAL;
+
+       WARN(!cpu_dai->dev, "SSP DAI: ERROR NULL cpu_dai->dev\n");
+       if (!cpu_dai->dev)
+               return -EINVAL;
+
+       ssp_dai_wq = dev_get_drvdata(cpu_dai->dev);
+
+
+       WARN(!ssp_dai_wq, "SSP DAI: ERROR NULL ssp_dai_wq\n");
+       if (!ssp_dai_wq)
+               return -EINVAL;
+
+       str_info = pl_runtime->private_data;
+
+       pr_debug("SSP DAI: FCT %s CMD = 0x%04X\n",
+                       __func__, cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!test_and_set_bit(INTEL_ALSA_SSP_STREAM_STARTED,
+                               &str_info->stream_status)) {
+                       if (test_bit(INTEL_ALSA_SSP_STREAM_DROPPED,
+                                       &str_info->stream_status)) {
+                               pr_debug("SSP DAI: FCT %s do not restart "
+                                               "the trigger stream running "
+                                               "already\n", __func__);
+                               trigger_start = false;
+                       } else
+                               trigger_start = true;
+               } else {
+                       pr_err("SSP DAI: ERROR 2 consecutive TRIGGER_START\n");
+                       return -EBUSY;
+               }
+
+               /* Store the substream locally */
+               if (trigger_start) {
+                       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                               pr_debug("SSP DAI: queue Playback Work\n");
+                               queue_work(ssp_dai_wq, &str_info->ssp_ws);
+                       } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+                               pr_debug("SSP DAI: queue Capture Work\n");
+                               queue_work(ssp_dai_wq, &str_info->ssp_ws);
+                       } else {
+                               pr_err("SSP DAI: SNDRV_PCM_TRIGGER_START Bad Stream: %d\n",
+                                               substream->stream);
+                               return -EINVAL;
+                       }
+               }
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (test_and_clear_bit(INTEL_ALSA_SSP_STREAM_STARTED,
+                               &str_info->stream_status))
+
+                       set_bit(INTEL_ALSA_SSP_STREAM_DROPPED,
+                                       &str_info->stream_status);
+               else {
+                       pr_err("SSP DAI: trigger START/STOP mismatch\n");
+                       return -EBUSY;
+               }
+               break;
+
+       default:
+               pr_err("SSP DAI: snd_i2s_alsa_pcm_trigger Bad Command\n");
+               return -EINVAL;
+       }
+       return ret_val;
+} /* ssp_dai_trigger */
+
+/**
+ * ssp_dai_hw_params - Allocate memory for Ring Buffer according
+ * to hw_params.
+ * It's called in a non-atomic context
+ *
+ * @param substream Substream for which the stream function is called
+ * @param hw_params Stream command thats requested from upper layer
+ * @param cpu_dai Pointer to the CPU DAI that is used
+ * return status 0 ==> OK
+ *
+ */
+static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params,
+               struct snd_soc_dai *cpu_dai)
+{
+       struct intel_ssp_config *ssp_config;
+
+       pr_info("SSP DAI: FCT %s enters\n",
+                       __func__);
+
+       WARN(!cpu_dai, "SSP DAI: ERROR NULL cpu_dai\n");
+       if (!cpu_dai)
+               return -EINVAL;
+
+       ssp_config = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       pr_info("SSP DAI: FCT %s ssp_config %p\n",
+                               __func__,
+                               ssp_config);
+
+       /*
+        * The set HW Config is only once for a CPU DAI
+        */
+
+       if (cpu_dai->active == 1) {
+               intel_mid_i2s_command(ssp_config->i2s_handle,
+                                               SSP_CMD_SET_HW_CONFIG,
+                                               &(ssp_config->i2s_settings));
+
+       }
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               if (intel_mid_i2s_command(ssp_config->i2s_handle,
+                               SSP_CMD_ALLOC_TX, NULL)) {
+                       pr_err("can not alloc TX DMA Channel\n");
+                       return -EBUSY;
+               }
+               break;
+
+       case SNDRV_PCM_STREAM_CAPTURE:
+               if (intel_mid_i2s_command(ssp_config->i2s_handle,
+                               SSP_CMD_ALLOC_RX, NULL)) {
+                       pr_err("can not alloc RX DMA Channel\n");
+                       return -EBUSY;
+               }
+               break;
+
+       default:
+               pr_err("SSP DAI: FCT %s Bad stream_dir: %d\n",
+                               __func__, substream->stream);
+               return -EINVAL;
+       }
+
+       ssp_config->intel_mid_dma_alloc = true;
+
+       pr_debug("SSP DAI: FCT %s leaves\n",
+                       __func__);
+
+       return 0;
+}
+
+/* BT/FM */
+static struct snd_soc_dai_ops ssp_dai_ops = {
+       .startup        = ssp_dai_startup,
+       .shutdown       = ssp_dai_shutdown,
+       .trigger        = ssp_dai_trigger,
+       .hw_params      = ssp_dai_hw_params,
+       .set_sysclk     = ssp_set_dai_sysclk,
+       .set_pll    = NULL,
+       .set_fmt        = ssp_set_dai_fmt,
+       .set_tdm_slot   = ssp_set_dai_tdm_slot,
+       .set_tristate   = ssp_set_dai_tristate,
+};
+
+#define SSP_SUPPORTED_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
+                       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define SSP_SUPPORTED_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_U16_LE | \
+                       SNDRV_PCM_FMTBIT_S8 | \
+                       SNDRV_PCM_FMTBIT_U8)
+
+struct snd_soc_dai_driver intel_ssp_platform_dai[] = {
+{
+       .name = SSP_MODEM_DAI_NAME,
+       .id = 0,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SSP_SUPPORTED_RATES,
+               .formats = SSP_SUPPORTED_FORMATS,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SSP_SUPPORTED_RATES,
+               .formats = SSP_SUPPORTED_FORMATS,
+       },
+       .ops = &ssp_dai_ops,
+       .probe = ssp_probe,
+       .remove = ssp_remove,
+},
+{
+       .name = SSP_BT_DAI_NAME,
+       .id = 1,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SSP_SUPPORTED_RATES,
+               .formats = SSP_SUPPORTED_FORMATS,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SSP_SUPPORTED_RATES,
+               .formats = SSP_SUPPORTED_FORMATS,
+       },
+       .ops = &ssp_dai_ops,
+       .probe = ssp_probe,
+       .remove = ssp_remove,
+},
+};
+
+static int ssp_dai_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct workqueue_struct *ssp_dai_wq;
+
+       pr_debug("SSP DAI: FCT %s enters\n",
+                       __func__);
+
+       ret = snd_soc_register_platform(&pdev->dev,
+                               &soc_ssp_platform_drv);
+       if (ret) {
+               pr_err("registering SSP PLATFORM failed\n");
+               snd_soc_unregister_dai(&pdev->dev);
+               return -EBUSY;
+       }
+
+       ret = snd_soc_register_dais(&pdev->dev,
+                       intel_ssp_platform_dai,
+                       ARRAY_SIZE(intel_ssp_platform_dai));
+
+       if (ret) {
+               pr_err("registering cpu DAIs failed\n");
+               snd_soc_unregister_dai(&pdev->dev);
+               return -EBUSY;
+       }
+
+       ssp_dai_wq = create_workqueue("ssp_transfer_data");
+
+       if (!ssp_dai_wq) {
+               pr_err("work queue failed\n");
+               snd_soc_unregister_dai(&pdev->dev);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, ssp_dai_wq);
+
+       pr_debug("SSP DAI: FCT %s leaves %d\n",
+                       __func__, ret);
+
+       return ret;
+}
+
+static int ssp_dai_remove(struct platform_device *pdev)
+{
+       struct workqueue_struct *ssp_dai_wq = platform_get_drvdata(pdev);
+
+       pr_debug("SSP DAI: FCT %s enters\n",
+                       __func__);
+
+       flush_workqueue(ssp_dai_wq);
+
+       destroy_workqueue(ssp_dai_wq);
+
+       platform_set_drvdata(pdev, NULL);
+
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(intel_ssp_platform_dai));
+
+       snd_soc_unregister_platform(&pdev->dev);
+
+       pr_debug("SSP DAI: FCT %s leaves\n",
+                       __func__);
+
+       return 0;
+}
+
+static struct platform_driver intel_ssp_dai_driver = {
+       .driver         = {
+               .name           = "mid-ssp-dai",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = ssp_dai_probe,
+       .remove         = ssp_dai_remove,
+};
+
+
+static int __init ssp_soc_dai_init(void)
+{
+       pr_debug("SSP DAI: FCT %s called\n",
+                       __func__);
+
+       return  platform_driver_register(&intel_ssp_dai_driver);
+}
+module_init(ssp_soc_dai_init);
+
+static void __exit ssp_soc_dai_exit(void)
+{
+       pr_debug("SSP DAI: FCT %s called\n",
+                       __func__);
+
+       platform_driver_unregister(&intel_ssp_dai_driver);
+
+}
+module_exit(ssp_soc_dai_exit);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
+MODULE_AUTHOR("Selma Bensaid");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ssp-cpu-dai");
diff --git a/sound/soc/mid-x86/mid_ssp.h b/sound/soc/mid-x86/mid_ssp.h
new file mode 100644 (file)
index 0000000..64017bc
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *     mfld_ssp.h - ASoC CPU DAI driver for
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Authors:   Selma Bensaid <selma.bensaid@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef MID_SSP_H_
+#define MID_SSP_H_
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include <linux/intel_mid_i2s_if.h>
+
+#define SSP_MODEM_DAI_NAME "ssp-modem-cpu-dai"
+#define SSP_BT_DAI_NAME "ssp-bt-cpu-dai"
+
+#define SSP_MAX_BUFFER         (640*1024)
+#define SSP_MIN_BUFFER         (640*1024)
+
+#define TRISTATE_BIT                   0
+#define FRAME_SYNC_RELATIVE_TIMING_BIT 1
+#define DUMMY_START_ONE_PERIOD_OFFSET  2
+#define DUMMY_START_ONE_PERIOD_MASK     0x3
+
+#define IS_TRISTATE_ENABLED(x) (x & BIT(TRISTATE_BIT))
+#define IS_NEXT_FRMS_ASSERTED_WITH_LSB_PREVIOUS_FRM(x) \
+                       ((x & BIT(FRAME_SYNC_RELATIVE_TIMING_BIT)) \
+                                       >> FRAME_SYNC_RELATIVE_TIMING_BIT)
+#define IS_DUMMY_START_ONE_PERIOD_OFFSET(x) \
+                       ((x >> DUMMY_START_ONE_PERIOD_OFFSET) \
+                                       & DUMMY_START_ONE_PERIOD_MASK)
+
+#define MID_SSP_RX_FIFO_THRESHOLD 8
+#define MID_SSP_TX_FIFO_THRESHOLD 7
+
+/*
+ * Structures Definition
+ */
+
+
+struct intel_ssp_config {
+       struct intel_mid_i2s_hdl *i2s_handle;
+       struct intel_mid_i2s_settings i2s_settings;
+       bool intel_mid_dma_alloc;
+};
+
+struct intel_alsa_ssp_stream_info {
+       struct snd_pcm_substream *substream;
+       struct work_struct ssp_ws;
+       struct intel_ssp_config *ssp_config;
+       unsigned long stream_status;
+       u32 period_req_index;
+       s32 period_cb_index;
+       u8 *addr;
+       int length;
+};
+
+
+/*
+ * Enum Definition
+ */
+
+enum intel_alsa_ssp_stream_status {
+       INTEL_ALSA_SSP_STREAM_INIT = 0,
+       INTEL_ALSA_SSP_STREAM_STARTED,
+       INTEL_ALSA_SSP_STREAM_RUNNING,
+       INTEL_ALSA_SSP_STREAM_PAUSED,
+       INTEL_ALSA_SSP_STREAM_DROPPED,
+};
+enum ssp_clk_def {
+       SSP_CLK_ONCHIP = 0x0,
+       SSP_CLK_NET,
+       SSP_CLK_EXT,
+       SSP_CLK_AUDIO
+};
+
+
+#endif /* MID_SSP_H_ */