>From f44814d59badc396f4f66e954375ee75da7aa9b1 Mon Sep 17 00:00:00 2001
From: R Dharageswari <[email protected]>
Date: Tue, 7 Dec 2010 18:03:49 +0530
Subject: [PATCH 3/4] sst:vmic implementation in audio driver

Medfield supports virtual mic which pulseaudio can use for
post-porcessing algorithms.

This patch enable virtual mic feature in dsp fw and adds a
new alsamixer kcontrol for specifying the vmic device.

Signed-off-by: R Dharageswari <[email protected]>
Signed-off-by: Ramesh Babu K V <[email protected]>
---
 include/sound/intel_sst.h               |    1 +
 sound/pci/sst/intel_sst_common.h        |    9 +++-
 sound/pci/sst/intel_sst_drv_interface.c |   13 ++++++-
 sound/pci/sst/intel_sst_fw_ipc.h        |    1 +
 sound/pci/sst/intel_sst_ipc.c           |   18 ++++++++
 sound/pci/sst/intel_sst_pvt.c           |   29 ++++++++++++++
 sound/pci/sst/intel_sst_stream.c        |    2 +-
 sound/pci/sst/intelmid.h                |   14 ++++++-
 sound/pci/sst/intelmid_ctrl.c           |   65 ++++++++++++++++++++++++++++++-
 9 files changed, 143 insertions(+), 9 deletions(-)

