Merge "hal: add support for I2S based external modem"
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index 128e4af..59bdb56 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -125,7 +125,9 @@
 
 static void  update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name)
 {
-    if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card")) {
+    if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card") ||
+        !strncmp(snd_card_name, "apq8084-taiko-i2s-mtp-snd-card",
+                 sizeof("apq8084-taiko-i2s-mtp-snd-card"))) {
         strlcpy(hw_info->type, "mtp", sizeof(hw_info->type));
         strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
         hw_info->snd_devices = NULL;
@@ -137,6 +139,13 @@
         hw_info->snd_devices = (snd_device_t *)taiko_apq8084_CDP_variant_devices;
         hw_info->num_snd_devices = ARRAY_SIZE(taiko_apq8084_CDP_variant_devices);
         strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+    } else if (!strncmp(snd_card_name, "apq8084-taiko-i2s-cdp-snd-card",
+                        sizeof("apq8084-taiko-i2s-cdp-snd-card"))) {
+        strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
     } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) {
         strlcpy(hw_info->type , " liquid", sizeof(hw_info->type));
         strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type));
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 4161d87..b88d86f 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -36,6 +36,11 @@
 
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
+#define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
+
+#define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
+#define PLATFORM_INFO_XML_PATH_I2S  "/system/etc/audio_platform_info_i2s.xml"
+
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
 
@@ -109,6 +114,7 @@
     int  fluence_type;
     int  btsco_sample_rate;
     bool slowtalk;
+    bool is_i2s_ext_modem;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -410,7 +416,7 @@
     return 0;
 }
 
-static struct csd_data *open_csd_client()
+static struct csd_data *open_csd_client(bool i2s_ext_modem)
 {
     struct csd_data *csd = calloc(1, sizeof(struct csd_data));
 
@@ -512,6 +518,16 @@
                   __func__, dlerror());
             goto error;
         }
+
+        csd->get_sample_rate = (get_sample_rate_t)dlsym(csd->csd_client,
+                                             "csd_client_get_sample_rate");
+        if (csd->get_sample_rate == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_get_sample_rate",
+                  __func__, dlerror());
+
+            goto error;
+        }
+
         csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
 
         if (csd->init == NULL) {
@@ -519,7 +535,7 @@
                   __func__, dlerror());
             goto error;
         } else {
-            csd->init();
+            csd->init(i2s_ext_modem);
         }
     }
     return csd;
@@ -557,7 +573,23 @@
     ALOGD("%s: num_modems %d\n", __func__, mdm_detect_info.num_modems);
 
     if (mdm_detect_info.num_modems > 0)
-        plat_data->csd = open_csd_client();
+        plat_data->csd = open_csd_client(plat_data->is_i2s_ext_modem);
+}
+
+static bool platform_is_i2s_ext_modem(const char *snd_card_name,
+                                      struct platform_data *plat_data)
+{
+    plat_data->is_i2s_ext_modem = false;
+
+    if (!strncmp(snd_card_name, "apq8084-taiko-i2s-mtp-snd-card",
+                 sizeof("apq8084-taiko-i2s-mtp-snd-card")) ||
+        !strncmp(snd_card_name, "apq8084-taiko-i2s-cdp-snd-card",
+                 sizeof("apq8084-taiko-i2s-cdp-snd-card"))) {
+        plat_data->is_i2s_ext_modem = true;
+    }
+    ALOGV("%s, is_i2s_ext_modem:%d",__func__, plat_data->is_i2s_ext_modem);
+
+    return plat_data->is_i2s_ext_modem;
 }
 
 void *platform_init(struct audio_device *adev)
@@ -593,10 +625,16 @@
         if (!my_data->hw_info) {
             ALOGE("%s: Failed to init hardware info", __func__);
         } else {
-            if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH,
-                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS)
+            if (platform_is_i2s_ext_modem(snd_card_name, my_data)) {
+                ALOGD("%s: Call MIXER_XML_PATH_I2S", __func__);
+
+                adev->audio_route = audio_route_init(snd_card_num,
+                                                     MIXER_XML_PATH_I2S);
+            } else if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH,
+                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS) {
                 adev->audio_route = audio_route_init(snd_card_num,
                                                  MIXER_XML_PATH);
+            }
             if (!adev->audio_route) {
                 ALOGE("%s: Failed to init audio route controls, aborting.",
                        __func__);
@@ -695,7 +733,10 @@
     }
 
     /* Initialize ACDB ID's */
-    platform_info_init();
+    if (my_data->is_i2s_ext_modem)
+        platform_info_init(PLATFORM_INFO_XML_PATH_I2S);
+    else
+        platform_info_init(PLATFORM_INFO_XML_PATH);
 
     /* load csd client */
     platform_csd_init(my_data);
@@ -971,6 +1012,20 @@
     return ret;
 }
 
