audio: platform: clean up platform driver to support future platforms
authorOmair Mohammed Abdullah <omair.m.abdullah@intel.com>
Fri, 20 Jan 2012 07:05:33 +0000 (12:35 +0530)
committerbuildbot <buildbot@intel.com>
Fri, 20 Apr 2012 17:02:55 +0000 (10:02 -0700)
BZ: 15815

Platform driver contains Medfield specific code which needs to be removed so
that other platforms can be supported with same platform driver.

This change makes the SST driver register to the platform driver instead of the
other way round. The intel_sst_set_pll() function is replaced by the
intel_scu_ipc_set_osc_clk0() function and a proper calling mechanism is set up
in the machine driver. The intel_sst.h file is replaced by sst_platform.h. Some
ASoC core changes are backported from the upstream tree.  Clock and PLL
enabling/disabling sequence is changed.

Change-Id: I40848eb0ebd671d988428daccccd9b8027752123
Signed-off-by: Omair Mohammed Abdullah <omair.m.abdullah@linux.intel.com>
Reviewed-on: http://android.intel.com:8080/33673
Reviewed-by: Abdullah, Omair M <omair.m.abdullah@intel.com>
Reviewed-by: Babu, Ramesh <ramesh.babu@intel.com>
Reviewed-by: Koul, Vinod <vinod.koul@intel.com>
Reviewed-by: Hibare, PramodX <pramodx.hibare@intel.com>
Tested-by: Hibare, PramodX <pramodx.hibare@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
31 files changed:
arch/x86/include/asm/intel_scu_ipc.h
drivers/input/misc/intel_mid_vibra.c
drivers/misc/Kconfig
drivers/misc/a1026.c
drivers/platform/x86/intel_scu_ipc.c
include/sound/intel_sst.h [deleted file]
include/sound/intel_sst_ioctl.h
include/sound/soc-dapm.h
include/sound/soc.h
sound/soc/codecs/sn95031.c
sound/soc/codecs/sn95031.h
sound/soc/mid-x86/Kconfig
sound/soc/mid-x86/Makefile
sound/soc/mid-x86/clv_machine.c
sound/soc/mid-x86/mfld_machine.c
sound/soc/mid-x86/mfld_machine_gi.c
sound/soc/mid-x86/sst/intel_sst.c
sound/soc/mid-x86/sst/intel_sst_app_interface.c
sound/soc/mid-x86/sst/intel_sst_common.h
sound/soc/mid-x86/sst/intel_sst_drv_interface.c
sound/soc/mid-x86/sst/intel_sst_dsp.c
sound/soc/mid-x86/sst/intel_sst_fw_ipc.h
sound/soc/mid-x86/sst/intel_sst_ipc.c
sound/soc/mid-x86/sst/intel_sst_pvt.c
sound/soc/mid-x86/sst/intel_sst_stream.c
sound/soc/mid-x86/sst/intel_sst_stream_encoded.c
sound/soc/mid-x86/sst_platform.c
sound/soc/mid-x86/sst_platform.h
sound/soc/mid-x86/sst_platform_pvt.h [new file with mode: 0644]
sound/soc/soc-core.c
sound/soc/soc-dapm.c

index abdde5d..8cd4e97 100644 (file)
@@ -69,6 +69,16 @@ int intel_scu_ipc_read_osnib_rr(u8 *rr);
 
 int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz);
 
+enum clk0_mode {
+       CLK0_AUDIENCE = 0x4,
+       CLK0_VIBRA1 = 0x8,
+       CLK0_VIBRA2 = 0x10,
+       CLK0_MSIC = 0x20,
+       CLK0_QUERY = 0x1000,
+};
+
+int intel_scu_ipc_set_osc_clk0(unsigned int enable, enum clk0_mode mode);
+
 extern struct blocking_notifier_head intel_scu_notifier;
 
 static inline void intel_scu_notifier_add(struct notifier_block *nb)
index 7e064ca..404d45b 100644 (file)
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <sound/intel_sst.h>
-
+/* FIXME: remove once vibra becomes PCI driver */
+#include "../../../sound/soc/mid-x86/sst_platform.h"
 
 #define VIBRA_ENABLE_GPIO 40
 #define PWM_ENABLE_GPIO 49
 