diff --git a/include/sound/intel_sst.h b/include/sound/intel_sst.h
index a8f7941..d2d3653 100644
--- a/include/sound/intel_sst.h
+++ b/include/sound/intel_sst.h
@@ -59,6 +59,7 @@ enum sst_controls {
        SST_MAX_CONTROLS =              0x1008,
        SST_CONTROL_BASE =              0x1000,
        SST_ENABLE_RX_TIME_SLOT =       0x1009,
+       SST_VMIC_CHANNEL_SELECT =       0x1011,
 };
 
 enum SND_CARDS {
diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h
index 30fccab..4e02dd9 100644
--- a/sound/pci/sst/intel_sst_common.h
+++ b/sound/pci/sst/intel_sst_common.h
@@ -28,8 +28,8 @@
  *  Common private declarations for SST
  */
 
-#define SST_DRIVER_VERSION "1.2.11"
-#define SST_VERSION_NUM 0x1211
+#define SST_DRIVER_VERSION "1.2.14"
+#define SST_VERSION_NUM 0x1214
 
 /* driver names */
 #define SST_DRV_NAME "intel_sst_driver"
@@ -394,7 +394,8 @@ struct intel_sst_drv {
        struct stream_info      streams[MAX_NUM_STREAMS];
        struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM];
        struct sst_block        tgt_dev_blk, fw_info_blk, ppp_params_blk,
-                               vol_info_blk, mute_info_blk, hs_info_blk;
+                               vol_info_blk, mute_info_blk, hs_info_blk,
+                               vmic_info_blk;
        struct mutex            list_lock;/* mutex for IPC list locking */
        spinlock_t      list_spin_lock; /* mutex for IPC list locking */
        struct snd_pmic_ops     *scard_ops;
@@ -413,6 +414,7 @@ struct intel_sst_drv {
        unsigned int            lpe_stalled; /* LPE is stalled or not */
        unsigned int            pmic_port_instance; /*pmic port instance*/
        int                     rx_time_slot_status;
+       int                     vmic_device;
        unsigned int            lpaudio_start;
                /* 1 - LPA stream(MP3 pb) in progress*/
        unsigned int            audio_start;
@@ -446,6 +448,7 @@ int sst_stalled(void);
 int sst_pause_stream(int id);
 int sst_resume_stream(int id);
 int sst_enable_rx_timeslot(int status);
+int sst_enable_vmic(u32 device);
 int sst_drop_stream(int id);
 int sst_free_stream(int id);
 int sst_start_stream(int streamID);
diff --git a/sound/pci/sst/intel_sst_drv_interface.c 
b/sound/pci/sst/intel_sst_drv_interface.c
index 2a9c232..51b19e5 100644
--- a/sound/pci/sst/intel_sst_drv_interface.c
+++ b/sound/pci/sst/intel_sst_drv_interface.c
@@ -107,9 +107,14 @@ void free_stream_context(unsigned int str_id)
                if (stream->ops == STREAM_OPS_PLAYBACK ||
                                stream->ops == STREAM_OPS_PLAYBACK_DRM) {
                        sst_drv_ctx->pb_streams--;
-                       if (sst_drv_ctx->pb_streams == 0)
+                       if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
                                sst_drv_ctx->scard_ops->power_down_pmic_pb(
                                                stream->device);
+                       else {
+                               if (sst_drv_ctx->pb_streams == 0)
+                                       sst_drv_ctx->scard_ops->
+                                       power_down_pmic_pb(stream->device);
+                       }
                } else if (stream->ops == STREAM_OPS_CAPTURE) {
                        sst_drv_ctx->cp_streams--;
                        if (sst_drv_ctx->cp_streams == 0)
@@ -458,6 +463,12 @@ int sst_device_control(int cmd, void *arg)
                sst_enable_rx_timeslot(status);
                break;
        }
+       case SST_VMIC_CHANNEL_SELECT: {
+               int device = *(int *)arg;
+               sst_drv_ctx->vmic_device = device;
+               sst_enable_vmic(device);
+               break;
+       }
        default:
                /* Illegal case */
                pr_warn("sst: illegal req\n");
diff --git a/sound/pci/sst/intel_sst_fw_ipc.h b/sound/pci/sst/intel_sst_fw_ipc.h
index ed237c3..11f9da9 100644
--- a/sound/pci/sst/intel_sst_fw_ipc.h
+++ b/sound/pci/sst/intel_sst_fw_ipc.h
@@ -91,6 +91,7 @@
 #define IPC_IA_ENABLE_RX_TIME_SLOT 0x2E /* Enable Rx time slot 0 or 1 */
 
 #define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */
+#define IPC_IA_VMIC_CHANL_SELECT 0x33
 
 /* Debug msgs */
 #define IPC_IA_DBG_MEM_READ 0x40
diff --git a/sound/pci/sst/intel_sst_ipc.c b/sound/pci/sst/intel_sst_ipc.c
index 4ff6470..5da1df2 100644
--- a/sound/pci/sst/intel_sst_ipc.c
+++ b/sound/pci/sst/intel_sst_ipc.c
@@ -607,6 +607,24 @@ void sst_process_reply(struct work_struct *work)
                        wake_up(&sst_drv_ctx->wait_queue);
                }
                break;
+       case IPC_IA_VMIC_CHANL_SELECT:
+               if (!msg->header.part.data) {
+                       pr_debug("sst: VMIC_Device success\n");
+                       sst_drv_ctx->vmic_info_blk.ret_code = 0;
+               } else {
+                       pr_err("sst:  Msg %x reply error %x\n",
+                               msg->header.part.msg_id,
+                               msg->header.part.data);
+                       sst_drv_ctx->vmic_info_blk.ret_code =
+                               -msg->header.part.data;
+               }
+               if (sst_drv_ctx->vmic_info_blk.on == true) {
+                       sst_drv_ctx->vmic_info_blk.on = false;
+                       sst_drv_ctx->vmic_info_blk.condition = true;
+                       wake_up(&sst_drv_ctx->wait_queue);
+               }
+               break;
+
        case IPC_IA_PAUSE_STREAM:
        case IPC_IA_RESUME_STREAM:
        case IPC_IA_SET_STREAM_PARAMS:
diff --git a/sound/pci/sst/intel_sst_pvt.c b/sound/pci/sst/intel_sst_pvt.c
index 7f2f8d7..5105070 100644
--- a/sound/pci/sst/intel_sst_pvt.c
+++ b/sound/pci/sst/intel_sst_pvt.c
@@ -307,4 +307,33 @@ int sst_enable_rx_timeslot(int status)
                                &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT);
        return retval;
 }
