hal: Add support to enable VBat feature

Add support to enable VBat feature. This includes required changes
to select VBat speaker devices for audio and voice usecases and
sending the VBat calibration data to codec driver.

Change-Id: I2234bee3cc4d6f16934a4b27ef9da21cde74bb48
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 2303e9d..aaca0b2 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -133,6 +133,7 @@
 char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
         [WCD9XXX_ANC_CAL] = "anc_cal",
         [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_VBAT_CAL] = "vbat_cal",
 };
 
 #define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
@@ -173,6 +174,7 @@
 typedef int (*acdb_set_audio_cal_t) (void *, void *, uint32_t);
 typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
 typedef int (*acdb_send_common_top_t) (void);
+typedef int (*acdb_set_codec_data_t) (void *, char *);
 
 typedef struct codec_backend_cfg {
     uint32_t sample_rate;
@@ -205,6 +207,9 @@
     bool ec_ref_enabled;
     bool is_wsa_speaker;
     bool is_acdb_initialized;
+    /* Vbat monitor related flags */
+    bool is_vbat_speaker;
+    bool gsm_mode_enabled;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -217,6 +222,7 @@
     acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
     acdb_get_default_app_type_t acdb_get_default_app_type;
     acdb_send_common_top_t     acdb_send_common_top;
+    acdb_set_codec_data_t      acdb_set_codec_data;
 #ifdef RECORD_PLAY_CONCURRENCY
     bool rec_play_conc_set;
 #endif
@@ -309,6 +315,7 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = "speaker-ext-1",
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = "speaker-ext-2",
     [SND_DEVICE_OUT_SPEAKER_WSA] = "wsa-speaker",
+    [SND_DEVICE_OUT_SPEAKER_VBAT] = "vbat-speaker",
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
     [SND_DEVICE_OUT_HEADPHONES_44_1] = "headphones-44.1",
@@ -318,6 +325,7 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
     [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
     [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = "wsa-voice-speaker",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = "vbat-voice-speaker",
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
     [SND_DEVICE_OUT_HDMI] = "hdmi",
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
@@ -339,6 +347,8 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = "speaker-protected-vbat",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = "voice-speaker-protected-vbat",
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
     [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
@@ -414,6 +424,7 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 14,
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 14,
     [SND_DEVICE_OUT_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_SPEAKER_VBAT] = 135,
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HEADPHONES_44_1] = 10,
@@ -423,6 +434,7 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
     [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = 135,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HDMI] = 18,
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
@@ -444,6 +456,8 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = 124,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = 101,
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
     [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
@@ -521,6 +535,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_1)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_2)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES_44_1)},
@@ -530,6 +545,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
@@ -551,6 +567,8 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT)},
 #ifdef RECORD_PLAY_CONCURRENCY
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
@@ -887,6 +905,24 @@
     }
 }
 
+void platform_set_gsm_mode(void *platform, bool enable)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    if (my_data->gsm_mode_enabled) {
+        my_data->gsm_mode_enabled = false;
+        ALOGV("%s: disabling gsm mode", __func__);
+        audio_route_reset_and_update_path(adev->audio_route, "gsm-mode");
+    }
+
+    if (enable) {
+         my_data->gsm_mode_enabled = true;
+         ALOGD("%s: enabling gsm mode", __func__);
+         audio_route_apply_and_update_path(adev->audio_route, "gsm-mode");
+    }
+}
+
 void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device)
 {
     struct platform_data *my_data = (struct platform_data *)adev->platform;
@@ -897,20 +933,27 @@
 
     if (strcmp(my_data->ec_ref_mixer_path, "")) {
         ALOGV("%s: disabling %s", __func__, my_data->ec_ref_mixer_path);
-        audio_route_reset_and_update_path(adev->audio_route, my_data->ec_ref_mixer_path);
+        audio_route_reset_and_update_path(adev->audio_route,
+                                          my_data->ec_ref_mixer_path);
     }
 
     if (enable) {
-        strlcpy(my_data->ec_ref_mixer_path, "echo-reference", sizeof(my_data->ec_ref_mixer_path));
         snd_device = platform_get_output_snd_device(adev->platform, &out);
+
         /*
          * If native audio device reference count > 0, then apply codec EC otherwise
-         * fallback to headphones if so or default
+         * fallback to Speakers with VBat if enabled or default
          */
         if (adev->snd_dev_ref_cnt[SND_DEVICE_OUT_HEADPHONES_44_1] > 0)
-            platform_add_backend_name(my_data->ec_ref_mixer_path, SND_DEVICE_OUT_HEADPHONES_44_1);
+            strlcpy(my_data->ec_ref_mixer_path, "echo-reference headphones-44.1",
+                    sizeof(my_data->ec_ref_mixer_path));
+        else if ((snd_device == SND_DEVICE_OUT_SPEAKER_VBAT) ||
+                 (snd_device == SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT))
+            strlcpy(my_data->ec_ref_mixer_path, "vbat-speaker echo-reference",
+                    sizeof(my_data->ec_ref_mixer_path));
         else
-            platform_add_backend_name(my_data->ec_ref_mixer_path, snd_device);
+            strlcpy(my_data->ec_ref_mixer_path, "echo-reference",
+                    sizeof(my_data->ec_ref_mixer_path));
 
         ALOGD("%s: enabling %s", __func__, my_data->ec_ref_mixer_path);
         audio_route_apply_and_update_path(adev->audio_route, my_data->ec_ref_mixer_path);
@@ -1092,6 +1135,7 @@
     backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
     backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
     backend_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("headphones-44.1");
+    backend_table[SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = strdup("vbat-voice-speaker");
 }
 
 void get_cvd_version(char *cvd_version, struct audio_device *adev)
@@ -1147,7 +1191,38 @@
     void   *buff;
 };
 
-static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+static int send_vbat_adc_data_to_acdb(struct platform_data *plat_data, char *cal_type)
+{
+    int ret = 0;
+    struct mixer_ctl *ctl;
+    uint16_t vbat_adc_data[2];
+    struct platform_data *my_data = plat_data;
+    struct audio_device *adev = my_data->adev;
+
+    const char *mixer_ctl_name = "Vbat ADC data";
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer ctl name - %s",
+               __func__, mixer_ctl_name);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    vbat_adc_data[0] = mixer_ctl_get_value(ctl, 0);
+    vbat_adc_data[1] = mixer_ctl_get_value(ctl, 1);
+
+    ALOGD("%s: Vbat ADC output values: Dcp1: %d , Dcp2: %d",
+           __func__, vbat_adc_data[0], vbat_adc_data[1]);
+
+    ret = my_data->acdb_set_codec_data(&vbat_adc_data[0], cal_type);
+
+done:
+    return ret;
+}
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration,
+                          struct platform_data *plat_data, int fd)
 {
     int ret = 0, type;
 
@@ -1159,6 +1234,12 @@
         if (type == WCD9XXX_MAD_CAL)
             continue;
 
+        if((plat_data->is_vbat_speaker) && (WCD9XXX_VBAT_CAL == type)) {
+           ret = send_vbat_adc_data_to_acdb(plat_data, cal_name_info[type]);
+           if (ret < 0)
+               ALOGE("%s error in sending vbat adc data to acdb", __func__);
+        }
+
         calib.get_size = 1;
         ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
                                                                  &calib);