-
 struct vibra_info {
        struct mutex            lock;
        struct device           *dev;
@@ -85,7 +84,6 @@ static ssize_t vibra_set_vibrator(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t len)
 {
        long vibrator_enable;
-       int  ret;
 
        struct platform_device *pdev = to_platform_device(dev);
        struct vibra_info *info = platform_get_drvdata(pdev);
index ffcabdf..dd00161 100755 (executable)
@@ -548,8 +548,7 @@ config MID_I2S_DEV
 
 config A1026
        tristate "Audience a1026/eS305 Voice Processor"
-       depends on I2C
-       depends on SND_INTEL_SST
+       depends on I2C && INTEL_SCU_IPC
        help
          Provides an interface to the Audience voice processing
          unit via an I2C bus interface.
index c3ae384..97dc91a 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
-#include <sound/intel_sst.h>
+#include <asm/intel_scu_ipc.h>
 #include <linux/a1026.h>
 #include <linux/i2c.h>
 
@@ -155,7 +155,8 @@ static int suspend(struct vp_ctxt *vp)
        vp->suspended = 1;
        msleep(120); /* 120 defined by fig 2 of eS305 as the time to wait
                        before clock gating */
-       rc = intel_sst_set_pll(false, SST_PLL_AUDIENCE);
+       pr_debug("A1026 suspend\n");
+       rc = intel_scu_ipc_set_osc_clk0(false, CLK0_AUDIENCE);
        if (rc)
                pr_err("ipc clk disable command failed: %d\n", rc);
 
@@ -527,7 +528,7 @@ static long es305_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case A1026_ENABLE_CLOCK:
                pr_debug("%s:ipc clk enable command\n", __func__);
                mutex_lock(&the_vp->mutex);
-               rc = intel_sst_set_pll(true, SST_PLL_AUDIENCE);
+               rc = intel_scu_ipc_set_osc_clk0(true, CLK0_AUDIENCE);
                mutex_unlock(&the_vp->mutex);
                if (rc) {
                        pr_err("ipc clk enable command failed: %d\n", rc);
index f698f78..629aaea 100644 (file)
@@ -148,6 +148,10 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
 /* PM Qos struct */
 static struct pm_qos_request_list *qos;
 
+/* Mode for Audio clock */
+static DEFINE_MUTEX(osc_clk0_lock);
+static unsigned int osc_clk0_mode;
+
 /*
  * Command Register (Write Only):
  * A write to this register results in an interrupt to the SCU core processor
@@ -1727,6 +1731,48 @@ int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz)
 EXPORT_SYMBOL_GPL(intel_scu_ipc_osc_clk);
 
 /*
+ * OSC_CLK_AUDIO is connected to the MSIC as well as Audience, so it should be
+ * turned on if any one of them requests it to be on and it should be turned off
+ * only if no one needs it on.
+ */
+int intel_scu_ipc_set_osc_clk0(unsigned int enable, enum clk0_mode mode)
+{
+       int ret = 0, clk_enable;
+       static const unsigned int clk_khz = 19200;
+
+       pr_debug("set_clk0 request %s for Mode 0x%x\n",
+                               enable ? "ON" : "OFF", mode);
+       mutex_lock(&osc_clk0_lock);
+       if (mode == CLK0_QUERY) {
+               ret = osc_clk0_mode;
+               goto out;
+       }
+       if (enable) {
+               /* if clock is already on, just add new user */
+               if (osc_clk0_mode) {
+                       osc_clk0_mode |= mode;
+                       goto out;
+               }
+               osc_clk0_mode |= mode;
+               pr_debug("set_clk0: enabling clk, mode 0x%x\n", osc_clk0_mode);
+               clk_enable = 1;
+       } else {
+               osc_clk0_mode &= ~mode;
+               pr_debug("set_clk0: disabling clk, mode 0x%x\n", osc_clk0_mode);
+               /* others using the clock, cannot turn it of */
+               if (osc_clk0_mode)
+                       goto out;
+               clk_enable = 0;
+       }
+       pr_debug("configuring OSC_CLK_AUDIO now\n");
+       ret = intel_scu_ipc_osc_clk(OSC_CLK_AUDIO, clk_enable ? clk_khz : 0);
+out:
+       mutex_unlock(&osc_clk0_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(intel_scu_ipc_set_osc_clk0);
+
+/*
  * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
  * When ioc bit is set to 1, caller api must wait for interrupt handler called
  * which in turn unlocks the caller api. Currently this is not used
diff --git a/include/sound/intel_sst.h b/include/sound/intel_sst.h
deleted file mode 100644 (file)
index 3c48120..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef __INTEL_SST_H__
-#define __INTEL_SST_H__
-/*
- *  intel_sst.h - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-10 Intel Corporation
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This driver exposes the audio engine functionalities to the ALSA
- *     and middleware.
- *  This file is shared between the SST and MAD drivers
- */
-#include <sound/intel_sst_ioctl.h>
-#include <sound/jack.h>
-
-#define SST_CARD_NAMES "intel_mid_card"
-#define SST_PLL_DELAY 2000
-
-#define MFLD_MAX_HW_CH 4
-/* control list Pmic & Lpe */
-/* Input controls */
-enum port_status {
-       ACTIVATE = 1,
-       DEACTIVATE,
-};
-
-/* Card states */
-enum sst_card_states {
-       SND_CARD_UN_INIT = 0,
-       SND_CARD_INIT_DONE,
-};
-
-enum sst_controls {
-       SST_SND_ALLOC =                 0x1000,
-       SST_SND_PAUSE =                 0x1001,
-       SST_SND_RESUME =                0x1002,
-       SST_SND_DROP =                  0x1003,
-       SST_SND_FREE =                  0x1004,
-       SST_SND_BUFFER_POINTER =        0x1005,
-       SST_SND_STREAM_INIT =           0x1006,
-       SST_SND_START    =              0x1007,
-       SST_SND_STREAM_PROCESS =        0x1008,
-       SST_CONTROL_BASE =              0x1000,
-       SST_ENABLE_RX_TIME_SLOT =       0x1009,
-       SST_SND_DEVICE_SUSPEND =        0x1010,
-       SST_VMIC_CHANNEL_SELECT =       0x1011,
-       SST_SND_DEVICE_RESUME =         0x1012,
-       SST_SND_DEVICE_RESUME_SYNC =    0x1013,
-       SST_SET_RUNTIME_PARAMS =        0x1014,
-       SST_SET_ALGO_PARAMS =           0x1015,
-       SST_MAX_CONTROLS =              0x1015,
-};
-
-enum SND_CARDS {
-       SND_FS = 0,
-       SND_MX,
-       SND_NC,
-       SND_MSIC
-};
-
-struct pcm_stream_info {
-       int str_id;
-       void *mad_substream;
-       void (*period_elapsed) (void *mad_substream);
-       unsigned long long buffer_ptr;
-       unsigned long long pcm_delay;
-       int sfreq;
-};
-
-struct snd_pmic_ops {
-       int card_status;
-       int master_mute;
-       int num_channel;
-       int input_dev_id;
-       int mute_status;
-       struct mutex lock;
-       int pb_on, pbhs_on;
-       int cap_on;
-       int output_dev_id;
-       int lineout_dev_id, lineout_names_cnt;
-       int prev_lineout_dev_id;
-       bool jack_interrupt_status;
-       void (*pmic_irq_cb) (void *cb_data, u8 value);
-       void (*pmic_irq_enable)(void *data);
-       int (*pmic_get_mic_bias)(void *intelmaddata);
-       int (*pmic_set_headset_state)(int state);
-
-       unsigned int hw_dmic_map[MFLD_MAX_HW_CH];
-       unsigned int available_dmics;
-       int (*set_hw_dmic_route) (u8 index);
-};
-
-extern void sst_mad_send_jack_report(struct snd_jack *jack,
-                                    int buttonpressevent,
-                                    int status);
-
-
-int intemad_set_headset_state(int state);
-int intelmad_get_mic_bias(void);
-
-struct intel_sst_pcm_control {
-       int (*open) (struct snd_sst_params *str_param);
-       int (*device_control) (int cmd, void *arg);
-       int (*set_generic_params) (enum sst_controls cmd, void *arg);
-       int (*close) (unsigned int str_id);
-};
-struct intel_sst_card_ops {
-       unsigned int  vendor_id;
-       struct intel_sst_pcm_control *pcm_control;
-};
-
-/* modified for generic access */
-struct sc_reg_access {
-       u16 reg_addr;
-       u8 value;
-       u8 mask;
-};
-enum sc_reg_access_type {
-       PMIC_READ = 0,
-       PMIC_WRITE,
-       PMIC_READ_MODIFY,
-};
-
-enum intel_sst_pll_mode {
-       SST_PLL_VOICE = 0x1,
-       SST_PLL_AUDIO = 0x2,
-       SST_PLL_AUDIENCE = 0x4,
-       SST_PLL_VIBRA1 = 0x8,
-       SST_PLL_VIBRA2 = 0x10,
-       SST_PLL_MSIC = 0x20,
-};
-
-enum lpe_param_types_mixer {
-       SST_ALGO_PARAM_MIXER_STREAM_CFG = 0x801,
-};
-
-
-int register_sst_card(struct intel_sst_card_ops *card);
-void unregister_sst_card(struct intel_sst_card_ops *card);
-int intel_sst_set_pll(unsigned int enable, enum intel_sst_pll_mode mode);
-int intel_sst_get_pll(void);
-void intel_sst_pwm_suspend(unsigned int suspend);
-#endif /* __INTEL_SST_H__ */
index a63c2c4..e2277e5 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/types.h>
 
 enum sst_codec_types {
-/*  AUDIO/MUSIC        CODEC Type Definitions */
+       /*  AUDIO/MUSIC CODEC Type Definitions */
        SST_CODEC_TYPE_UNKNOWN = 0,
        SST_CODEC_TYPE_PCM,     /* Pass through Audio codec */
        SST_CODEC_TYPE_MP3,
@@ -62,14 +62,6 @@ enum sst_algo_types {
        SST_CODEC_OEM2 = 0xC9,
 };
 
-enum snd_sst_stream_ops {
-       STREAM_OPS_PLAYBACK = 0,        /* Decode */
-       STREAM_OPS_CAPTURE,             /* Encode */
-       STREAM_OPS_PLAYBACK_DRM,        /* Play Audio/Voice */
-       STREAM_OPS_PLAYBACK_ALERT,      /* Play Audio/Voice */
-       STREAM_OPS_CAPTURE_VOICE_CALL,  /* CSV Voice recording */
-};
-
 enum stream_mode {
        SST_STREAM_MODE_NONE = 0,
        SST_STREAM_MODE_DNR = 1,
@@ -85,33 +77,12 @@ enum stream_type {
        SST_STREAM_TYPE_LOW_LATENCY = 4,
 };
 
-enum snd_sst_audio_device_type {
-       SND_SST_DEVICE_HEADSET = 1,
-       SND_SST_DEVICE_IHF,
-       SND_SST_DEVICE_VIBRA,
-       SND_SST_DEVICE_HAPTIC,
-       SND_SST_DEVICE_CAPTURE,
-};
-
-enum snd_sst_input_stream {
-       SST_INPUT_STREAM_PCM = 0x2,
-       SST_INPUT_STREAM_COMPRESS = 0x8,
-       SST_INPUT_STREAM_MIXED = 0xA,
-};
-
-enum snd_sst_stream_type {
-       SST_STREAM_DEVICE_HS = 32,
-       SST_STREAM_DEVICE_IHF = 33,
-       SST_STREAM_DEVICE_MIC0 = 34,
-       SST_STREAM_DEVICE_MIC1 = 35,
-};
-
 /* Firmware Version info */
 struct snd_sst_fw_version {
        __u8 build;     /* build number*/
        __u8 minor;     /* minor number*/
        __u8 major;     /* major number*/
-       __u8 type; /* build type */
+       __u8 type;      /* build type */
 };
 
 /* Port info structure */
@@ -331,7 +302,6 @@ enum snd_sst_device_type {
 };
 
 enum snd_sst_device_mode {
-
        SND_SST_DEV_MODE_PCM_MODE1 = 1, /*(16-bit word, bit-length frame sync)*/
        SND_SST_DEV_MODE_PCM_MODE2,
        SND_SST_DEV_MODE_PCM_MODE3,
@@ -350,7 +320,7 @@ enum snd_sst_port_action {
 enum stream_param_type {
        SST_SET_TIME_SLOT = 0,
        SST_SET_CHANNEL_INFO = 1,
-       OTHERS = 2, /*reserved for other params that need to be set in future*/
+       OTHERS = 2, /*reserved for future params*/
 };
 
 /* Target selection per device structure */
@@ -425,7 +395,7 @@ struct snd_sst_tuning_params {
        __u8 size;
        __u8 rsvd;
        __u64 addr;
-} __attribute__ ((packed));
+} __packed;
 
 struct snd_sst_runtime_params {
        __u8 type;
@@ -433,7 +403,8 @@ struct snd_sst_runtime_params {
        __u8 size;
        __u8 rsvd;
        void *addr;
-} __attribute__ ((packed));
+} __packed;
+
 /*IOCTL defined here */
 /*SST MMF IOCTLS only */
 #define SNDRV_SST_STREAM_SET_PARAMS _IOWR('L', 0x00, \
index c46e7d8..304369a 100644 (file)
@@ -513,6 +513,8 @@ struct snd_soc_dapm_context {
        int dev_power;
        struct list_head list;
 
+       int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
+
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_dapm;
 #endif
index 0c6c621..a0d05e4 100644 (file)
@@ -617,8 +617,9 @@ struct snd_soc_codec_driver {
                              enum snd_soc_bias_level level);
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
-       int (*stream_event)(struct snd_soc_dapm_context *,
-                               enum snd_soc_bias_level level);
+
+       /* codec stream completion event */
+       int (*stream_event)(struct snd_soc_dapm_context *, int level);
 };
 
 /* SoC platform interface */
index eaeb9b1..24a3fb1 100644 (file)
@@ -39,7 +39,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 #include <sound/jack.h>
-#include <sound/intel_sst.h>
 #include "sn95031.h"
 
 #define SN95031_RATES (SNDRV_PCM_RATE_8000_96000)
@@ -95,7 +94,6 @@ static unsigned int sn95031_read_voltage(void)
 static void sn95031_enable_mic_bias(struct snd_soc_codec *codec)
 {
        pr_debug("enable mic bias\n");
-       pr_debug("codec %p\n", codec);
        mutex_lock(&codec->mutex);
        /* GI board has amic bias swapped, we need to enable
                Mic2 bias for jack */
@@ -149,13 +147,16 @@ static inline int sn95031_write(struct snd_soc_codec *codec,
        return ret;
 }
 
-static void sn95031_configure_pll(struct snd_soc_codec *codec, int operation)
+void sn95031_configure_pll(struct snd_soc_codec *codec, int operation)
 {
        struct sn95031_priv *sn95031_ctx;
        sn95031_ctx = snd_soc_codec_get_drvdata(codec);
 
-       if (operation) {
-               pr_debug("enabling PLL\n");
+       if (sn95031_ctx->pll_state == PLL_ENABLE_PENDING
+                       && operation == ENABLE_PLL) {
+               pr_debug("setting PLL to 0x%x\n", sn95031_ctx->clk_src);
+               snd_soc_write(codec, SN95031_AUDPLLCTRL, 0x20);
+               udelay(1000);
                /* PLL takes few msec to stabilize
                Refer sec2.3 MFLD Audio Interface Doc-rev0.7 */
                snd_soc_write(codec, SN95031_AUDPLLCTRL,
@@ -166,51 +167,31 @@ static void sn95031_configure_pll(struct snd_soc_codec *codec, int operation)
                snd_soc_update_bits(codec, SN95031_AUDPLLCTRL, BIT(5), BIT(5));
                udelay(1000);
                sn95031_ctx->pll_state = PLL_ENABLED;
-       } else {
+       } else if (operation == DISABLE_PLL) {
                pr_debug("disabling PLL\n");
                sn95031_ctx->clk_src = SN95031_INVALID;
                sn95031_ctx->pll_state = PLL_DISABLED;
                snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
+       } else {
+               pr_debug("PLL configure state: op=0x%x, state=0x%x\n",
+                               operation, sn95031_ctx->pll_state);
        }
 }
+EXPORT_SYMBOL_GPL(sn95031_configure_pll);
 
-static int sn95031_codec_stream_event(struct snd_soc_dapm_context *dapm,
-               int event)
-{
-       pr_debug("%s:Event=%d\n", __func__, event);
-
-       if (event == SND_SOC_DAPM_STREAM_STOP) {
-               /* disable the MSIC PLL only if no other active streams */
-               if (dapm->codec->active == 0) {
-                       sn95031_configure_pll(dapm->codec, DISABLE_PLL);
-                       /* disable PLLIN source clock */
-                       intel_sst_set_pll(false, SST_PLL_MSIC);
-               }
-       }
-       return 0;
-}
 static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
                enum snd_soc_bias_level level)
 {
        struct sn95031_priv *sn95031_ctx;
        sn95031_ctx = snd_soc_codec_get_drvdata(codec);
 
+       pr_debug("%s: 0x%x\n", __func__, level);
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               pr_debug("bias_prepare\n");
-               /* enable msic pll only when any codec dai is active,
-                       not other use cases like static vibra etc */
-               if (codec->active) {
-                       pr_debug("vaud_bias powering up pll\n");
-                       intel_sst_set_pll(true, SST_PLL_MSIC);
-                       /* allow few ms to stabilize the clock before
-                               enabling the MSIC PLL */
-                       usleep_range(5000, 6000);
-                       sn95031_configure_pll(codec, ENABLE_PLL);
-               }
+               pr_debug("vaud_bias PREPARE\n");
                break;
 
        case SND_SOC_BIAS_STANDBY:
@@ -218,14 +199,15 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
                        pr_debug("vaud_bias power up rail\n");
                        /* power up the rail, on in normal and aoac mode */
                        snd_soc_write(codec, SN95031_VAUD, 0x2D);
-                       msleep(1);
+                       usleep_range(1000, 1100);
                } else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
-                       pr_debug("vaud_bias standby\n");
+                       pr_debug("vaud_bias STANDBY\n");
                }
                break;
 
        case SND_SOC_BIAS_OFF:
-               pr_debug("vaud_bias _OFF doing rail shutdown\n");
+               pr_debug("vaud_bias OFF, doing rail shutdown\n");
+               sn95031_configure_pll(codec, DISABLE_PLL);
                /*
                 * off mode is 100, and we need AOAC as off as well,
                 * so 100100b ie 24
@@ -338,76 +320,6 @@ static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int sn95031_enable_pnw_clk(struct snd_soc_dapm_widget *w,
-                       struct snd_kcontrol *k, int event)
-{
-       int clk_id = 0;
-
-       if (!strcmp(w->name, "Vibra1Clock"))
-               clk_id = SST_PLL_VIBRA1;
-       else if (!strcmp(w->name, "Vibra2Clock"))
-               clk_id = SST_PLL_VIBRA2;
-
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               intel_sst_set_pll(true, clk_id);
-       else if (SND_SOC_DAPM_EVENT_OFF(event))
-               intel_sst_set_pll(false, clk_id);
-       return 0;
-}
-
-/* Callback to set volume for *VOLCTRL regs. Needs to be implemented separately
- * since clock and VAUDA need to be on before value can be written to the regs
- */
-static int sn95031_set_vol_2r(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int reg = mc->reg;
-       unsigned int reg2 = mc->rreg;
-       unsigned int shift = mc->shift;
-       int max = mc->max;
-       unsigned int mask = (1 << fls(max)) - 1;
-       unsigned int invert = mc->invert;
-       int err;
-       unsigned int val, val2, val_mask;
-       int sst_pll_mode_saved;
-
-       val_mask = mask << shift;
-       val = (ucontrol->value.integer.value[0] & mask);
-       val2 = (ucontrol->value.integer.value[1] & mask);
-
-       if (invert) {
-               val = max - val;
-               val2 = max - val2;
-       }
-
-       val = val << shift;
-       val2 = val2 << shift;
-
-       pr_debug("enabling PLL and VAUDA to change volume\n");
-       mutex_lock(&codec->mutex);
-       sst_pll_mode_saved = intel_sst_get_pll();
-       intel_sst_set_pll(true, SST_PLL_MSIC);
-       udelay(SST_PLL_DELAY);
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
-       snd_soc_dapm_sync(&codec->dapm);
-
-       err = snd_soc_update_bits(codec, reg, val_mask, val);
-       if (err < 0)
-               goto restore_state;
-
-       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
-restore_state:
-       snd_soc_dapm_disable_pin(&codec->dapm, "VirtBias");
-       snd_soc_dapm_sync(&codec->dapm);
-       if ((sst_pll_mode_saved & SST_PLL_MSIC) == 0)
-               intel_sst_set_pll(false, SST_PLL_MSIC);
-       mutex_unlock(&codec->mutex);
-       return err;
-}
-
 /* mux controls */
 static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
 
@@ -463,8 +375,6 @@ static unsigned int mic_tlv[] = {
        2, 2, TLV_DB_SCALE_ITEM(2100, 0, 0),
        3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
 };
-/* -62db to 9 db in 1db steps*/
-static const DECLARE_TLV_DB_SCALE(out_tlv, -6200, 100, 0);
 
 static const struct soc_enum sn95031_micmode1_enum =
        SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text);
@@ -614,18 +524,9 @@ static const struct snd_kcontrol_new sn95031_snd_controls[] = {
                        2, 3, 0, mic_tlv),
        SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2,
                        2, 3, 0, mic_tlv),
-       /* Add digital volume and mute controls for Headphone/Headset*/
-       SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", SN95031_HSLVOLCTRL,
-                               SN95031_HSRVOLCTRL, 0, 71, 1,
-                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
-                               out_tlv),
        SOC_DOUBLE_R("Headphone Playback Switch", SN95031_HSLVOLCTRL,
                                SN95031_HSRVOLCTRL, 7, 1, 0),
        /* Add digital volume and mute controls for Speaker*/
-       SOC_DOUBLE_R_EXT_TLV("Speaker Playback Volume", SN95031_IHFLVOLCTRL,
-                               SN95031_IHFRVOLCTRL, 0, 71, 1,
-                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
-                               out_tlv),
        SOC_DOUBLE_R("Speaker Playback Switch", SN95031_IHFLVOLCTRL,
                                SN95031_IHFRVOLCTRL, 7, 1, 0),
 
@@ -682,8 +583,6 @@ static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
        SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0),
        SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0),
        SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0),
-       /* Dummy widget to trigger VAUDA on/off */
-       SND_SOC_DAPM_MICBIAS("VirtBias", SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0,
                                sn95031_dmic12_event,
@@ -708,12 +607,6 @@ static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0,
                        sn95031_vihf_event,
                        SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_SUPPLY("Vibra1Clock", SND_SOC_NOPM, 0, 0,
-                       sn95031_enable_pnw_clk,
-                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_SUPPLY("Vibra2Clock", SND_SOC_NOPM, 0, 0,
-                       sn95031_enable_pnw_clk,
-                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* playback path driver enables */
        SND_SOC_DAPM_OUT_DRV("Headset Left Playback",
@@ -805,8 +698,6 @@ static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route sn95031_audio_map[] = {
        /* headset and earpiece map */
-       { "HPOUTL", NULL, "Headset Rail"},
-       { "HPOUTR", NULL, "Headset Rail"},
        { "HPOUTL", NULL, "Headset Left Playback" },
        { "HPOUTR", NULL, "Headset Right Playback" },
        { "EPOUT", NULL, "Earpiece Playback" },
@@ -842,13 +733,11 @@ static const struct snd_soc_dapm_route sn95031_audio_map[] = {
        { "Vibra1 Playback", NULL, "Vibra1 Enable Mux"},
        { "Vibra1 Enable Mux", "PWM", "Vibra1 DAC"},
        { "Vibra1 Enable Mux", "SPI", "VIB1SPI"},
-       { "VIB1SPI", NULL, "Vibra1Clock"},
 
        { "VIB2OUT", NULL, "Vibra2 Playback"},
        { "Vibra2 Playback", NULL, "Vibra2 Enable Mux"},
        { "Vibra2 Enable Mux", "PWM", "Vibra2 DAC"},
        { "Vibra2 Enable Mux", "SPI", "VIB2SPI"},
-       { "VIB2SPI", NULL, "Vibra2Clock"},
 
        /* lineout */
        { "LINEOUTL", NULL, "Lineout Left Playback"},
@@ -970,73 +859,53 @@ static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
        return 0;
 }
 
-static int sn95031_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+static int sn95031_codec_set_pll(struct snd_soc_codec *codec, int pll_id,
                int source, unsigned int freq_in, unsigned int freq_out)
 {
-       int mode, target_clk_src;
-       struct snd_soc_codec *codec = codec_dai->codec;
+       int retval = 0;
        struct sn95031_priv *sn95031_ctx;
-       sn95031_ctx = snd_soc_codec_get_drvdata(codec_dai->codec);
-
-       pr_debug("set_dai_pll\n");
+       sn95031_ctx = snd_soc_codec_get_drvdata(codec);
 
+       pr_debug("%s: 0x%x\n", __func__, source);
        mutex_lock(&codec->mutex);
        if (!freq_in || !freq_out) {
                /* disable PLL  */
+               pr_debug("request to disable pll\n");
                sn95031_configure_pll(codec, DISABLE_PLL);
-               mutex_unlock(&codec->mutex);
-               return 0;
-       }
-       mode = snd_soc_read(codec, SN95031_PCM1C3) >> 7;
-       if (!mode && (!strcmp(codec_dai->name, "SN95031 Voice"))) {
-               target_clk_src = SN95031_PCM1BCLK;
-               snd_soc_write(codec, SN95031_PCM1C2, 0x04);
-       } else {
-               target_clk_src = SN95031_PLLIN;
-               snd_soc_write(codec, SN95031_PCM1C2, 0x00);
+               retval = 0;
+               goto out;
        }
-       /* clock source is same, so don't do anything */
-       if (sn95031_ctx->clk_src == target_clk_src) {
-               pr_debug("clk src is same, no action\n");
-               mutex_unlock(&codec->mutex);
-               return 0;
-       }
-       sn95031_ctx->clk_src = target_clk_src;
-       if (codec->dapm.bias_level >= SND_SOC_BIAS_PREPARE) {
-               pr_debug("bias_level is active, enabling pll\n");
-               intel_sst_set_pll(true, SST_PLL_MSIC);
-               /* allow few ms to stabilize the clock before
-                       enabling the MSIC PLL */
-               usleep_range(5000, 6000);
-               sn95031_configure_pll(codec, ENABLE_PLL);
-       } else
+       if (sn95031_ctx->clk_src != source) {
                sn95031_ctx->pll_state = PLL_ENABLE_PENDING;
-
+               sn95031_ctx->clk_src = source;
+       }
+       if (source == SN95031_INVALID)
+               sn95031_ctx->pll_state = PLL_DISABLED;
+out:
        mutex_unlock(&codec->mutex);
-       return 0;
+       return retval;
 }
 
 static int sn95031_set_pcm2_tristate(struct snd_soc_dai *codec_dai,
                                                        int tristate)
 {
-       u8 val;
-
-       pr_debug("enter:%s\n", __func__);
-       if (tristate)
-               val = 0;
-       else
-               val = 1;
-
        return snd_soc_update_bits(codec_dai->codec, SN95031_PCM2C2,
-                                               BIT(0), val);
+                                       BIT(0), !tristate);
 }
 
+static int sn95031_set_pcm1_tristate(struct snd_soc_dai *codec_dai,
+                                                       int tristate)
+{
+       return snd_soc_update_bits(codec_dai->codec, SN95031_PCM1C3,
+                                               BIT(0), !tristate);
+}
+
+
 static int sn95031_codec_set_params(struct snd_soc_codec *codec,
                                                unsigned int param)
 {
        unsigned int format;
 
-       pr_debug("enter:%s\n", __func__);
        switch (param) {
        case SNDRV_PCM_FORMAT_S16_LE:
                format = BIT(4)|BIT(5);
@@ -1055,27 +924,69 @@ static int sn95031_codec_set_params(struct snd_soc_codec *codec,
        return 0;
 }
 
+static int sn95031_set_voice_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int mode, format;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               mode = 0;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               mode = BIT(7);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format = BIT(2);
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format = BIT(1)|BIT(0);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format = BIT(1);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               format = 0;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               format = BIT(0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, SN95031_PCM1C3, BIT(7), mode);
+       snd_soc_update_bits(codec, SN95031_PCM1C2, BIT(0)|BIT(1)|BIT(2),
+                                                       format);
+       return 0;
+}
+
 static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        unsigned int rate;
 
-       pr_debug("pcm_hw param\n");
        switch (params_rate(params)) {
        case 48000:
                pr_debug("RATE_48000\n");
                rate = 0;
                break;
-
        case 44100:
                pr_debug("RATE_44100\n");
                rate = BIT(7);
                break;
-
        default:
                pr_err("ERR rate %d\n", params_rate(params));
                return -EINVAL;
        }
+       pr_debug("%s: format=0x%x\n", __func__, params_format(params));
        snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate);
 
        return 0;
@@ -1097,6 +1008,7 @@ static int sn95031_voice_hw_params(struct snd_pcm_substream *substream,
        default:
                return -EINVAL;
        }
+       pr_debug("%s: format=0x%x\n", __func__, format);
        snd_soc_update_bits(dai->codec, SN95031_PCM1C3,
                        BIT(4)|BIT(5), format);
 
@@ -1143,20 +1055,21 @@ static int sn95031_voice_hw_params(struct snd_pcm_substream *substream,
        snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate);
        snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(6)|BIT(5)|BIT(4),
                                                pcm1fs);
-       /* enable pcm 1 */
-       snd_soc_update_bits(dai->codec, SN95031_PCM1C3, BIT(0), BIT(0));
+       /* enable PCM1 */
+       sn95031_set_pcm1_tristate(dai, 0);
        return 0;
 }
 
 static int sn95031_voice_hw_free(struct snd_pcm_substream *substream,
                                        struct snd_soc_dai *dai)
 {
-       pr_debug("inside hw_free");
-       snd_soc_update_bits(dai->codec, SN95031_PCM1C3, BIT(0), 0);
+       pr_debug("%s\n", __func__);
+       sn95031_set_pcm1_tristate(dai, 1);
        /* PCM1 should be in slave, short or long sync mode for
                Tx line to be in Hi-Z state */
-       snd_soc_update_bits(dai->codec, SN95031_PCM1C3, BIT(7), 0);
-       snd_soc_write(dai->codec, SN95031_PCM1C2, 0x00);
+       sn95031_set_voice_dai_fmt(dai, SND_SOC_DAIFMT_CBS_CFS);
+       sn95031_set_voice_dai_fmt(dai, SND_SOC_DAIFMT_CBS_CFS
+                                       | SND_SOC_DAIFMT_DSP_A);
        return 0;
 }
 
@@ -1164,34 +1077,21 @@ static int sn95031_voice_hw_free(struct snd_pcm_substream *substream,
 static struct snd_soc_dai_ops sn95031_headset_dai_ops = {
        .digital_mute   = sn95031_pcm_hs_mute,
        .hw_params      = sn95031_pcm_hw_params,
-       .set_pll        = sn95031_set_dai_pll,
        .set_tristate   = sn95031_set_pcm2_tristate,
 };
 
 static struct snd_soc_dai_ops sn95031_speaker_dai_ops = {
        .digital_mute   = sn95031_pcm_spkr_mute,
        .hw_params      = sn95031_pcm_hw_params,
-       .set_pll        = sn95031_set_dai_pll,
-       .set_tristate   = sn95031_set_pcm2_tristate,
-};
-
-static struct snd_soc_dai_ops sn95031_vib1_dai_ops = {
-       .hw_params      = sn95031_pcm_hw_params,
-       .set_pll        = sn95031_set_dai_pll,
-       .set_tristate   = sn95031_set_pcm2_tristate,
-};
-
-static struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
-       .hw_params      = sn95031_pcm_hw_params,
-       .set_pll        = sn95031_set_dai_pll,
        .set_tristate   = sn95031_set_pcm2_tristate,
 };
 
 static struct snd_soc_dai_ops sn95031_voice_dai_ops = {
        .digital_mute   = sn95031_pcm_hs_mute,
        .hw_params      = sn95031_voice_hw_params,
+       .set_fmt        = sn95031_set_voice_dai_fmt,
        .hw_free        = sn95031_voice_hw_free,
-       .set_pll        = sn95031_set_dai_pll,
+       .set_tristate   = sn95031_set_pcm1_tristate,
 };
 
 static struct snd_soc_dai_driver sn95031_dais[] = {
@@ -1231,7 +1131,7 @@ static struct snd_soc_dai_driver sn95031_dais[] = {
                .rates = SN95031_RATES,
                .formats = SN95031_FORMATS,
        },
-       .ops = &sn95031_vib1_dai_ops,
+       .ops = NULL,
 },
 {      .name = "SN95031 Vibra2",
        .playback = {
@@ -1241,7 +1141,7 @@ static struct snd_soc_dai_driver sn95031_dais[] = {
                .rates = SN95031_RATES,
                .formats = SN95031_FORMATS,
        },
-       .ops = &sn95031_vib2_dai_ops,
+       .ops = NULL,
 },
 {
        .name = "SN95031 Voice",
@@ -1588,7 +1488,7 @@ struct snd_soc_codec_driver sn95031_codec = {
        .num_dapm_widgets       = ARRAY_SIZE(sn95031_dapm_widgets),
        .dapm_routes    = sn95031_audio_map,
        .num_dapm_routes        = ARRAY_SIZE(sn95031_audio_map),
-       .stream_event   = sn95031_codec_stream_event,
+       .set_pll        = sn95031_codec_set_pll,
 };
 
 static int __devinit sn95031_device_probe(struct platform_device *pdev)
index 3e08147..8d3481e 100644 (file)
@@ -163,6 +163,7 @@ extern void sn95031_jack_detection(struct mfld_jack_data *jack_data);
 extern void sn95031_oc_handler(struct snd_soc_codec *codec,
                                        int oc_interrupt_value);
 
+void sn95031_configure_pll(struct snd_soc_codec *codec, int operation);
 #ifdef CONFIG_SWITCH_MID
 extern void mid_headset_report(int state);
 #endif
index 120ed1f..45a91e8 100644 (file)
@@ -14,12 +14,12 @@ config SND_MFLD_MACHINE
 
 config SND_MFLD_MACHINE_GI
        tristate "SOC Machine Audio driver for Intel Medfield GI board"
-       depends on INTEL_SCU_IPC
-       depends on SND_INTEL_SST
+       depends on INTEL_SCU_IPC && X86 && GPIO_LANGWELL
        depends on MSIC_GPADC
        select SND_SOC_SN95031
        select SND_SST_PLATFORM
-       default N
+       select SND_INTEL_SST
+       default n
        help
           This adds support for ASoC machine driver for Gilligan Island board, based on
          Intel(R) MID Medfield platform. This will create an alsa sound card.
index b6923aa..313b148 100644 (file)
@@ -1,10 +1,17 @@
 snd-soc-sst-platform-objs := sst_platform.o
-snd-soc-mfld-machine-objs := mfld_machine.o
-snd-soc-mfld-machine-gi-objs := mfld_machine_gi.o
-snd-soc-clv-machine-objs := clv_machine.o
-
 obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o
+
+# Medfield board
+snd-soc-mfld-machine-objs := mfld_machine.o
 obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
+
+# Gilligan Island/Lexington board
+snd-soc-mfld-machine-gi-objs := mfld_machine_gi.o
 obj-$(CONFIG_SND_MFLD_MACHINE_GI) += snd-soc-mfld-machine-gi.o
+
+# Cloverview/Clovertrail+ board
+snd-soc-clv-machine-objs := clv_machine.o
 obj-$(CONFIG_SND_CLV_MACHINE) += snd-soc-clv-machine.o
+
+# DSP driver
 obj-$(CONFIG_SND_INTEL_SST) += sst/
index 5c479e0..efe0e85 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/delay.h>
 #include <linux/ipc_device.h>
 #include <asm/intel_scu_ipc.h>
-#include <sound/intel_sst.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -50,7 +49,7 @@
 
 static unsigned int vsp_mode;
 
-static vsp_mode_get(struct snd_kcontrol *kcontrol,
+static int vsp_mode_get(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        ucontrol->value.integer.value[0] = vsp_mode;
@@ -349,10 +348,10 @@ static int clv_set_bias_level(struct snd_soc_card *card,
        case SND_SOC_BIAS_PREPARE:
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
-                       intel_sst_set_pll(true, SST_PLL_MSIC);
+                       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
                break;
        case SND_SOC_BIAS_OFF:
-               intel_sst_set_pll(false, SST_PLL_MSIC);
+               intel_scu_ipc_set_osc_clk0(false, CLK0_MSIC);
        }
        codec->dapm.bias_level = level;
        pr_debug("codec->bias_level %u\n", card->dapm.bias_level);
@@ -418,12 +417,33 @@ static int clv_init(struct snd_soc_pcm_runtime *runtime)
        return ret;
 }
 
+static unsigned int rates_48000[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+       .count  = ARRAY_SIZE(rates_48000),
+       .list   = rates_48000,
+};
+
+static int clv_startup(struct snd_pcm_substream *substream)
+{
+       pr_debug("%s - applying rate constraint\n", __func__);
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE,
+                                  &constraints_48000);
+       return 0;
+}
+
 static struct snd_soc_ops clv_asp_ops = {
+       .startup = clv_startup,
        .hw_params = clv_asp_hw_params,
 };
+
 static struct snd_soc_ops clv_vsp_ops = {
        .hw_params = clv_vsp_hw_params,
 };
+
 struct snd_soc_dai_link clv_msic_dailink[] = {
        {
                .name = "Cloverview ASP",
@@ -550,11 +570,10 @@ static struct ipc_driver snd_clv_mc_driver = {
 
 static int __init snd_clv_driver_init(void)
 {
-       pr_debug("In %s\n", __func__);
+       pr_info("In %s\n", __func__);
        return ipc_driver_register(&snd_clv_mc_driver);
 }
-
-module_init(snd_clv_driver_init);
+late_initcall(snd_clv_driver_init);
 
 static void __exit snd_clv_driver_exit(void)
 {
index 91debe7..d26265b 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/async.h>
 #include <linux/gpio.h>
 #include <linux/ipc_device.h>
 #include <asm/intel-mid.h>
+#include <asm/intel_scu_ipc.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "../codecs/sn95031.h"
 
-#define MID_MONO 1
-#define MID_STEREO 2
-#define MID_MAX_CAP 5
 #define MFLD_JACK_INSERT 0x04
 #define HEADSET_DET_PIN 77
 
@@ -56,16 +56,14 @@ enum soc_mic_bias_zones {
        MFLD_MV_UNDEFINED,
 };
 
-static unsigned int    hs_switch;
-static unsigned int    lo_dac;
-
 struct mfld_mc_private {
-       struct ipc_device *socdev;
        void __iomem *int_base;
-       struct snd_soc_codec *codec;
        u8 jack_interrupt_status;
        u8 oc_interrupt_status;
        spinlock_t lock; /* lock for interrupt status and jack debounce */
+       int pcm1_master_mode;
+       unsigned int hs_switch;
+       unsigned int lo_dac;
 #ifdef CONFIG_HAS_WAKELOCK
        struct wake_lock wake_lock;
 #endif
@@ -99,7 +97,10 @@ static const struct soc_enum SN95031_pcm1_mode_config_enum =
 static int headset_get_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       ucontrol->value.integer.value[0] = hs_switch;
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
+       ucontrol->value.integer.value[0] = mc_drv_ctx->hs_switch;
        return 0;
 }
 
@@ -107,8 +108,10 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       if (ucontrol->value.integer.value[0] == hs_switch)
+       if (ucontrol->value.integer.value[0] == mc_drv_ctx->hs_switch)
                return 0;
 
        if (ucontrol->value.integer.value[0]) {
@@ -123,20 +126,22 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
        mutex_lock(&codec->mutex);
        snd_soc_dapm_sync(&codec->dapm);
        mutex_unlock(&codec->mutex);
-       hs_switch = ucontrol->value.integer.value[0];
+       mc_drv_ctx->hs_switch = ucontrol->value.integer.value[0];
 
        return 0;
 }
 
 static void lo_enable_out_pins(struct snd_soc_codec *codec)
 {
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
        snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL");
        snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR");
        snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL");
        snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR");
        snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT");
        snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT");
-       if (hs_switch) {
+       if (mc_drv_ctx->hs_switch) {
                snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
                snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
        } else {
@@ -148,7 +153,10 @@ static void lo_enable_out_pins(struct snd_soc_codec *codec)
 static int lo_get_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       ucontrol->value.integer.value[0] = lo_dac;
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
+       ucontrol->value.integer.value[0] = mc_drv_ctx->lo_dac;
        return 0;
 }
 
@@ -156,8 +164,10 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       if (ucontrol->value.integer.value[0] == lo_dac)
+       if (ucontrol->value.integer.value[0] == mc_drv_ctx->lo_dac)
                return 0;
 
        /* we dont want to work with last state of lineout so just enable all
@@ -196,44 +206,103 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
        mutex_lock(&codec->mutex);
        snd_soc_dapm_sync(&codec->dapm);
        mutex_unlock(&codec->mutex);
-       lo_dac = ucontrol->value.integer.value[0];
+       mc_drv_ctx->lo_dac = ucontrol->value.integer.value[0];
        return 0;
 }
+
 static int sn95031_get_pcm1_mode(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       int mode;
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       mode = snd_soc_read(codec, SN95031_PCM1C3) >> 7;
-       pr_debug("mode: %d\n", mode);
-       ucontrol->value.integer.value[0] = mode;
+       pr_debug("PCM1 master mode: %d\n", mc_drv_ctx->pcm1_master_mode);
+       ucontrol->value.integer.value[0] = mc_drv_ctx->pcm1_master_mode;
        return 0;
 }
+
 static int sn95031_set_pcm1_mode(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       u8 mode = ucontrol->value.integer.value[0];
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       if (mode) {
-               pr_debug("can we set the master mode settings\n");
-               snd_soc_update_bits(codec, SN95031_PCM1C3,
-                               BIT(1)|BIT(2)|BIT(3)|BIT(7), BIT(7)|BIT(1));
-               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1),
-                                                               BIT(0)|BIT(1));
-               snd_soc_update_bits(codec, SN95031_PCM1C2,
-                                               BIT(0)|BIT(1)|BIT(2), 0);
-       } else {
-               pr_debug("setting the slave mode settings\n");
-               snd_soc_update_bits(codec, SN95031_PCM1C3, BIT(7), 0);
-               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1), 0);
-               snd_soc_update_bits(codec, SN95031_PCM1C2, BIT(2), BIT(2));
+       mc_drv_ctx->pcm1_master_mode = ucontrol->value.integer.value[0];
+       return 0;
+}
 
-       }
+static int mfld_vibra_enable_clk(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       int clk_id = 0;
+
+       if (!strcmp(w->name, "Vibra1Clock"))
+               clk_id = CLK0_VIBRA1;
+       else if (!strcmp(w->name, "Vibra2Clock"))
+               clk_id = CLK0_VIBRA2;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               intel_scu_ipc_set_osc_clk0(true, clk_id);
+       else if (SND_SOC_DAPM_EVENT_OFF(event))
+               intel_scu_ipc_set_osc_clk0(false, clk_id);
        return 0;
 }
 
+/* Callback to set volume for *VOLCTRL regs. Needs to be implemented separately
+ * since clock and VAUDA need to be on before value can be written to the regs
+ */
+static int sn95031_set_vol_2r(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
+       int err;
+       unsigned int val, val2, val_mask;
+       int sst_pll_mode_saved;
+
+       val_mask = mask << shift;
+       val = (ucontrol->value.integer.value[0] & mask);
+       val2 = (ucontrol->value.integer.value[1] & mask);
+
+       if (invert) {
+               val = max - val;
+               val2 = max - val2;
+       }
+
+       val = val << shift;
+       val2 = val2 << shift;
+
+       pr_debug("enabling PLL and VAUDA to change volume\n");
+       mutex_lock(&codec->mutex);
+       sst_pll_mode_saved = intel_scu_ipc_set_osc_clk0(true, CLK0_QUERY);
+       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       snd_soc_dapm_sync(&codec->dapm);
+
+       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       if (err < 0)
+               goto restore_state;
+
+       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+restore_state:
+       snd_soc_dapm_disable_pin(&codec->dapm, "VirtBias");
+       if (!(sst_pll_mode_saved & CLK0_MSIC))
+               intel_scu_ipc_set_osc_clk0(false, CLK0_MSIC);
+       mutex_unlock(&codec->mutex);
+       return err;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -6200, 100, 0);
+
 static const struct snd_kcontrol_new mfld_snd_controls[] = {
        SOC_ENUM_EXT("Playback Switch", headset_enum,
                        headset_get_switch, headset_set_switch),
@@ -241,17 +310,38 @@ static const struct snd_kcontrol_new mfld_snd_controls[] = {
                        lo_get_switch, lo_set_switch),
        SOC_ENUM_EXT("PCM1 Mode", SN95031_pcm1_mode_config_enum,
                        sn95031_get_pcm1_mode, sn95031_set_pcm1_mode),
+       /* Add digital volume and mute controls for Headphone/Headset*/
+       SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", SN95031_HSLVOLCTRL,
+                               SN95031_HSRVOLCTRL, 0, 71, 1,
+                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
+                               out_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Speaker Playback Volume", SN95031_IHFLVOLCTRL,
+                               SN95031_IHFRVOLCTRL, 0, 71, 1,
+                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
+                               out_tlv),
 };
 
 static const struct snd_soc_dapm_widget mfld_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_MIC("Mic", NULL),
+       /* Dummy widget to trigger VAUDA on/off */
+       SND_SOC_DAPM_MICBIAS("VirtBias", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("Vibra1Clock", SND_SOC_NOPM, 0, 0,
+                       mfld_vibra_enable_clk,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("Vibra2Clock", SND_SOC_NOPM, 0, 0,
+                       mfld_vibra_enable_clk,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route mfld_map[] = {
+       { "HPOUTL", NULL, "Headset Rail"},
+       { "HPOUTR", NULL, "Headset Rail"},
        {"Headphones", NULL, "HPOUTR"},
        {"Headphones", NULL, "HPOUTL"},
        {"AMIC1", NULL, "Mic"},
+       {"VIB1SPI", NULL, "Vibra1Clock"},
+       {"VIB2SPI", NULL, "Vibra2Clock"},
 };
 
 static void mfld_jack_check(unsigned int intr_status)
@@ -277,6 +367,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
 {
        struct snd_soc_codec *codec = runtime->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
        int ret_val;
 
        /* Add jack sense widgets */
@@ -291,16 +383,13 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
                pr_err("soc_add_controls failed %d", ret_val);
                return ret_val;
        }
-       /* always connected */
-       snd_soc_dapm_enable_pin(dapm, "Headphones");
-       snd_soc_dapm_enable_pin(dapm, "Mic");
        /* default is earpiece pin, userspace sets it explcitly */
        snd_soc_dapm_disable_pin(dapm, "Headphones");
        /* default is lineout NC, userspace sets it explcitly */
        snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
        snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
-       lo_dac = 3;
-       hs_switch = 0;
+       mc_drv_ctx->lo_dac = 3;
+       mc_drv_ctx->hs_switch = 0;
        /* we dont use linein in this so set to NC */
        snd_soc_dapm_disable_pin(dapm, "LINEINL");
        snd_soc_dapm_disable_pin(dapm, "LINEINR");
@@ -361,6 +450,126 @@ static int mfld_speaker_init(struct snd_soc_pcm_runtime *runtime)
 }
 #endif
 
+static int mfld_media_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       int ret;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       pr_debug("%s\n", __func__);
+       /* Force the data width to 24 bit in MSIC since post processing
+       algorithms in DSP enabled with 24 bit precision */
+       ret = snd_soc_codec_set_params(codec, SNDRV_PCM_FORMAT_S24_LE);
+       if (ret < 0) {
+               pr_debug("codec_set_params returned error %d\n", ret);
+               return ret;
+       }
+       snd_soc_codec_set_pll(codec, 0, SN95031_PLLIN, 1, 1);
+
+       /* VAUD needs to be on before configuring PLL */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       mutex_lock(&codec->mutex);
+       snd_soc_dapm_sync(&codec->dapm);
+       mutex_unlock(&codec->mutex);
+       usleep_range(5000, 6000);
+       sn95031_configure_pll(codec, ENABLE_PLL);
+
+       /* enable PCM2 */
+       snd_soc_dai_set_tristate(rtd->codec_dai, 0);
+       return 0;
+}
+
+static int mfld_voice_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_codec *codec = rtd->codec;
+       struct snd_soc_card *soc_card = rtd->card;
+       struct mfld_mc_private *mc_drv_ctx = snd_soc_card_get_drvdata(soc_card);
+       pr_debug("%s\n", __func__);
+
+       if (mc_drv_ctx->pcm1_master_mode) { /* VOIP call */
+               snd_soc_codec_set_pll(codec, 0, SN95031_PLLIN, 1, 1);
+               snd_soc_dai_set_fmt(rtd->codec_dai, SND_SOC_DAIFMT_CBM_CFM
+                                               | SND_SOC_DAIFMT_DSP_A);
+               /* Sets the PCM1 clock rate */
+               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1),
+                                                               BIT(0)|BIT(1));
+       } else { /* CSV call */
+               snd_soc_codec_set_pll(codec, 0, SN95031_PCM1BCLK, 1, 1);
+               snd_soc_dai_set_fmt(rtd->codec_dai, SND_SOC_DAIFMT_CBS_CFS
+                                               | SND_SOC_DAIFMT_I2S);
+               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1), 0);
+       }
+
+       /* VAUD needs to be on before configuring PLL */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       mutex_lock(&codec->mutex);
+       snd_soc_dapm_sync(&codec->dapm);
+       mutex_unlock(&codec->mutex);
+       usleep_range(5000, 6000);
+       sn95031_configure_pll(codec, ENABLE_PLL);
+       return 0;
+}
+
+static unsigned int rates_44100[] = {
+       44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_44100 = {
+       .count  = ARRAY_SIZE(rates_44100),
+       .list   = rates_44100,
+};
+
+static int mfld_media_startup(struct snd_pcm_substream *substream)
+{
+       pr_debug("%s - applying rate constraint\n", __func__);
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE,
+                                  &constraints_44100);
+       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
+       return 0;
+}
+
+static void mfld_media_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       pr_debug("%s\n", __func__);
+
+       snd_soc_dapm_disable_pin(&rtd->codec->dapm, "VirtBias");
+       /* switch off PCM2 port */
+       if (!rtd->codec->active)
+               snd_soc_dai_set_tristate(codec_dai, 1);
+}
+
+static int mfld_voice_startup(struct snd_pcm_substream *substream)
+{
+       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
+       return 0;
+}
+
+static void mfld_voice_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       pr_debug("%s\n", __func__);
+
+       snd_soc_dapm_disable_pin(&rtd->codec->dapm, "VirtBias");
+}
+
+static struct snd_soc_ops mfld_media_ops = {
+       .startup = mfld_media_startup,
+       .shutdown = mfld_media_shutdown,
+       .hw_params = mfld_media_hw_params,
+};
+
+static struct snd_soc_ops mfld_voice_ops = {
+       .startup = mfld_voice_startup,
+       .shutdown = mfld_voice_shutdown,
+       .hw_params = mfld_voice_hw_params,
+};
+
 static struct snd_soc_dai_link mfld_msic_dailink[] = {
        {
                .name = "Medfield Headset",
@@ -371,6 +580,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .platform_name = "sst-platform",
                .init = mfld_init,
                .ignore_suspend = 1,
+               .ops = &mfld_media_ops,
        },
        {
                .name = "Medfield Speaker",
@@ -385,6 +595,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .init = NULL,
 #endif
                .ignore_suspend = 1,
+               .ops = &mfld_media_ops,
        },
 /*
  *     This configurtaion doesnt need Vibra as PCM device
@@ -421,6 +632,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .init = NULL,
                .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
+               .ops = &mfld_voice_ops,
        },
 };
 
@@ -452,6 +664,19 @@ static int snd_mfld_mc_poweroff(struct device *dev)
 #define snd_mfld_mc_poweroff NULL
 #endif
 
+static int mfld_card_stream_event(struct snd_soc_dapm_context *dapm, int event)
+{
+       struct snd_soc_codec *codec = dapm->codec;
+       pr_debug("machine stream event: %d\n", event);
+       if (event == SND_SOC_DAPM_STREAM_STOP) {
+               if (!codec->active) {
+                       sn95031_configure_pll(codec, DISABLE_PLL);
+                       return intel_scu_ipc_set_osc_clk0(false, CLK0_MSIC);
+               }
+       }
+       return 0;
+}
+
 /* SoC card */
 static struct snd_soc_card snd_soc_card_mfld = {
        .name = "medfield_audio",
@@ -588,14 +813,14 @@ static int __devinit snd_mfld_mc_probe(struct ipc_device *ipcdev)
        }
        /* register the soc card */
        snd_soc_card_mfld.dev = &ipcdev->dev;
-       snd_soc_initialize_card_lists(&snd_soc_card_mfld);
+       snd_soc_card_mfld.dapm.stream_event = mfld_card_stream_event;
+       snd_soc_card_set_drvdata(&snd_soc_card_mfld, mc_drv_ctx);
        ret_val = snd_soc_register_card(&snd_soc_card_mfld);
        if (ret_val) {
                pr_debug("snd_soc_register_card failed %d\n", ret_val);
                goto freeirq;
        }
        ipc_set_drvdata(ipcdev, &snd_soc_card_mfld);
-       snd_soc_card_set_drvdata(&snd_soc_card_mfld, mc_drv_ctx);
        pr_debug("successfully exited probe\n");
        return ret_val;
 
@@ -643,10 +868,10 @@ static struct ipc_driver snd_mfld_mc_driver = {
 
 static int __init snd_mfld_driver_init(void)
 {
-       pr_debug("snd_mfld_driver_init called\n");
+       pr_info("snd_mfld_driver_init called\n");
        return ipc_driver_register(&snd_mfld_mc_driver);
 }
-module_init_async(snd_mfld_driver_init);
+late_initcall(snd_mfld_driver_init);
 
 static void __exit snd_mfld_driver_exit(void)
 {
index a52e102..e24d445 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/async.h>
 #include <linux/gpio.h>
 #include <linux/ipc_device.h>
 #include <asm/intel-mid.h>
+#include <asm/intel_scu_ipc.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "../codecs/sn95031.h"
 
-#define MID_MONO 1
-#define MID_STEREO 2
-#define MID_MAX_CAP 5
 #define MFLD_JACK_INSERT 0x04
 #define HEADSET_DET_PIN 77
 
@@ -58,15 +58,13 @@ enum soc_mic_bias_zones {
        MFLD_MV_UNDEFINED,
 };
 
-static unsigned int    hs_switch;
-
 struct mfld_mc_private {
-       struct ipc_device *socdev;
        void __iomem *int_base;
-       struct snd_soc_codec *codec;
        u8 jack_interrupt_status;
        u8 oc_interrupt_status;
        spinlock_t lock; /* lock for interrupt status and jack debounce */
+       int pcm1_master_mode;
+       unsigned int hs_switch;
 #ifdef CONFIG_HAS_WAKELOCK
        struct wake_lock wake_lock;
 #endif
@@ -95,7 +93,10 @@ static const struct soc_enum SN95031_pcm1_mode_config_enum =
 static int headset_get_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       ucontrol->value.integer.value[0] = hs_switch;
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
+       ucontrol->value.integer.value[0] = mc_drv_ctx->hs_switch;
        return 0;
 }
 
@@ -103,8 +104,10 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       if (ucontrol->value.integer.value[0] == hs_switch)
+       if (ucontrol->value.integer.value[0] == mc_drv_ctx->hs_switch)
                return 0;
 
        if (ucontrol->value.integer.value[0]) {
@@ -116,8 +119,10 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
                snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
                snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
        }
+       mutex_lock(&codec->mutex);
        snd_soc_dapm_sync(&codec->dapm);
-       hs_switch = ucontrol->value.integer.value[0];
+       mutex_unlock(&codec->mutex);
+       mc_drv_ctx->hs_switch = ucontrol->value.integer.value[0];
 
        return 0;
 }
@@ -125,56 +130,136 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
 static int sn95031_get_pcm1_mode(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       int mode;
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       mode = snd_soc_read(codec, SN95031_PCM1C3) >> 7;
-       pr_debug("mode: %d\n", mode);
-       ucontrol->value.integer.value[0] = mode;
+       pr_debug("PCM1 master mode: %d\n", mc_drv_ctx->pcm1_master_mode);
+       ucontrol->value.integer.value[0] = mc_drv_ctx->pcm1_master_mode;
        return 0;
 }
+
 static int sn95031_set_pcm1_mode(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       u8 mode = ucontrol->value.integer.value[0];
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
 
-       if (mode) {
-               pr_debug("can we set the master mode settings\n");
-               snd_soc_update_bits(codec, SN95031_PCM1C3,
-                               BIT(1)|BIT(2)|BIT(3)|BIT(7), BIT(7)|BIT(1));
-               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1),
-                                                               BIT(0)|BIT(1));
-               snd_soc_update_bits(codec, SN95031_PCM1C2,
-                                               BIT(0)|BIT(1)|BIT(2), 0);
-       } else {
-               pr_debug("setting the slave mode settings\n");
-               snd_soc_update_bits(codec, SN95031_PCM1C3, BIT(7), 0);
-               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1), 0);
-               snd_soc_update_bits(codec, SN95031_PCM1C2, BIT(2), BIT(2));
+       mc_drv_ctx->pcm1_master_mode = ucontrol->value.integer.value[0];
+       return 0;
+}
 
-       }
+static int mfld_vibra_enable_clk(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       int clk_id = 0;
+
+       if (!strcmp(w->name, "Vibra1Clock"))
+               clk_id = CLK0_VIBRA1;
+       else if (!strcmp(w->name, "Vibra2Clock"))
+               clk_id = CLK0_VIBRA2;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               intel_scu_ipc_set_osc_clk0(true, clk_id);
+       else if (SND_SOC_DAPM_EVENT_OFF(event))
+               intel_scu_ipc_set_osc_clk0(false, clk_id);
        return 0;
 }
 
+/* Callback to set volume for *VOLCTRL regs. Needs to be implemented separately
+ * since clock and VAUDA need to be on before value can be written to the regs
+ */
+static int sn95031_set_vol_2r(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
+       int err;
+       unsigned int val, val2, val_mask;
+       int sst_pll_mode_saved;
+
+       val_mask = mask << shift;
+       val = (ucontrol->value.integer.value[0] & mask);
+       val2 = (ucontrol->value.integer.value[1] & mask);
+
+       if (invert) {
+               val = max - val;
+               val2 = max - val2;
+       }
+
+       val = val << shift;
+       val2 = val2 << shift;
+
+       pr_debug("enabling PLL and VAUDA to change volume\n");
+       mutex_lock(&codec->mutex);
+       sst_pll_mode_saved = intel_scu_ipc_set_osc_clk0(true, CLK0_QUERY);
+       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       snd_soc_dapm_sync(&codec->dapm);
+
+       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       if (err < 0)
+               goto restore_state;
+
+       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+restore_state:
+       snd_soc_dapm_disable_pin(&codec->dapm, "VirtBias");
+       if (!(sst_pll_mode_saved & CLK0_MSIC))
+               intel_scu_ipc_set_osc_clk0(false, CLK0_MSIC);
+       mutex_unlock(&codec->mutex);
+       return err;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -6200, 100, 0);
+
 static const struct snd_kcontrol_new mfld_snd_controls[] = {
        SOC_ENUM_EXT("Playback Switch", headset_enum,
                        headset_get_switch, headset_set_switch),
        SOC_ENUM_EXT("PCM1 Mode", SN95031_pcm1_mode_config_enum,
                        sn95031_get_pcm1_mode, sn95031_set_pcm1_mode),
+       /* Add digital volume and mute controls for Headphone/Headset*/
+       SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", SN95031_HSLVOLCTRL,
+                               SN95031_HSRVOLCTRL, 0, 71, 1,
+                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
+                               out_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Speaker Playback Volume", SN95031_IHFLVOLCTRL,
+                               SN95031_IHFRVOLCTRL, 0, 71, 1,
+                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
+                               out_tlv),
 };
 
 static const struct snd_soc_dapm_widget mfld_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_MIC("BuiltinMic", NULL),
        SND_SOC_DAPM_MIC("HeadsetMic", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+       /* Dummy widget to trigger VAUDA on/off */
+       SND_SOC_DAPM_MICBIAS("VirtBias", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("Vibra1Clock", SND_SOC_NOPM, 0, 0,
+                       mfld_vibra_enable_clk,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("Vibra2Clock", SND_SOC_NOPM, 0, 0,
+                       mfld_vibra_enable_clk,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route mfld_map[] = {
+       { "HPOUTL", NULL, "Headset Rail"},
+       { "HPOUTR", NULL, "Headset Rail"},
        {"Headphones", NULL, "HPOUTR"},
        {"Headphones", NULL, "HPOUTL"},
        {"AMIC2", NULL, "BuiltinMic"},
        {"AMIC1", NULL, "HeadsetMic"},
+       {"VIB1SPI", NULL, "Vibra1Clock"},
+       {"VIB2SPI", NULL, "Vibra2Clock"},
 };
 
 static void mfld_jack_check(unsigned int intr_status)
@@ -200,6 +285,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
 {
        struct snd_soc_codec *codec = runtime->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct mfld_mc_private *mc_drv_ctx =
+                       snd_soc_card_get_drvdata(codec->card);
        int ret_val;
 
        /* Add jack sense widgets */
@@ -208,7 +295,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        /* Set up the map */
        snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
 
-
        ret_val = snd_soc_add_controls(codec, mfld_snd_controls,
                                ARRAY_SIZE(mfld_snd_controls));
        if (ret_val) {
@@ -220,7 +306,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        /* default is lineout NC, userspace sets it explcitly */
        snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
        snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
-       hs_switch = 0;
+       mc_drv_ctx->hs_switch = 0;
        /* we dont use linein in this so set to NC */
        snd_soc_dapm_disable_pin(dapm, "LINEINL");
        snd_soc_dapm_disable_pin(dapm, "LINEINR");
@@ -241,7 +327,9 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        snd_soc_dapm_ignore_suspend(dapm, "Headphones");
        snd_soc_dapm_ignore_suspend(dapm, "BuiltinMic");
        snd_soc_dapm_ignore_suspend(dapm, "HeadsetMic");
+       mutex_lock(&codec->mutex);
        snd_soc_dapm_sync(dapm);
+       mutex_unlock(&codec->mutex);
        /* Headset and button jack detection */
        ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
@@ -274,6 +362,126 @@ static int mfld_speaker_init(struct snd_soc_pcm_runtime *runtime)
        return cpu_dai->driver->ops->set_tdm_slot(cpu_dai, 0, 0, 1, 0);
 }
 
+static int mfld_media_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       int ret;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       pr_debug("%s\n", __func__);
+       /* Force the data width to 24 bit in MSIC since post processing
+       algorithms in DSP enabled with 24 bit precision */
+       ret = snd_soc_codec_set_params(codec, SNDRV_PCM_FORMAT_S24_LE);
+       if (ret < 0) {
+               pr_debug("codec_set_params returned error %d\n", ret);
+               return ret;
+       }
+       snd_soc_codec_set_pll(codec, 0, SN95031_PLLIN, 1, 1);
+
+       /* VAUD needs to be on before configuring PLL */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       mutex_lock(&codec->mutex);
+       snd_soc_dapm_sync(&codec->dapm);
+       mutex_unlock(&codec->mutex);
+       usleep_range(5000, 6000);
+       sn95031_configure_pll(codec, ENABLE_PLL);
+
+       /* enable PCM2 */
+       snd_soc_dai_set_tristate(rtd->codec_dai, 0);
+       return 0;
+}
+
+static int mfld_voice_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_codec *codec = rtd->codec;
+       struct snd_soc_card *soc_card = rtd->card;
+       struct mfld_mc_private *mc_drv_ctx = snd_soc_card_get_drvdata(soc_card);
+       pr_debug("%s\n", __func__);
+
+       if (mc_drv_ctx->pcm1_master_mode) { /* VOIP call */
+               snd_soc_codec_set_pll(codec, 0, SN95031_PLLIN, 1, 1);
+               snd_soc_dai_set_fmt(rtd->codec_dai, SND_SOC_DAIFMT_CBM_CFM
+                                               | SND_SOC_DAIFMT_DSP_A);
+               /* Sets the PCM1 clock rate */
+               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1),
+                                                               BIT(0)|BIT(1));
+       } else { /* CSV call */
+               snd_soc_codec_set_pll(codec, 0, SN95031_PCM1BCLK, 1, 1);
+               snd_soc_dai_set_fmt(rtd->codec_dai, SND_SOC_DAIFMT_CBS_CFS
+                                               | SND_SOC_DAIFMT_I2S);
+               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1), 0);
+       }
+
+       /* VAUD needs to be on before configuring PLL */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       mutex_lock(&codec->mutex);
+       snd_soc_dapm_sync(&codec->dapm);
+       mutex_unlock(&codec->mutex);
+       usleep_range(5000, 6000);
+       sn95031_configure_pll(codec, ENABLE_PLL);
+       return 0;
+}
+
+static unsigned int rates_44100[] = {
+       44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_44100 = {
+       .count  = ARRAY_SIZE(rates_44100),
+       .list   = rates_44100,
+};
+
+static int mfld_media_startup(struct snd_pcm_substream *substream)
+{
+       pr_debug("%s - applying rate constraint\n", __func__);
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE,
+                                  &constraints_44100);
+       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
+       return 0;
+}
+
+static void mfld_media_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       pr_debug("%s\n", __func__);
+
+       snd_soc_dapm_disable_pin(&rtd->codec->dapm, "VirtBias");
+       /* switch off PCM2 port */
+       if (!rtd->codec->active)
+               snd_soc_dai_set_tristate(codec_dai, 1);
+}
+
+static int mfld_voice_startup(struct snd_pcm_substream *substream)
+{
+       intel_scu_ipc_set_osc_clk0(true, CLK0_MSIC);
+       return 0;
+}
+
+static void mfld_voice_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       pr_debug("%s\n", __func__);
+
+       snd_soc_dapm_disable_pin(&rtd->codec->dapm, "VirtBias");
+}
+
+static struct snd_soc_ops mfld_media_ops = {
+       .startup = mfld_media_startup,
+       .shutdown = mfld_media_shutdown,
+       .hw_params = mfld_media_hw_params,
+};
+
+static struct snd_soc_ops mfld_voice_ops = {
+       .startup = mfld_voice_startup,
+       .shutdown = mfld_voice_shutdown,
+       .hw_params = mfld_voice_hw_params,
+};
+
 static struct snd_soc_dai_link mfld_msic_dailink[] = {
        {
                .name = "Medfield Headset",
@@ -284,6 +492,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .platform_name = "sst-platform",
                .init = mfld_init,
                .ignore_suspend = 1,
+               .ops = &mfld_media_ops,
        },
        {
                .name = "Medfield Speaker",
@@ -294,6 +503,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .platform_name = "sst-platform",
                .init = mfld_speaker_init,
                .ignore_suspend = 1,
+               .ops = &mfld_media_ops,
        },
        {
                .name = "Medfield Voice",
@@ -305,6 +515,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .init = NULL,
                .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
+               .ops = &mfld_voice_ops,
        },
 };
 