+/**
+ * sst_enable_vmic - Send information of the vmic device selected to the 
firmware
+ * @status: rx timeslot to be enabled
+ *
+ * This function is called when VMIC info is to be sent to the firmware
+ */
+int sst_enable_vmic(u32 device)
+{
+       int retval = 0;
+       struct ipc_post *msg = NULL;
+
+       if (sst_create_short_msg(&msg)) {
+               pr_err("sst: mem allocation failed\n");
+                       return -ENOMEM;
+       }
+       pr_debug("sst: ipc message sending: VMIC_DEVICE:%d\n", device);
+       sst_fill_header(&msg->header, IPC_IA_VMIC_CHANL_SELECT, 0, 0);
+       msg->header.part.data = device;
+       sst_drv_ctx->vmic_info_blk.condition = false;
+       sst_drv_ctx->vmic_info_blk.ret_code = 0;
+       sst_drv_ctx->vmic_info_blk.on = true;
+       spin_lock(&sst_drv_ctx->list_spin_lock);
+       list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+       spin_unlock(&sst_drv_ctx->list_spin_lock);
+       sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+       retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+                               &sst_drv_ctx->vmic_info_blk, SST_BLOCK_TIMEOUT);
+       return retval;
+}
 
diff --git a/sound/pci/sst/intel_sst_stream.c b/sound/pci/sst/intel_sst_stream.c
index ee5bd5d..2d247fb 100644
--- a/sound/pci/sst/intel_sst_stream.c
+++ b/sound/pci/sst/intel_sst_stream.c
@@ -68,7 +68,7 @@ int sst_check_device_type(u32 device, u32 num_chan, u32 
*pcm_slot)
                        *pcm_slot = 0x03;
                else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 3)
                        *pcm_slot = 0x07;
-               else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4)
+               else if (device == SND_SST_DEVICE_CAPTURE && num_chan >= 4)
                        *pcm_slot = 0x0F;
                else {
                        pr_debug("sst: No condition satisfied.. ret err\n");
diff --git a/sound/pci/sst/intelmid.h b/sound/pci/sst/intelmid.h
index 0ce1031..9f1790a 100644
--- a/sound/pci/sst/intelmid.h
+++ b/sound/pci/sst/intelmid.h
@@ -53,11 +53,11 @@
 #define STEREO_CNTL            2
 #define MIN_CHANNEL            1
 #define MAX_CHANNEL_AMIC       2
-#define MAX_CHANNEL_DMIC       4
+#define MAX_CHANNEL_DMIC       5
 #define FIFO_SIZE              0 /* fifo not being used */
 #define INTEL_MAD              "Intel MAD"
 #define MAX_CTRL_MRST          7
-#define MAX_CTRL_MFLD          2
+#define MAX_CTRL_MFLD          4
 #define MAX_CTRL               7
 #define MAX_VENDORS            4
 /* TODO +6 db */
@@ -163,6 +163,16 @@ enum _widget_ctrl {
        CAPTURE_MUTE,
        MASTER_MUTE
 };
+enum _widget_ctrl_mfld {
+       LINEOUT_SEL_MFLD = 3,
+       VMIC_SEL_MFLD,
+};
+enum vmic_controls {
+       IHFL,
+       IHFR,
+       HSL,
+       HSR
+};
 
 void period_elapsed(void *mad_substream);
 int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream);