@@ -1212,7 +1293,7 @@
            dlerror());
         return;
     }
-    if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+    if (send_codec_cal(acdb_loader_get_calibration, plat_data, fd) < 0)
         ALOGE("%s: Could not send anc cal", __FUNCTION__);
 }
 
@@ -1399,6 +1480,12 @@
         acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
     }
 
+    /* Check if Vbat speaker enabled property is set, this should be done before acdb init */
+    bool ret = false;
+    ret = audio_extn_can_use_vbat();
+    if (ret)
+        my_data->is_vbat_speaker = true;
+
     my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
@@ -1455,6 +1542,14 @@
             ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
                   __func__, LIB_ACDB_LOADER);
 
+        my_data->acdb_set_codec_data = (acdb_set_codec_data_t)dlsym(
+                                                    my_data->acdb_handle,
+                                                    "acdb_loader_set_codec_data");
+        if (!my_data->acdb_set_codec_data)
+            ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_v2");
         if (my_data->acdb_init == NULL) {
@@ -1506,7 +1601,6 @@
     audio_extn_dap_hal_init(adev->snd_card);
 
     audio_extn_dolby_set_license(adev);
-    audio_hwdep_send_cal(my_data);
 
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
@@ -1614,13 +1708,20 @@
     return 0;
 }
 
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device,
+                               struct audio_usecase *usecase)
 {
     if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
         ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
         return;
     }
 
+    if((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+        !(usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)) {
+        ALOGI("%s: Not adding vbat speaker device to non voice use cases", __func__);
+        return;
+    }
+
     const char * suffix = backend_table[snd_device];
 
     if (suffix != NULL) {
@@ -1984,10 +2085,14 @@
     if (my_data->csd == NULL)
         return ret;
 
-    if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-        audio_extn_spkr_prot_is_enabled())
-        acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
-    else
+    if ((out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+         audio_extn_spkr_prot_is_enabled()) {
+        if (my_data->is_vbat_speaker)
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
+        else
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+    } else
         acdb_rx_id = acdb_device_table[out_snd_device];
 
     acdb_tx_id = acdb_device_table[in_snd_device];
@@ -2044,10 +2149,14 @@
     if (my_data->csd == NULL)
         return ret;
 
-    if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-        audio_extn_spkr_prot_is_enabled())
-        acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
-    else
+    if ((out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+         audio_extn_spkr_prot_is_enabled()) {
+        if (my_data->is_vbat_speaker)
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
+         else
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+    } else
         acdb_rx_id = acdb_device_table[out_snd_device];
 
     acdb_tx_id = acdb_device_table[in_snd_device];
@@ -2309,7 +2418,9 @@
             else
                 snd_device = SND_DEVICE_OUT_BT_SCO;
         } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                if (my_data->is_wsa_speaker)
+                if (my_data->is_vbat_speaker)
+                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_VBAT;
+                else if (my_data->is_wsa_speaker)
                     snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
                 else
                     snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
@@ -2370,7 +2481,9 @@
                 snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
             else
             {
-                if (my_data->is_wsa_speaker)
+                if (my_data->is_vbat_speaker)
+                    snd_device = SND_DEVICE_OUT_SPEAKER_VBAT;
+                else if (my_data->is_wsa_speaker)
                     snd_device = SND_DEVICE_OUT_SPEAKER_WSA;
                 else
                     snd_device = SND_DEVICE_OUT_SPEAKER;