@@ -336,6 +547,19 @@ static int snd_mfld_mc_poweroff(struct device *dev)
 #define snd_mfld_mc_poweroff NULL
 #endif
 
+static int mfld_card_stream_event(struct snd_soc_dapm_context *dapm, int event)
+{
+       struct snd_soc_codec *codec = dapm->codec;
+       pr_debug("machine stream event: %d\n", event);
+       if (event == SND_SOC_DAPM_STREAM_STOP) {
+               if (!codec->active) {
+                       sn95031_configure_pll(codec, DISABLE_PLL);
+                       return intel_scu_ipc_set_osc_clk0(false, CLK0_MSIC);
+               }
+       }
+       return 0;
+}
+
 /* SoC card */
 static struct snd_soc_card snd_soc_card_mfld = {
        .name = "medfield_audio",
@@ -472,14 +696,14 @@ static int __devinit snd_mfld_mc_probe(struct ipc_device *ipcdev)
        }
        /* register the soc card */
        snd_soc_card_mfld.dev = &ipcdev->dev;
-       snd_soc_initialize_card_lists(&snd_soc_card_mfld);
+       snd_soc_card_mfld.dapm.stream_event = mfld_card_stream_event;
+       snd_soc_card_set_drvdata(&snd_soc_card_mfld, mc_drv_ctx);
        ret_val = snd_soc_register_card(&snd_soc_card_mfld);
        if (ret_val) {
                pr_debug("snd_soc_register_card failed %d\n", ret_val);
                goto freeirq;
        }
        ipc_set_drvdata(ipcdev, &snd_soc_card_mfld);