diff --git a/sound/pci/sst/intelmid_ctrl.c b/sound/pci/sst/intelmid_ctrl.c
index 105606e..e996474 100644
--- a/sound/pci/sst/intelmid_ctrl.c
+++ b/sound/pci/sst/intelmid_ctrl.c
@@ -36,6 +36,10 @@ static char *out_names_mrst[] = {"Headphones",
 static char *in_names_mrst[] = {"AMIC",
                                "DMIC",
                                "HS_MIC"};
+static char *vmic_names_mfld[] = {"IHF-left     ",
+                               "IHF-right    ",
+                               "Headset-Left ",
+                               "Headset-Right"};
 static char *out_names_mfld[] = {"Headset ",
                                "EarPiece  "};
 static char *in_names_mfld[] = {"AMIC",
@@ -175,13 +179,26 @@ static int snd_intelmad_device_info_mrst(struct 
snd_kcontrol *kcontrol,
 static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_info *uinfo)
 {
+       struct snd_pmic_ops *scard_ops;
+       struct snd_intelmad *intelmaddata;
+
        WARN_ON(!kcontrol);
        WARN_ON(!uinfo);
+
+       intelmaddata = kcontrol->private_data;
+
+       WARN_ON(!intelmaddata->sstdrv_ops);
+
+       scard_ops = intelmaddata->sstdrv_ops->scard_ops;
        /* setup device select as drop down controls with different values */
        if (kcontrol->id.numid == OUTPUT_SEL)
                uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mfld);
-       else
+       else if (kcontrol->id.numid == INPUT_SEL)
                uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mfld);
+       else if (kcontrol->id.numid == VMIC_SEL_MFLD)
+               uinfo->value.enumerated.items = ARRAY_SIZE(vmic_names_mfld);
+       else
+               return -EINVAL;
        uinfo->count = MONO_CNTL;
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 
@@ -191,10 +208,16 @@ static int snd_intelmad_device_info_mfld(struct 
snd_kcontrol *kcontrol,
                strncpy(uinfo->value.enumerated.name,
                        out_names_mfld[uinfo->value.enumerated.item],
                        sizeof(uinfo->value.enumerated.name)-1);
-       else
+       else if (kcontrol->id.numid == INPUT_SEL)
                strncpy(uinfo->value.enumerated.name,
                        in_names_mfld[uinfo->value.enumerated.item],
                        sizeof(uinfo->value.enumerated.name)-1);
+       else if (kcontrol->id.numid == VMIC_SEL_MFLD)
+               strncpy(uinfo->value.enumerated.name,
+                       vmic_names_mfld[uinfo->value.enumerated.item],
+                       sizeof(uinfo->value.enumerated.name)-1);
+       else
+               return -EINVAL;
        return 0;
 }
 
@@ -468,6 +491,9 @@ static int snd_intelmad_device_get(struct snd_kcontrol 
*kcontrol,
                else if (kcontrol->id.numid == INPUT_SEL)
                        uval->value.enumerated.item[0] =
                                        scard_ops->input_dev_id;
+               else if (kcontrol->id.numid == VMIC_SEL_MFLD)
+                       uval->value.enumerated.item[0] =
+                                       kcontrol->private_value;
                else
                        return -EINVAL;
        } else
@@ -490,6 +516,7 @@ static int snd_intelmad_device_set(struct snd_kcontrol 
*kcontrol,
        struct snd_intelmad *intelmaddata;
        struct snd_pmic_ops *scard_ops;
        int ret_val = 0, vendor, status;
+       u32 device;
        struct intel_sst_pcm_control *pcm_control;
 
        pr_debug("sst: snd_intelmad_device_set called\n");
@@ -530,6 +557,22 @@ static int snd_intelmad_device_set(struct snd_kcontrol 
*kcontrol,
                                uval->value.enumerated.item[0]);
                intelmaddata->input_sel = uval->value.enumerated.item[0];
                break;
+       case VMIC_SEL_MFLD:
+               pcm_control = intelmaddata->sstdrv_ops->pcm_control;
+               if (uval->value.enumerated.item[0] == IHFL)
+                       device = 0x02;
+               else if (uval->value.enumerated.item[0] == IHFR)
+                       device = 0x03;
+               else if (uval->value.enumerated.item[0] == HSL)
+                       device = 0x00;
+               else if (uval->value.enumerated.item[0] == HSR)
+                       device = 0x01;
+               else
+               pr_debug("sst: Invalid selection\n");
+               pcm_control->device_control(
+                                       SST_VMIC_CHANNEL_SELECT, &device);
+               break;
+
        default:
                return -EINVAL;
        }
@@ -623,5 +666,23 @@ snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = {
        .put            =       snd_intelmad_device_set,
        .private_value  =       0,
 },
+{
+       .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           =       "Line out",
+       .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info           =       snd_intelmad_device_info_mfld,
+       .get            =       snd_intelmad_device_get,
+       .put            =       snd_intelmad_device_set,
+       .private_value  =       0,
+},
+{
+       .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           =       "Virtual MIC",
+       .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info           =       snd_intelmad_device_info_mfld,
+       .get            =       snd_intelmad_device_get,
+       .put            =       snd_intelmad_device_set,
+       .private_value  =       0,
+},
 };
 
-- 
1.6.2.5

Attachment: 0003-sst-vmic-implementation-in-audio-driver.patch
Description: 0003-sst-vmic-implementation-in-audio-driver.patch

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to