+int platform_get_sample_rate(void *platform, uint32_t *rate)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if ((my_data->csd != NULL) && my_data->is_i2s_ext_modem) {
+        ret = my_data->csd->get_sample_rate(rate);
+        if (ret < 0) {
+            ALOGE("%s: csd_get_sample_rate error %d\n", __func__, ret);
+        }
+    }
+    return ret;
+}
+
 int platform_set_voice_volume(void *platform, int volume)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index e80d3f1..e2ec822 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -221,7 +221,7 @@
 
 #define LIB_CSD_CLIENT "libcsd-client.so"
 /* CSD-CLIENT related functions */
-typedef int (*init_t)();
+typedef int (*init_t)(bool);
 typedef int (*deinit_t)();
 typedef int (*disable_device_t)();
 typedef int (*enable_device_config_t)(int, int);
@@ -235,6 +235,7 @@
 typedef int (*stop_playback_t)(uint32_t);
 typedef int (*start_record_t)(uint32_t, int);
 typedef int (*stop_record_t)(uint32_t);
+typedef int (*get_sample_rate_t)(uint32_t *);
 /* CSD Client structure */
 struct csd_data {
     void *csd_client;
@@ -252,6 +253,7 @@
     stop_playback_t stop_playback;
     start_record_t start_record;
     stop_record_t stop_record;
+    get_sample_rate_t get_sample_rate;
 };
 
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 81291a2..2ec6b50 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -44,6 +44,7 @@
 int platform_stop_voice_call(void *platform, uint32_t vsid);
 int platform_set_voice_volume(void *platform, int volume);
 int platform_set_mic_mute(void *platform, bool state);
+int platform_get_sample_rate(void *platform, uint32_t *rate);
 snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
 snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
 int platform_set_hdmi_channels(void *platform, int channel_count);
@@ -63,7 +64,7 @@
 bool platform_listen_update_status(snd_device_t snd_device);
 
 /* From platform_info_parser.c */
-int platform_info_init(void);
+int platform_info_init(const char *filename);
 
 struct audio_offload_info_t;
 uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 8f56107..85a05eb 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -38,7 +38,6 @@
 #include "platform_api.h"
 #include <platform.h>
 
-#define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
 #define BUF_SIZE                    1024
 
 static void process_device(const XML_Char **attr)
@@ -52,20 +51,20 @@
 
     index = platform_get_snd_device_index((char *)attr[1]);
     if (index < 0) {
-        ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
-              __func__, attr[1], PLATFORM_INFO_XML_PATH);
+        ALOGE("%s: Device %s in platform info xml not found, no ACDB ID set!",
+              __func__, attr[1]);
         goto done;
     }
 
     if (strcmp(attr[2], "acdb_id") != 0) {
-        ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
-              __func__, attr[1], PLATFORM_INFO_XML_PATH);
+        ALOGE("%s: Device %s in platform info xml has no acdb_id, no ACDB ID set!",
+              __func__, attr[1]);
         goto done;
     }
 
     if(platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
-        ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
-              __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
+        ALOGE("%s: Device %s in platform info xml ACDB ID %d was not set!",
+              __func__, attr[1], atoi((char *)attr[3]));
         goto done;
     }
 
@@ -91,7 +90,7 @@
 
 }
 
-int platform_info_init(void)
+int platform_info_init(const char *filename)
 {
     XML_Parser      parser;
     FILE            *file;
@@ -99,10 +98,10 @@
     int             bytes_read;
     void            *buf;
 
-    file = fopen(PLATFORM_INFO_XML_PATH, "r");
+    file = fopen(filename, "r");
     if (!file) {
         ALOGD("%s: Failed to open %s, using defaults.",
-            __func__, PLATFORM_INFO_XML_PATH);
+            __func__, filename);
         ret = -ENODEV;
         goto done;
     }
@@ -134,7 +133,7 @@
         if (XML_ParseBuffer(parser, bytes_read,
                             bytes_read == 0) == XML_STATUS_ERROR) {
             ALOGE("%s: XML_ParseBuffer failed, for %s",
-                __func__, PLATFORM_INFO_XML_PATH);
+                __func__, filename);
             ret = -EINVAL;
             goto err_free_parser;
         }
diff --git a/hal/voice.c b/hal/voice.c
index 28d44db..1c3ab38 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -106,6 +106,7 @@
     int i, ret = 0;
     struct audio_usecase *uc_info;
     int pcm_dev_rx_id, pcm_dev_tx_id;
+    uint32_t sample_rate = 8000;
     struct voice_session *session = NULL;
     struct pcm_config voice_config = pcm_config_voice_call;
 
@@ -133,6 +134,13 @@
         ret = -EIO;
         goto error_start_voice;
     }
+    ret = platform_get_sample_rate(adev->platform, &sample_rate);
+    if (ret < 0) {
+        ALOGE("platform_get_sample_rate error %d\n", ret);
+    } else {
+        voice_config.rate = sample_rate;
+    }
+    ALOGD("voice_config.rate %d\n", voice_config.rate);
 
     ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
           __func__, adev->snd_card, pcm_dev_rx_id);