-       snd_soc_card_set_drvdata(&snd_soc_card_mfld, mc_drv_ctx);
        pr_debug("successfully exited probe\n");
        return ret_val;
 
@@ -527,10 +751,10 @@ static struct ipc_driver snd_mfld_mc_driver = {
 
 static int __init snd_mfld_driver_init(void)
 {
-       pr_debug("snd_mfld_driver_init called\n");
+       pr_info("snd_mfld_driver_init called\n");
        return ipc_driver_register(&snd_mfld_mc_driver);
 }
-module_init_async(snd_mfld_driver_init);
+late_initcall(snd_mfld_driver_init);
 
 static void __exit snd_mfld_driver_exit(void)
 {
index e38277a..3f8313d 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/async.h>
 #include <linux/lnw_gpio.h>
+#include <linux/delay.h>
 #include <asm/intel-mid.h>
-#include <asm/intel_scu_ipc.h>
-#include <sound/intel_sst.h>
 #include <sound/intel_sst_ioctl.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
-#include <linux/delay.h>
 
 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
@@ -134,7 +133,7 @@ static irqreturn_t intel_sst_interrupt(int irq, void *context)
                                stream->period_elapsed(stream->pcm_substream);
                        return IRQ_HANDLED;
                }
-               pr_err("recieved IPC %x\n", header.full);
+               pr_debug("received IPC %x\n", header.full);
                if (header.part.large)
                        size = header.part.data;
                if (header.part.msg_id & REPLY_MSG) {
@@ -223,7 +222,6 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        INIT_WORK(&sst_drv_ctx->ipc_post_msg.wq, sst_post_message);
        INIT_WORK(&sst_drv_ctx->ipc_process_msg.wq, sst_process_message);
        INIT_WORK(&sst_drv_ctx->ipc_process_reply.wq, sst_process_reply);
-       INIT_WORK(&sst_drv_ctx->mad_ops.wq, sst_process_mad_ops);
        init_waitqueue_head(&sst_drv_ctx->wait_queue);
 
        sst_drv_ctx->mad_wq = create_singlethread_workqueue("sst_mad_wq");
@@ -394,7 +392,8 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        pci_set_drvdata(pci, sst_drv_ctx);
        pm_runtime_allow(&pci->dev);
        pm_runtime_put_noidle(&pci->dev);
-       pr_debug("...successfully done!!!\n");
+       register_sst(&pci->dev);
+       pr_info("%s successfully done!\n", __func__);
        return ret;
 
 do_free_misc:
@@ -442,6 +441,7 @@ static void __devexit intel_sst_remove(struct pci_dev *pci)
 {
        pm_runtime_get_noresume(&pci->dev);
        pm_runtime_forbid(&pci->dev);
+       unregister_sst(&pci->dev);
        pci_dev_put(sst_drv_ctx->pci);
        sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
        misc_deregister(&lpe_ctrl);
@@ -518,46 +518,6 @@ static void sst_save_dsp_context(void)
        return;
 }
 
-int intel_sst_set_pll(unsigned int enable, enum intel_sst_pll_mode mode)
-{
-       int ret = 0;
-       int clock_enable = 0;
-       static const unsigned int clock_khz = 19200;
-
-       pr_debug("set_pll, Enable %x, Mode %x\n", enable, mode);
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       if (enable == true) {
-               /*enable clock */
-               clock_enable = 1;
-               if (sst_drv_ctx->pll_mode) {
-                       /* clock is on, so just update and return */
-                       sst_drv_ctx->pll_mode |= mode;
-                       goto out;
-               }
-               sst_drv_ctx->pll_mode |= mode;
-               pr_debug("set_pll, enabling pll %x\n", sst_drv_ctx->pll_mode);
-       } else {
-               /* for turning off only, we check device state and turn off only
-                * when device is supspended
-                */
-               sst_drv_ctx->pll_mode &= ~mode;
-               pr_debug("set_pll, disabling pll %x\n", sst_drv_ctx->pll_mode);
-               if (sst_drv_ctx->pll_mode)
-                       goto out;
-               clock_enable = 0; /*disbale clock */
-       }
-       /* send ipc command to configure the PNW clock to MSIC PLLIN */
-       pr_debug("configuring clock now\n");
-       ret = intel_scu_ipc_osc_clk(OSC_CLK_AUDIO, clock_enable ?
-                                                               clock_khz : 0);
-       if (ret)
-               pr_err("ipc clk disable command failed: %d\n", ret);
-out:
-       mutex_unlock(&sst_drv_ctx->sst_lock);
-       return ret;
-}
-EXPORT_SYMBOL(intel_sst_set_pll);
-
 void intel_sst_pwm_suspend(unsigned int pwm_suspend)
 {
 
@@ -570,17 +530,6 @@ void intel_sst_pwm_suspend(unsigned int pwm_suspend)
        }
 }
 EXPORT_SYMBOL(intel_sst_pwm_suspend);
-/*
- * The runtime_suspend/resume is pretty much similar to the legacy
- * suspend/resume with the noted exception below: The PCI core takes care of
- * taking the system through D3hot and restoring it back to D0 and so there is
- * no need to duplicate that here.
- */
-int intel_sst_get_pll(void)
-{
-       return sst_drv_ctx->pll_mode;
-}
-EXPORT_SYMBOL(intel_sst_get_pll);
 
 int vibra_pwm_configure(unsigned int enable)
 {
@@ -617,6 +566,12 @@ int vibra_pwm_configure(unsigned int enable)
        return 0;
 }
 
+/*
+ * The runtime_suspend/resume is pretty much similar to the legacy
+ * suspend/resume with the noted exception below: The PCI core takes care of
+ * taking the system through D3hot and restoring it back to D0 and so there is
+ * no need to duplicate that here.
+ */
 static int intel_sst_runtime_suspend(struct device *dev)
 {
        union config_status_reg csr;
@@ -638,7 +593,6 @@ static int intel_sst_runtime_suspend(struct device *dev)
        sst_drv_ctx->sst_state = SST_SUSPENDED;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
        mutex_unlock(&sst_drv_ctx->sst_lock);
-       intel_sst_set_pll(false, SST_PLL_AUDIO);
        if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID)
                vibra_pwm_configure(false);
        return 0;
@@ -677,7 +631,6 @@ static int intel_sst_runtime_resume(struct device *dev)
                vibra_pwm_configure(true);
        }
 
-       intel_sst_set_pll(true, SST_PLL_AUDIO);
        sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
        return 0;
 }
@@ -733,7 +686,7 @@ static int __init intel_sst_init(void)
 {
        /* Init all variables, data structure etc....*/
        int ret = 0;
-       pr_debug("INFO: ******** SST DRIVER loading.. Ver: %s\n",
+       pr_info("INFO: ******** SST DRIVER loading.. Ver: %s\n",
                                       SST_DRIVER_VERSION);
 
        mutex_init(&drv_ctx_lock);
index ad6c790..55fc412 100644 (file)
@@ -41,8 +41,8 @@
 #include <linux/rar_register.h>
 #include "../../../drivers/staging/memrar/memrar.h"
 #endif
-#include <sound/intel_sst.h>
 #include <sound/intel_sst_ioctl.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -1055,7 +1055,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
 
        case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
-               struct snd_sst_params str_param;
+               struct sst_stream_params str_param;
 
                pr_debug("IOCTL_SET_PARAMS received!\n");
                if (minor != STREAM_MODULE) {
@@ -1097,11 +1097,9 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        /* Block the call for reply */
                        if (!retval) {
                                int sfreq = 0, word_size = 0, num_channel = 0;
-                               sfreq = str_param.sparams.uc.pcm_params.sfreq;
-                               word_size =
-                                  str_param.sparams.uc.pcm_params.pcm_wd_sz;
-                               num_channel =
-                                  str_param.sparams.uc.pcm_params.num_chan;
+                               sfreq = str_param.sparams.sfreq;
+                               word_size = str_param.sparams.pcm_wd_sz;
+                               num_channel = str_param.sparams.num_chan;
                        }
                }
                break;
index 37a20b2..94d1aa4 100644 (file)
@@ -259,7 +259,7 @@ struct stream_info {
        u32                     curr_bytes;
        u32                     cumm_bytes;
        u32                     src;
-       enum snd_sst_audio_device_type device;
+       enum sst_audio_device_type device;
        u8                      pcm_slot;
 };
 
@@ -320,13 +320,6 @@ struct sst_ipc_msg_wq {
        struct work_struct      wq;
 };
 
-struct mad_ops_wq {
-       int stream_id;
-       enum sst_controls control_op;
-       struct work_struct      wq;
-
-};
-
 #define SST_MMAP_PAGES (640*1024 / PAGE_SIZE)
 #define SST_MMAP_STEP  (40*1024 / PAGE_SIZE)
 
@@ -409,7 +402,6 @@ struct intel_sst_drv {
        struct sst_ipc_msg_wq   ipc_process_msg;
        struct sst_ipc_msg_wq   ipc_process_reply;
        struct sst_ipc_msg_wq   ipc_post_msg;
-       struct mad_ops_wq       mad_ops;
        wait_queue_head_t       wait_queue;
        struct workqueue_struct *mad_wq;
        struct workqueue_struct *post_msg_wq;
@@ -422,7 +414,7 @@ struct intel_sst_drv {
                                vol_info_blk, mute_info_blk, hs_info_blk,
                                dma_info_blk;
        struct mutex            list_lock;/* mutex for IPC list locking */
-       spinlock_t      list_spin_lock; /* mutex for IPC list locking */
+       spinlock_t              list_spin_lock; /* mutex for IPC list locking */
        struct snd_pmic_ops     *scard_ops;
        struct pci_dev          *pci;
        void                    *mmap_mem;
@@ -438,21 +430,20 @@ struct intel_sst_drv {
        unsigned int            lpe_stalled; /* LPE is stalled or not */
        unsigned int            pmic_port_instance; /*pmic port instance*/
        unsigned int            lpaudio_start;
-               /* 1 - LPA stream(MP3 pb) in progress*/
+       /* 1 - LPA stream(MP3 pb) in progress*/
        unsigned int            audio_start;
        dev_t                   devt_d, devt_c;
        unsigned int            max_streams;
        unsigned int            *fw_cntx;
        unsigned int            fw_cntx_size;
        unsigned int            csr_value;
-       unsigned int            pll_mode;
-       const struct firmware *fw;
+       const struct firmware   *fw;
 
        struct sst_dma          dma;
        void                    *fw_in_mem;
        struct sst_runtime_param runtime_param;
-       unsigned int            device_input_mixer;
-       struct mutex         mixer_ctrl_lock;
+       unsigned int            device_input_mixer;
+       struct mutex            mixer_ctrl_lock;
        struct dma_async_tx_descriptor *desc;
        struct sst_sg_list fw_sg_list, library_list;
 };
@@ -486,15 +477,15 @@ int sst_start_stream(int streamID);
 int sst_play_frame(int streamID);
 int sst_pcm_play_frame(int str_id, struct sst_stream_bufs *sst_buf);
 int sst_capture_frame(int streamID);
-int sst_set_stream_param(int streamID, struct snd_sst_params *str_param);
+int sst_set_stream_param(int streamID, struct sst_stream_params *str_param);
 int sst_target_device_select(struct snd_sst_target_device *target_device);
 int sst_decode(int str_id, struct snd_sst_dbufs *dbufs);
 int sst_get_decoded_bytes(int str_id, unsigned long long *bytes);
 int sst_get_fw_info(struct snd_sst_fw_info *info);
 int sst_get_stream_params(int str_id,
                struct snd_sst_get_stream_params *get_params);
-int sst_get_stream(struct snd_sst_params *str_param);
-int sst_get_stream_allocated(struct snd_sst_params *str_param,
+int sst_get_stream(struct sst_stream_params *str_param);
+int sst_get_stream_allocated(struct sst_stream_params *str_param,
                                struct snd_sst_lib_download **lib_dnld);
 int sst_drain_stream(int str_id);
 int sst_get_vol(struct snd_sst_vol *set_vol);
@@ -597,7 +588,7 @@ static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx)
  */
 static inline void sst_init_stream(struct stream_info *stream,
                int codec, int sst_id, int ops, u8 slot,
-               enum snd_sst_audio_device_type device)
+               enum sst_audio_device_type device)
 {
        stream->status = STREAM_INIT;
        stream->prev = STREAM_UN_INIT;
@@ -660,4 +651,7 @@ sst_set_fw_state_locked(struct intel_sst_drv *sst_drv_ctx, int sst_state)
        sst_drv_ctx->sst_state = sst_state;
        mutex_unlock(&sst_drv_ctx->sst_lock);
 }
+
+int register_sst(struct device *);
+int unregister_sst(struct device *);
 #endif /* __INTEL_SST_COMMON_H__ */
index ff1c57f..ca07088 100644 (file)
@@ -33,8 +33,8 @@
 #include <linux/fs.h>
 #include <linux/firmware.h>
 #include <linux/pm_runtime.h>
-#include <sound/intel_sst.h>
 #include <sound/intel_sst_ioctl.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -160,7 +160,7 @@ void free_stream_context(unsigned int str_id)
        }
 }
 
-void sst_send_lpe_mixer_algo_params()
+void sst_send_lpe_mixer_algo_params(void)
 {
        struct snd_ppp_params algo_param;
        struct snd_ppp_mixer_params mixer_param;
@@ -198,7 +198,7 @@ void sst_send_lpe_mixer_algo_params()
  * This creates new stream id for a stream, in case lib is to be downloaded to
  * DSP, it downloads that
  */
-int sst_get_stream_allocated(struct snd_sst_params *str_param,
+int sst_get_stream_allocated(struct sst_stream_params *str_param,
                struct snd_sst_lib_download **lib_dnld)
 {
        int retval, str_id;
@@ -237,17 +237,17 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param,
  *
  * @str_param : stream params
  */
-static int sst_get_sfreq(struct snd_sst_params *str_param)
+static int sst_get_sfreq(struct sst_stream_params *str_param)
 {
        switch (str_param->codec) {
        case SST_CODEC_TYPE_PCM:
-               return str_param->sparams.uc.pcm_params.sfreq;
+               return str_param->sparams.sfreq;
        case SST_CODEC_TYPE_MP3:
-               return str_param->sparams.uc.mp3_params.sfreq;
+               return str_param->sparams.sfreq;
        case SST_CODEC_TYPE_AAC:
-               return str_param->sparams.uc.aac_params.sfreq;
+               return str_param->sparams.sfreq;
        case SST_CODEC_TYPE_WMA9:
-               return str_param->sparams.uc.wma_params.sfreq;
+               return str_param->sparams.sfreq;
        default:
                return 0;
        }
@@ -258,7 +258,7 @@ static int sst_get_sfreq(struct snd_sst_params *str_param)
  *
  * @str_param : stream param
  */
-int sst_get_stream(struct snd_sst_params *str_param)
+int sst_get_stream(struct sst_stream_params *str_param)
 {
        int i, retval;
        struct stream_info *str_info;
@@ -342,9 +342,7 @@ static int sst_prepare_fw(void)
                retval = sst_download_fw();
                if (retval) {
                        pr_err("FW download fail %x\n", retval);
-                       pr_debug("doing rtpm_put\n");
                        sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
-                       pm_runtime_put(&sst_drv_ctx->pci->dev);
                        return retval;
                }
        } else {
@@ -378,11 +376,6 @@ void sst_process_mad_ops(struct work_struct *work)
        case SST_SND_STREAM_PROCESS:
                pr_debug("play/capt frames...\n");
                break;
-       case SST_SND_DEVICE_RESUME:
-               pr_debug("SST_SND_DEVICE_RESUME\n");
-               pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
-               sst_prepare_fw();
-               break;
        default:
                pr_err(" wrong control_ops reported\n");
        }
@@ -401,21 +394,22 @@ void sst_process_mad_ops(struct work_struct *work)
  * This function is called by MID sound card driver to open
  * a new pcm interface
  */
-static int sst_open_pcm_stream(struct snd_sst_params *str_param)
+static int sst_open_pcm_stream(struct sst_stream_params *str_param)
 {
        struct stream_info *str_info;
        int retval;
 
+       if (!str_param)
+               return -EINVAL;
+
        pr_debug("open_pcm, doing rtpm_get\n");
        pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
 
        retval = sst_prepare_fw();
-       if (retval)
+       if (retval) {
+               pr_err("Unable to download FW\n");
+               pm_runtime_put(&sst_drv_ctx->pci->dev);
                return retval;
-
-       if (!str_param) {
-               pr_debug("open_pcm, doing rtpm_put\n");
-               return -EINVAL;
        }
 
        mutex_lock(&sst_drv_ctx->sst_lock);
@@ -479,8 +473,7 @@ static int sst_device_control(int cmd, void *arg)
        case SST_SND_PAUSE:
        case SST_SND_RESUME:
        case SST_SND_DROP:
-       case SST_SND_START:
-       case SST_SND_DEVICE_RESUME: {
+       case SST_SND_START: {
                struct mad_ops_wq *work = kzalloc(sizeof(*work), GFP_ATOMIC);
                if (!work)
                        return -ENOMEM;
@@ -490,15 +483,6 @@ static int sst_device_control(int cmd, void *arg)
                queue_work(sst_drv_ctx->mad_wq, &work->wq);
                break;
        }
-       case SST_SND_DEVICE_RESUME_SYNC:
-               pr_debug("SST_SND_DEVICE_RESUME_SYNC\n");
-               pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
-               sst_prepare_fw();
-               break;
-       case SST_SND_DEVICE_SUSPEND:
-               pr_debug("SST_SND_DEVICE_SUSPEND doing rtpm_put\n");
-               pm_runtime_put(&sst_drv_ctx->pci->dev);
-               break;
        case SST_SND_STREAM_INIT: {
                struct pcm_stream_info *str_info;
                struct stream_info *stream;
@@ -629,50 +613,36 @@ static int sst_set_generic_params(enum sst_controls cmd, void *arg)
        return ret_val;
 }
 
-static struct intel_sst_pcm_control pcm_ops = {
+static struct sst_ops pcm_ops = {
        .open = sst_open_pcm_stream,
        .device_control = sst_device_control,
        .set_generic_params = sst_set_generic_params,
        .close = sst_close_pcm_stream,
 };
 
-static struct intel_sst_card_ops sst_pmic_ops = {
-       .pcm_control = &pcm_ops,
+static struct sst_device sst_dsp_device = {
+       .name = "Intel(R) SST LPE",
+       .dev = NULL,
+       .ops = &pcm_ops,
 };
 
 /*
- * register_sst_card - function for sound card to register
+ * register_sst - function to register DSP
  *
- * @card: pointer to structure of operations
- *
- * This function is called card driver loads and is ready for registration
+ * This functions registers DSP with the platform driver
  */
-int register_sst_card(struct intel_sst_card_ops *card)
+int register_sst(struct device *dev)
 {
-       pr_debug("driver register card %p\n", sst_drv_ctx);
-       if (!sst_drv_ctx) {
-               pr_err("No SST driver register card reject\n");
-               return -ENODEV;
-       }
+       int ret_val;
+       sst_dsp_device.dev = dev;
+       ret_val = sst_register_dsp(&sst_dsp_device);
+       if (ret_val)
+               pr_err("Unable to register DSP with platform driver\n");
 
-       if (!card) {
-               pr_err("Null Pointer Passed\n");
-               return -EINVAL;
-       }
-       card->pcm_control = sst_pmic_ops.pcm_control;
-       return 0;
+       return ret_val;
 }
-EXPORT_SYMBOL_GPL(register_sst_card);
 
-/*
- * unregister_sst_card- function for sound card to un-register
- *
- * @card: pointer to structure of operations
- *
- * This function is called when card driver unloads
- */
-void unregister_sst_card(struct intel_sst_card_ops *card)
+int unregister_sst(struct device *dev)
 {
-       return;
+       return sst_unregister_dsp(&sst_dsp_device);
 }
-EXPORT_SYMBOL_GPL(unregister_sst_card);
index e18c2db..017fcd4 100644 (file)
@@ -38,8 +38,8 @@
 #include <linux/firmware.h>
 #include <linux/dmaengine.h>
 #include <linux/intel_mid_dma.h>
-#include <sound/intel_sst.h>
 #include <sound/intel_sst_ioctl.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 #include <linux/sched.h>
@@ -241,7 +241,7 @@ static int sst_parse_module(struct fw_module_header *module,
                }
                /*converting from physical to virtual because
                scattergather list works on virtual pointers*/
-               ram = phys_to_virt(ram);
+               ram = (int) phys_to_virt(ram);
                sst_fill_sglist(ram, block, &sg_src, &sg_dst);
                block = (void *)block + sizeof(*block) + block->size;
        }
index 3959d7c..4723648 100644 (file)
@@ -366,7 +366,7 @@ struct snd_ppp_mixer_params {
        __u32                   type; /*Type of the parameter */
        __u32                   size;
        __u32                   input_stream_bitmap; /*Input stream Bit Map*/
-} __attribute__ ((packed));
+} __packed;
 
 struct snd_sst_lib_download {
        struct module_info lib_info; /* library info type, capabilities etc */
index 7b94bcd..81e4c91 100644 (file)
@@ -31,8 +31,8 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
-#include <sound/intel_sst.h>
 #include <sound/intel_sst_ioctl.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
index ca51d49..1a4e9eb 100644 (file)
@@ -35,8 +35,8 @@
 #include <linux/fs.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
-#include <sound/intel_sst.h>
 #include <sound/intel_sst_ioctl.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
index 7efeae4..37391f0 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
 #include <sound/intel_sst_ioctl.h>
-#include <sound/intel_sst.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -192,7 +192,14 @@ int sst_alloc_stream(char *params, unsigned int stream_ops,
        pr_debug("SST DBG:%d %d %d\n", stream_ops, codec, device);
 
        BUG_ON(!params);
-       sparams = (struct snd_sst_stream_params *)params;
+       sparams = kzalloc(sizeof(*sparams), GFP_KERNEL);
+       if (!sparams) {
+               pr_err("Unable to allocate snd_sst_stream_params\n");
+               return -ENOMEM;
+       }
+       /* TODO: figure out type of codec - assuming PCM size here */
+       memcpy(&sparams->uc, params, sizeof(struct sst_pcm_params));
+
        num_ch = sparams->uc.pcm_params.num_chan;
        /*check the device type*/
        if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) {
@@ -232,8 +239,9 @@ int sst_alloc_stream(char *params, unsigned int stream_ops,
        alloc_param.str_type.protected_str = 0; /* non drm */
        alloc_param.str_type.time_slots = pcm_slot;
        alloc_param.str_type.result = alloc_param.str_type.reserved = 0;
-       memcpy(&alloc_param.stream_params, params,
+       memcpy(&alloc_param.stream_params, sparams,
                        sizeof(struct snd_sst_stream_params));
+       kfree(sparams);
 
        memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
        memcpy(msg->mailbox_data + sizeof(u32), &alloc_param,
index 074a463..5ea143f 100644 (file)
 #include "../memrar/memrar.h"
 #endif
 #include <sound/intel_sst_ioctl.h>
-#include <sound/intel_sst.h>
+#include "../sst_platform.h"
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
+
 /**
 * sst_get_stream_params - Send msg to query for stream parameters
 * @str_id:     stream id for which the parameters are queried for
@@ -118,7 +119,7 @@ int sst_get_stream_params(int str_id,
  *
  * This function sets stream params during runtime
  */
-int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
+int sst_set_stream_param(int str_id, struct sst_stream_params *str_param)
 {
        int retval = 0;
        struct ipc_post *msg = NULL;
index ec908d8..b79309a 100644 (file)
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/intel_sst_ioctl.h>
-#include <sound/intel_sst.h>
-#include "../codecs/sn95031.h"
 #include "sst_platform.h"
+#include "sst_platform_pvt.h"
 
-#define SST_VOICE_DAI "Voice-cpu-dai"
-
-static struct sst_platform_ctx *sst_cpu_ctx;
+struct sst_device *sst_dsp;
+static DEFINE_MUTEX(sst_dsp_lock);
 
 static struct snd_pcm_hardware sst_platform_pcm_hw = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED |
@@ -66,66 +64,23 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = {
        .periods_max = SST_MAX_PERIODS,
        .fifo_size = SST_FIFO_SIZE,
 };
+
 #ifdef CONFIG_SND_CLV_MACHINE
 static unsigned int    lpe_mixer_input_ihf;
 static unsigned int    lpe_mixer_input_hs;
 
-int sst_set_mixer_param(unsigned int device_input_mixer)
+static int sst_set_mixer_param(unsigned int device_input_mixer)
 {
-       struct intel_sst_card_ops *sstdrv_ops;
-       int ret_val;
-
-       /* allocate memory for SST API set */
-       sstdrv_ops = kzalloc(sizeof(*sstdrv_ops), GFP_KERNEL);
-       if (!sstdrv_ops)
-               return -ENOMEM;
-       /* registering with SST driver to get access to SST APIs to use */
-       ret_val = register_sst_card(sstdrv_ops);
-       if (ret_val) {
-               pr_err("sst: sst card registration failed\n");
-               return -EIO;
+       if (!sst_dsp) {
+               pr_err("sst: DSP not registered\n");
+               return -ENODEV;
        }
 
        /*allocate memory for params*/
-       ret_val = sstdrv_ops->pcm_control->set_generic_params(
-                       SST_SET_ALGO_PARAMS, (void *)&device_input_mixer);
-       kfree(sstdrv_ops);
-       return ret_val;
-}
-#endif
-
-static int sst_platform_ihf_set_tdm_slot(struct snd_soc_dai *dai,
-                       unsigned int tx_mask, unsigned int rx_mask,
-                       int slots, int slot_width) {
-       struct intel_sst_card_ops *sstdrv_ops;
-       struct snd_sst_runtime_params params_data;
-       int channels = slots;
-       int ret_val;
-
-       /* allocate memory for SST API set */
-       sstdrv_ops = kzalloc(sizeof(*sstdrv_ops), GFP_KERNEL);
-       if (!sstdrv_ops)
-               return -ENOMEM;
-       /* registering with SST driver to get access to SST APIs to use */
-       ret_val = register_sst_card(sstdrv_ops);
-       if (ret_val) {
-               pr_err("sst: sst card registration failed\n");
-               return -EIO;
-       }
-       params_data.type = SST_SET_CHANNEL_INFO;
-       params_data.str_id = SND_SST_DEVICE_IHF;
-       params_data.size = sizeof(channels);
-       params_data.addr = &channels;
-       ret_val = sstdrv_ops->pcm_control->set_generic_params(SST_SET_RUNTIME_PARAMS,
-                                                       (void *)&params_data);
-       kfree(sstdrv_ops);
-       return ret_val;
+       return sst_dsp->ops->set_generic_params(SST_SET_ALGO_PARAMS,
+                                       (void *)&device_input_mixer);
 }
-static const struct snd_soc_dai_ops sst_ihf_ops = {
-       .set_tdm_slot = sst_platform_ihf_set_tdm_slot,
-};
 
-#ifdef CONFIG_SND_CLV_MACHINE
 static int lpe_mixer_ihf_get(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -145,17 +100,17 @@ static int lpe_mixer_ihf_set(struct snd_kcontrol *kcontrol,
                                        | SST_INPUT_STREAM_PCM;
        break;
        case 1:
-               pr_debug("input is Comptress  stream\n");
+               pr_debug("input is Compress  stream\n");
                device_input_mixer = SST_STREAM_DEVICE_IHF
                                        | SST_INPUT_STREAM_COMPRESS;
                break;
        case 2:
-               pr_debug("input is mixed stream\n");
+               pr_debug("input is Mixed stream\n");
                device_input_mixer = SST_STREAM_DEVICE_IHF
                                        | SST_INPUT_STREAM_MIXED;
                break;
        default:
-               pr_err("Invalid Input%d\n", ucontrol->value.integer.value[0]);
+               pr_err("Invalid Input:%ld\n", ucontrol->value.integer.value[0]);
                return -EINVAL;
        }
        lpe_mixer_input_ihf  = ucontrol->value.integer.value[0];
@@ -182,30 +137,31 @@ static int lpe_mixer_headset_set(struct snd_kcontrol *kcontrol,
                                         | SST_INPUT_STREAM_PCM;
                break;
        case 1:
-               pr_debug("input is Comptress  stream\n");
+               pr_debug("input is Compress  stream\n");
                mixer_input_stream = SST_STREAM_DEVICE_HS
                                         | SST_INPUT_STREAM_COMPRESS;
                break;
        case 2:
-               pr_debug("input is PCM stream\n");
+               pr_debug("input is Mixed stream\n");
                mixer_input_stream = SST_STREAM_DEVICE_HS
                                         | SST_INPUT_STREAM_MIXED;
                break;
        default:
-               pr_err("Invalid Input%d\n", ucontrol->value.integer.value[0]);
+               pr_err("Invalid Input:%ld\n", ucontrol->value.integer.value[0]);
                return -EINVAL;
        }
        lpe_mixer_input_hs  = ucontrol->value.integer.value[0];
        sst_set_mixer_param(mixer_input_stream);
        return 0;
 }
+
 static const char *lpe_mixer_text[] = {
-               "PCM", "Compressed", "PCM and Compressed"};
+       "PCM", "Compressed", "PCM and Compressed",
+};
 
 static const struct soc_enum lpe_mixer_enum =
        SOC_ENUM_SINGLE_EXT(3, lpe_mixer_text);
 
-
 static const struct snd_kcontrol_new sst_controls[] = {
        SOC_ENUM_EXT("LPE IHF mixer", lpe_mixer_enum,
                lpe_mixer_ihf_get, lpe_mixer_ihf_set),
@@ -214,80 +170,24 @@ static const struct snd_kcontrol_new sst_controls[] = {
 };
 #endif
 
-/* MFLD - MSIC */
-static struct snd_soc_dai_driver sst_platform_dai[] = {
-{
-       .name = "Headset-cpu-dai",
-       .playback = {
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-/**FIXME ***/
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-               .rates = SNDRV_PCM_RATE_44100,
-#else
-               .rates = SNDRV_PCM_RATE_48000,
-#endif
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-               .rates = SNDRV_PCM_RATE_44100,
-#else
-               .rates = SNDRV_PCM_RATE_48000,
-#endif
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "Speaker-cpu-dai",
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_STEREO,
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-               .rates = SNDRV_PCM_RATE_44100,
-#else
-               .rates = SNDRV_PCM_RATE_48000,
-#endif
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &sst_ihf_ops,
-},
-{
-       .name = "Vibra1-cpu-dai",
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_MONO,
-               .rates = SNDRV_PCM_RATE_44100,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "Vibra2-cpu-dai",
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_MONO,
-               .rates = SNDRV_PCM_RATE_44100,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "Voice-cpu-dai",
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-};
+static int sst_platform_ihf_set_tdm_slot(struct snd_soc_dai *dai,
+                       unsigned int tx_mask, unsigned int rx_mask,
+                       int slots, int slot_width) {
+       struct snd_sst_runtime_params params_data;
+       int channels = slots;
+
+       /* registering with SST driver to get access to SST APIs to use */
+       if (!sst_dsp) {
+               pr_err("sst: DSP not registered\n");
+               return -EIO;
+       }
+       params_data.type = SST_SET_CHANNEL_INFO;
+       params_data.str_id = SND_SST_DEVICE_IHF;
+       params_data.size = sizeof(channels);
+       params_data.addr = &channels;
+       return sst_dsp->ops->set_generic_params(SST_SET_RUNTIME_PARAMS,
+                                                       (void *)&params_data);
+}
 
 /* helper functions */
 static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
@@ -311,55 +211,51 @@ static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
 }
 
 static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
-                               struct snd_sst_stream_params *param)
-{
-
-       param->uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
-       param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
-       param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
-       param->uc.pcm_params.reserved = 0;
-       param->uc.pcm_params.sfreq = substream->runtime->rate;
-       param->uc.pcm_params.ring_buffer_size =
-                                       snd_pcm_lib_buffer_bytes(substream);
-       param->uc.pcm_params.period_count = substream->runtime->period_size;
-       param->uc.pcm_params.ring_buffer_addr =
-                               virt_to_phys(substream->dma_buffer.area);
-       pr_debug("period_cnt = %d\n", param->uc.pcm_params.period_count);
-       pr_debug("sfreq= %d, wd_sz = %d\n",
-                param->uc.pcm_params.sfreq, param->uc.pcm_params.pcm_wd_sz);
+                               struct sst_pcm_params *param)
+{
+       param->codec = SST_CODEC_TYPE_PCM;
+       param->num_chan = (u8) substream->runtime->channels;
+       param->pcm_wd_sz = substream->runtime->sample_bits;
+       param->reserved = 0;
+       param->sfreq = substream->runtime->rate;
+       param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
+       param->period_count = substream->runtime->period_size;
+       param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
+       pr_debug("period_cnt = %d\n", param->period_count);
+       pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
 }
 
 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
 {
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
-       struct snd_sst_stream_params param = {{{0,},},};
-       struct snd_sst_params str_params = {0};
+       struct sst_pcm_params param = {0};
+       struct sst_stream_params str_params = {0};
        int ret_val;
 
        /* set codec params and inform SST driver the same */
        sst_fill_pcm_params(substream, &param);
        substream->runtime->dma_area = substream->dma_buffer.area;
        str_params.sparams = param;
-       str_params.codec =  param.uc.pcm_params.codec;
+       str_params.codec =  param.codec;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                str_params.ops = STREAM_OPS_PLAYBACK;
                str_params.device_type = substream->pcm->device + 1;
-               pr_debug("Playbck stream,Device %d\n",
+               pr_debug("Playback stream, Device %d\n",
                                        substream->pcm->device);
        } else {
                str_params.ops = STREAM_OPS_CAPTURE;
                str_params.device_type = SND_SST_DEVICE_CAPTURE;
-               pr_debug("Capture stream,Device %d\n",
+               pr_debug("Capture stream, Device %d\n",
                                        substream->pcm->device);
        }
-       ret_val = stream->sstdrv_ops->pcm_control->open(&str_params);
-       pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
+       ret_val = stream->ops->open(&str_params);
+       pr_debug("platform prepare: stream open ret_val = 0x%x\n", ret_val);
        if (ret_val <= 0)
                return ret_val;
 
        stream->stream_info.str_id = ret_val;
-       pr_debug("str id :  %d\n", stream->stream_info.str_id);
+       pr_debug("platform allocated strid:  %d\n", stream->stream_info.str_id);
 
        return ret_val;
 }
@@ -399,7 +295,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
        stream->stream_info.mad_substream = substream;
        stream->stream_info.buffer_ptr = 0;
        stream->stream_info.sfreq = substream->runtime->rate;
-       ret_val = stream->sstdrv_ops->pcm_control->device_control(
+       ret_val = stream->ops->device_control(
                        SST_SND_STREAM_INIT, &stream->stream_info);
        if (ret_val)
                pr_err("control_set ret error %d\n", ret_val);
@@ -408,57 +304,34 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
 }
 /* end -- helper functions */
 
-static int sst_platform_open(struct snd_pcm_substream *substream)
+static int sst_media_open(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
 {
-       struct snd_pcm_runtime *runtime;
-       struct sst_runtime_stream *stream;
        int ret_val = 0;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai_link = rtd->dai_link;
-
-       pr_debug("sst_platform_open called:%s\n", dai_link->cpu_dai_name);
-
-       runtime = substream->runtime;
-       runtime->hw = sst_platform_pcm_hw;
-       if (!strcmp(dai_link->cpu_dai_name, SST_VOICE_DAI)) {
-               sst_cpu_ctx->active_voice_cnt++;
-/**FIXME in clean up patch***/
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-
-               ret_val = intel_sst_set_pll(true, SST_PLL_VOICE);
-#endif
-               if (!ret_val)
-                       return snd_pcm_hw_constraint_integer(runtime,
-                               SNDRV_PCM_HW_PARAM_PERIODS);
-               else
-                       return ret_val;
-       }
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sst_runtime_stream *stream;
 
        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
        if (!stream)
                return -ENOMEM;
 
        spin_lock_init(&stream->status_lock);
-       stream->stream_info.str_id = 0;
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       stream->stream_info.mad_substream = substream;
-       /* allocate memory for SST API set */
-       stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops),
-                                                       GFP_KERNEL);
-       if (!stream->sstdrv_ops) {
-               pr_err("sst: mem allocation for ops fail\n");
-               ret_val = -ENOMEM;
+
+       /* get the sst ops */
+       mutex_lock(&sst_dsp_lock);
+       if (!sst_dsp ||
+           !try_module_get(sst_dsp->dev->driver->owner)) {
+               pr_err("no device available to run\n");
+               ret_val = -ENODEV;
                goto out_ops;
        }
-       stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
-       /* registering with SST driver to get access to SST APIs to use */
-       ret_val = register_sst_card(stream->sstdrv_ops);
-       if (ret_val) {
-               pr_err("sst: sst card registration failed\n");
-               goto out_reg_sst;
-       }
+       stream->ops = sst_dsp->ops;
+       mutex_unlock(&sst_dsp_lock);
+
+       stream->stream_info.str_id = 0;
+       sst_set_stream_status(stream, SST_PLATFORM_UNINIT);
+       stream->stream_info.mad_substream = substream;
        runtime->private_data = stream;
-       sst_cpu_ctx->active_nonvoice_cnt++;
 
        /* Make sure, that the period size is always even */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
@@ -466,71 +339,35 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
 
        return snd_pcm_hw_constraint_integer(runtime,
                         SNDRV_PCM_HW_PARAM_PERIODS);
-
-out_reg_sst:
-       kfree(stream->sstdrv_ops);
 out_ops:
        kfree(stream);
+       mutex_unlock(&sst_dsp_lock);
        return ret_val;
 }
 
-static int sst_platform_close(struct snd_pcm_substream *substream)
+static void sst_media_close(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
 {
        struct sst_runtime_stream *stream;
        int ret_val = 0, str_id;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai_link = rtd->dai_link;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
-       pr_debug("sst_platform_close called:%s\n", dai_link->cpu_dai_name);
-
-       if (!strcmp(dai_link->cpu_dai_name, SST_VOICE_DAI)) {
-               sst_cpu_ctx->active_voice_cnt--;
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-               intel_sst_set_pll(false, SST_PLL_VOICE);
-#endif
-               goto func_exit;
-       }
-       sst_cpu_ctx->active_nonvoice_cnt--;
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
-       if (str_id) {
-               if (stream->stream_status == SST_PLATFORM_SUSPENDED) {
-                       pr_debug("device suspended resume for closure\n");
-                       ret_val = stream->sstdrv_ops->pcm_control->
-                               device_control(SST_SND_DEVICE_RESUME_SYNC,
-                               &str_id);
-                       if (!ret_val)
-                               sst_set_stream_status(stream,
-                                       SST_PLATFORM_DROPPED);
-               }
-               ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
-       }
-       unregister_sst_card(stream->sstdrv_ops);
-       kfree(stream->sstdrv_ops);
+       if (str_id)
+               ret_val = stream->ops->close(str_id);
+       module_put(sst_dsp->dev->driver->owner);
        kfree(stream);
-func_exit:
-/**FIXME ***/
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-       if (!sst_cpu_ctx->active_nonvoice_cnt)
-               snd_soc_dai_set_tristate(codec_dai, 1);
-#endif
-       return ret_val;
+       pr_debug("%s: %d\n", __func__, ret_val);
 }
 
-static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
+static int sst_media_prepare(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
 {
        struct sst_runtime_stream *stream;
        int ret_val = 0, str_id;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai_link = rtd->dai_link;
 
-       pr_debug("sst_platform_pcm_prepare called\n");
+       pr_debug("%s\n", __func__);
 
-       if (!strcmp(dai_link->cpu_dai_name, SST_VOICE_DAI)) {
-               pr_debug("pcm_preare for Voice, returning.\n");
-               return ret_val;
-       }
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
        if (stream->stream_info.str_id)
@@ -538,7 +375,7 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
 
        ret_val = sst_platform_alloc_stream(substream);
        if (ret_val <= 0)
-               goto out;
+               return ret_val;
        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
                        "%d", stream->stream_info.str_id);
 
@@ -546,17 +383,114 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
        if (ret_val)
                return ret_val;
        substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+       return ret_val;
+}
 
+static int sst_media_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       pr_debug("%s\n", __func__);
+       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+       return 0;
+}
 
-out:
-       /* we are suspending the sink/source here as we want to have
-        * device suspended in idle, before handling next request we will send
-        * an explict RESUME call  */
-       pr_debug("Suspend NOW\n");
-       stream->sstdrv_ops->pcm_control->device_control(
-                       SST_SND_DEVICE_SUSPEND, &stream->stream_info.str_id);
-       sst_set_stream_status(stream, SST_PLATFORM_SUSPENDED);
-       return ret_val;
+static int sst_media_hw_free(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static struct snd_soc_dai_ops sst_media_dai_ops = {
+       .startup = sst_media_open,
+       .shutdown = sst_media_close,
+       .prepare = sst_media_prepare,
+       .hw_params = sst_media_hw_params,
+       .hw_free = sst_media_hw_free,
+       .set_tdm_slot = sst_platform_ihf_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver sst_platform_dai[] = {
+{
+       .name = SST_HEADSET_DAI,
+       .ops = &sst_media_dai_ops,
+       .playback = {
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = SST_SPEAKER_DAI,
+       .ops = &sst_media_dai_ops,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = SST_VIBRA1_DAI,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_MONO,
+               .rates = SNDRV_PCM_RATE_44100,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = SST_VIBRA2_DAI,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_MONO,
+               .rates = SNDRV_PCM_RATE_44100,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = SST_VOICE_DAI,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+};
+
+static int sst_platform_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+       pr_debug("sst_platform_open called:%s\n", dai_link->cpu_dai_name);
+       runtime = substream->runtime;
+       runtime->hw = sst_platform_pcm_hw;
+       return 0;
+}
+
+static int sst_platform_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai_link *dai_link = rtd->dai_link;
+       pr_debug("sst_platform_close called:%s\n", dai_link->cpu_dai_name);
+       return 0;
 }
 
 static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
@@ -571,51 +505,35 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
        str_id = stream->stream_info.str_id;
        alsa_state = substream->runtime->status->state;
 
-       if (stream->stream_status == SST_PLATFORM_SUSPENDED) {
-               pr_debug("in trigger, device is suspended, so resume it\n");
-               ret_val = stream->sstdrv_ops->pcm_control->device_control(
-                                       SST_SND_DEVICE_RESUME, &str_id);
-               if (!ret_val)
-                       sst_set_stream_status(stream, SST_PLATFORM_DROPPED);
-       }
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               pr_debug("sst: Trigger Start\n");
+               pr_debug("Trigger Start\n");
                str_cmd = SST_SND_START;
                status = SST_PLATFORM_RUNNING;
                stream->stream_info.mad_substream = substream;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               pr_debug("sst: in stop\n");
+               pr_debug("Trigger stop\n");
                str_cmd = SST_SND_DROP;
                status = SST_PLATFORM_DROPPED;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               pr_debug("sst: in pause\n");
+               pr_debug("Trigger pause\n");
                str_cmd = SST_SND_PAUSE;
                status = SST_PLATFORM_PAUSED;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               pr_debug("sst: in pause release\n");
+               pr_debug("Trigger pause release\n");
                str_cmd = SST_SND_RESUME;
                status = SST_PLATFORM_RUNNING;
                break;
        default:
                return -EINVAL;
        }
-       ret_val = stream->sstdrv_ops->pcm_control->device_control(str_cmd,
-                                                               &str_id);
+       ret_val = stream->ops->device_control(str_cmd, &str_id);
        if (!ret_val)
                sst_set_stream_status(stream, status);
 
-       if (cmd == SNDRV_PCM_TRIGGER_STOP &&
-                               alsa_state == SNDRV_PCM_STATE_DRAINING) {
-               ret_val = stream->sstdrv_ops->pcm_control->device_control(
-                                       SST_SND_DEVICE_SUSPEND, &str_id);
-               if (!ret_val)
-                       sst_set_stream_status(stream, SST_PLATFORM_SUSPENDED);
-       }
        return ret_val;
 }
 
@@ -632,7 +550,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
        if (status == SST_PLATFORM_INIT)
                return 0;
        str_info = &stream->stream_info;
-       ret_val = stream->sstdrv_ops->pcm_control->device_control(
+       ret_val = stream->ops->device_control(
                                SST_SND_BUFFER_POINTER, str_info);
        if (ret_val) {
                pr_err("sst: error code = %d\n", ret_val);
@@ -642,49 +560,12 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
        return stream->stream_info.buffer_ptr;
 }
 
-static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
-{
-       int ret;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-/**FIXME -Need to move all codec related stuff to Machine driver ***/
-#if (defined(CONFIG_SND_MFLD_MACHINE) || (CONFIG_SND_MFLD_MACHINE_GI))
-       if (strcmp(rtd->dai_link->cpu_dai_name, SST_VOICE_DAI)) {
-               /* Force the data width to 24 bit in MSIC. Post Processing
-               algorithms in DSP enabled with 24 bit precision */
-               ret = snd_soc_codec_set_params(codec, SNDRV_PCM_FORMAT_S24_LE);
-               if (ret < 0) {
-                       pr_debug("codec set_params returned error %d\n", ret);
-                       return ret;
-               }
-       }
-       /*last two parameters have to non-zero, otherwise pll gets disabled*/
-       snd_soc_dai_set_pll(codec_dai, 0, SST_CLK_UNINIT, 1,
-                                                       params_rate(params));
-#endif
-       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
-
-       return 0;
-}
-
-static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
 static struct snd_pcm_ops sst_platform_ops = {
        .open = sst_platform_open,
        .close = sst_platform_close,
        .ioctl = snd_pcm_lib_ioctl,
-       .prepare = sst_platform_pcm_prepare,
        .trigger = sst_platform_pcm_trigger,
        .pointer = sst_platform_pcm_pointer,
-       .hw_params = sst_platform_pcm_hw_params,
-       .hw_free = sst_platform_pcm_hw_free,
 };
 
 static void sst_pcm_free(struct snd_pcm *pcm)
@@ -713,6 +594,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
        }
        return retval;
 }
+
 #ifdef CONFIG_SND_CLV_MACHINE
 static int sst_soc_probe(struct snd_soc_platform *platform)
 {
@@ -737,23 +619,52 @@ static int sst_soc_probe(struct snd_soc_platform *platform)
        return snd_soc_add_platform_controls(platform, sst_controls,
                        ARRAY_SIZE(sst_controls));
 }
-
-static int sst_soc_remove(struct snd_soc_platform *platform)
-{
-       pr_debug("%s called\n", __func__);
-       return 0;
-}
 #endif
+
 static struct snd_soc_platform_driver sst_soc_platform_drv = {
 #ifdef CONFIG_SND_CLV_MACHINE
-       .probe          = &sst_soc_probe,
-       .remove         = &sst_soc_remove,
+       .probe          = sst_soc_probe,
 #endif
        .ops            = &sst_platform_ops,
        .pcm_new        = sst_pcm_new,
        .pcm_free       = sst_pcm_free,
 };
 
+int sst_register_dsp(struct sst_device *dev)
+{
+       if (!dev)
+               return -ENODEV;
+       mutex_lock(&sst_dsp_lock);
+       if (sst_dsp) {
+               pr_err("we already have a device %s\n", sst_dsp->name);
+               mutex_unlock(&sst_dsp_lock);
+               return -EEXIST;
+       }
+       pr_debug("registering device %s\n", dev->name);
+       sst_dsp = dev;
+       mutex_unlock(&sst_dsp_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_register_dsp);
+
+int sst_unregister_dsp(struct sst_device *dev)
+{
+       if (dev != sst_dsp)
+               return -EINVAL;
+
+       mutex_lock(&sst_dsp_lock);
+       if (sst_dsp) {
+               mutex_unlock(&sst_dsp_lock);
+               return -EIO;
+       }
+
+       pr_debug("unregister %s\n", sst_dsp->name);
+       sst_dsp = NULL;
+       mutex_unlock(&sst_dsp_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_unregister_dsp);
+
 static int sst_platform_probe(struct platform_device *pdev)
 {
        int ret;
@@ -765,19 +676,11 @@ static int sst_platform_probe(struct platform_device *pdev)
                return ret;
        }
 
-       sst_cpu_ctx = kzalloc(sizeof(*sst_cpu_ctx), GFP_KERNEL);
-       if (!sst_cpu_ctx) {
-               pr_err("memory alloc failed for cpu_dais context\n");
-               snd_soc_unregister_platform(&pdev->dev);
-               return -ENOMEM;
-       }
-
        ret = snd_soc_register_dais(&pdev->dev,
                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
        if (ret) {
                pr_err("registering cpu dais failed\n");
                snd_soc_unregister_platform(&pdev->dev);
-               kfree(sst_cpu_ctx);
        }
        return ret;
 }
@@ -787,7 +690,6 @@ static int sst_platform_remove(struct platform_device *pdev)
 
        snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
        snd_soc_unregister_platform(&pdev->dev);
-       kfree(sst_cpu_ctx);
        pr_debug("sst_platform_remove success\n");
        return 0;
 }
index 8e22096..39b921f 100644 (file)
 #ifndef __SST_PLATFORMDRV_H__
 #define __SST_PLATFORMDRV_H__
 
-#define SST_MONO               1
-#define SST_STEREO             2
+enum sst_audio_device_type {
+       SND_SST_DEVICE_HEADSET = 1,
+       SND_SST_DEVICE_IHF,
+       SND_SST_DEVICE_VIBRA,
+       SND_SST_DEVICE_HAPTIC,
+       SND_SST_DEVICE_CAPTURE,
+};
 
+enum snd_sst_input_stream {
+       SST_INPUT_STREAM_PCM = 0x2,
+       SST_INPUT_STREAM_COMPRESS = 0x8,
+       SST_INPUT_STREAM_MIXED = 0xA,
+};
 
-#define SST_MIN_RATE           8000
-#define SST_MAX_RATE           48000
-#define SST_MIN_CHANNEL                1
-#define SST_MAX_CHANNEL                2
+enum snd_sst_stream_type {
+       SST_STREAM_DEVICE_HS = 32,
+       SST_STREAM_DEVICE_IHF = 33,
+       SST_STREAM_DEVICE_MIC0 = 34,
+       SST_STREAM_DEVICE_MIC1 = 35,
+};
 
-/**FIXME ***/
-#ifdef CONFIG_SND_MFLD_MACHINE
-#define SST_MAX_BUFFER         88200 /*500ms*/
-#define SST_MIN_PERIOD_BYTES   1764  /*10ms@44.1,16bit,2ch*/
-#define SST_MAX_PERIOD_BYTES   44100 /*250ms*/
-#else
-#define SST_MAX_BUFFER         96000 /*500ms*/
-#define SST_MIN_PERIOD_BYTES   1920  /*10ms@44.1,16bit,2ch*/
-#define SST_MAX_PERIOD_BYTES   48000 /*250ms*/
-#endif
+enum sst_controls {
+       SST_SND_ALLOC =                 0x1000,
+       SST_SND_PAUSE =                 0x1001,
+       SST_SND_RESUME =                0x1002,
+       SST_SND_DROP =                  0x1003,
+       SST_SND_FREE =                  0x1004,
+       SST_SND_BUFFER_POINTER =        0x1005,
+       SST_SND_STREAM_INIT =           0x1006,
+       SST_SND_START    =              0x1007,
+       SST_SND_STREAM_PROCESS =        0x1008,
+       SST_CONTROL_BASE =              0x1009,
+       SST_VMIC_CHANNEL_SELECT =       0x1010,
+       SST_SET_RUNTIME_PARAMS =        0x1011,
+       SST_SET_ALGO_PARAMS =           0x1012,
+       SST_MAX_CONTROLS =              0x1012,
+};
 
-#define SST_MIN_PERIODS                2
-#define SST_MAX_PERIODS                50
-#define SST_FIFO_SIZE          0
-#define SST_CARD_NAMES         "intel_mid_card"
-#define MSIC_VENDOR_ID         3
-#define SST_CLK_UNINIT         0x03
+struct pcm_stream_info {
+       int str_id;
+       void *mad_substream;
+       void (*period_elapsed) (void *mad_substream);
+       unsigned long long buffer_ptr;
+       unsigned long long pcm_delay;
+       int sfreq;
+};
+
+enum sst_stream_ops {
+       STREAM_OPS_PLAYBACK = 0,        /* Decode */
+       STREAM_OPS_CAPTURE,             /* Encode */
+       STREAM_OPS_PLAYBACK_DRM,        /* Play Audio/Voice */
+       STREAM_OPS_PLAYBACK_ALERT,      /* Play Audio/Voice */
+       STREAM_OPS_CAPTURE_VOICE_CALL,  /* CSV Voice recording */
+};
+
+/* PCM Parameters */
+struct sst_pcm_params {
+       u16 codec;      /* codec type */
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u32 reserved;   /* Bitrate in bits per second */
+       u32 sfreq;      /* Sampling rate in Hz */
+       u32 ring_buffer_size;
+       u32 period_count;       /* period elapsed in samples*/
+       u32 ring_buffer_addr;
+};
+
+struct sst_stream_params {
+       u32 result;
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       struct sst_pcm_params sparams;
+};
+
+enum lpe_param_types_mixer {
+       SST_ALGO_PARAM_MIXER_STREAM_CFG = 0x801,
+};
+
+struct mad_ops_wq {
+       int stream_id;
+       enum sst_controls control_op;
+       struct work_struct wq;
+};
+
+struct sst_ops {
+       int (*open) (struct sst_stream_params *str_param);
+       int (*device_control) (int cmd, void *arg);
+       int (*set_generic_params) (enum sst_controls cmd, void *arg);
+       int (*close) (unsigned int str_id);
+};
 
 struct sst_runtime_stream {
        int     stream_status;
        struct pcm_stream_info stream_info;
-       struct intel_sst_card_ops *sstdrv_ops;
+       struct sst_ops *ops;
        spinlock_t      status_lock;
 };
 
-enum sst_drv_status {
-       SST_PLATFORM_INIT = 1,
-       SST_PLATFORM_STARTED,
-       SST_PLATFORM_RUNNING,
-       SST_PLATFORM_PAUSED,
-       SST_PLATFORM_DROPPED,
-       SST_PLATFORM_SUSPENDED,
+struct sst_device {
+       char *name;
+       struct device *dev;
+       struct sst_ops *ops;
 };
 
-struct sst_platform_ctx {
-       int active_nonvoice_cnt;
-       int active_voice_cnt;
-};
+int sst_register_dsp(struct sst_device *sst);
+int sst_unregister_dsp(struct sst_device *sst);
+/* FIXME: remove once vibra becomes PCI driver */
+void intel_sst_pwm_suspend(unsigned int suspend);
 #endif
diff --git a/sound/soc/mid-x86/sst_platform_pvt.h b/sound/soc/mid-x86/sst_platform_pvt.h
new file mode 100644 (file)
index 0000000..484dd9f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  sst_platform_pvt.h - Intel MID Platform driver header file
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  Author: Harsha Priya <priya.harsha@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 __SST_PLATFORMDRVPVT_H__
+#define __SST_PLATFORMDRVPVT_H__
+
+#define SST_MONO               1
+#define SST_STEREO             2
+
+#define SST_MIN_RATE           8000
+#define SST_MAX_RATE           48000
+#define SST_MIN_CHANNEL                1
+#define SST_MAX_CHANNEL                2
+
+#define SST_MAX_BUFFER         96000 /*500ms@48,16bit,2ch - CLV*/
+#define SST_MIN_PERIOD_BYTES   1764  /*10ms@44.1,16bit,2ch - MFLD*/
+#define SST_MAX_PERIOD_BYTES   48000 /*250ms@48,16bit,2ch - CLV*/
+
+#define SST_MIN_PERIODS                2
+#define SST_MAX_PERIODS                50
+#define SST_FIFO_SIZE          0
+#define SST_CLK_UNINIT         0x03
+#define SST_CODEC_TYPE_PCM     1
+
+#define SST_HEADSET_DAI "Headset-cpu-dai"
+#define SST_SPEAKER_DAI "Speaker-cpu-dai"
+#define SST_VIBRA1_DAI "Vibra1-cpu-dai"
+#define SST_VIBRA2_DAI "Vibra2-cpu-dai"
+#define SST_VOICE_DAI "Voice-cpu-dai"
+
+struct sst_device;
+
+enum sst_drv_status {
+       SST_PLATFORM_UNINIT,
+       SST_PLATFORM_INIT,
+       SST_PLATFORM_RUNNING,
+       SST_PLATFORM_PAUSED,
+       SST_PLATFORM_DROPPED,
+};
+
+#endif
index 25fb4bd..9a26ba0 100644 (file)
@@ -3818,6 +3818,7 @@ int snd_soc_register_codec(struct device *dev,
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
        codec->dapm.seq_notifier = codec_drv->seq_notifier;
+       codec->dapm.stream_event = codec_drv->stream_event;
        codec->dev = dev;
        codec->driver = codec_drv;
        codec->num_dai = num_dai;
index d78f107..e5a3132 100644 (file)
@@ -1213,6 +1213,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
 
+       list_for_each_entry(d, &dapm->card->dapm_list, list)
+               if (d->stream_event)
+                       d->stream_event(dapm, event);
+
        pop_dbg(dapm->dev, card->pop_time,
                "DAPM sequencing finished, waiting %dms\n", card->pop_time);
        pop_wait(card->pop_time);
@@ -2423,9 +2427,6 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
        }
 
        dapm_power_widgets(dapm, event);
-
-       if (dapm->codec->driver->stream_event)
-               dapm->codec->driver->stream_event(dapm, event);
 }
 
 /**