hal: Add support to get speaker FTM parameters

Add SET and GET parameter APIs to query speaker
parameters in feedback speaker protection FTM mode.

Change-Id: I14a2b8ccc2e0d61c4ccdcadd63c353ca31b9c8ad
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 28a0b2d..db91b51 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -764,6 +764,7 @@
    audio_extn_hpx_set_parameters(adev, parms);
    audio_extn_pm_set_parameters(parms);
    audio_extn_source_track_set_parameters(adev, parms);
+   audio_extn_fbsp_set_parameters(parms);
    check_and_set_hdmi_connection_status(parms);
    if (adev->offload_effects_set_parameters != NULL)
        adev->offload_effects_set_parameters(parms);
@@ -781,6 +782,7 @@
     audio_extn_dts_eagle_get_parameters(adev, query, reply);
     audio_extn_hpx_get_parameters(query, reply);
     audio_extn_source_track_get_parameters(adev, query, reply);
+    audio_extn_fbsp_get_parameters(query, reply);
     if (adev->offload_effects_get_parameters != NULL)
         adev->offload_effects_get_parameters(query, reply);
 
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 123752a..8980026 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -298,6 +298,8 @@
 #define audio_extn_spkr_prot_stop_processing(snd_device)     (0)
 #define audio_extn_spkr_prot_is_enabled() (false)
 #define audio_extn_spkr_prot_set_parameters(parms, value, len)   (0)
+#define audio_extn_fbsp_set_parameters(parms)   (0)
+#define audio_extn_fbsp_get_parameters(query, reply)   (0)
 #else
 void audio_extn_spkr_prot_init(void *adev);
 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
@@ -306,6 +308,9 @@
 void audio_extn_spkr_prot_calib_cancel(void *adev);
 void audio_extn_spkr_prot_set_parameters(struct str_parms *parms,
                                          char *value, int len);
+int audio_extn_fbsp_set_parameters(struct str_parms *parms);
+int audio_extn_fbsp_get_parameters(struct str_parms *query,
+                                   struct str_parms *reply);
 #endif
 
 #ifndef COMPRESS_CAPTURE_ENABLED
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 2a246cd..a9512a0 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -103,6 +103,12 @@
 #define AUDIO_PARAMETER_KEY_SPKR_TZ_1     "spkr_1_tz_name"
 #define AUDIO_PARAMETER_KEY_SPKR_TZ_2     "spkr_2_tz_name"
 
+#define AUDIO_PARAMETER_KEY_FBSP_TRIGGER_SPKR_CAL   "trigger_spkr_cal"
+#define AUDIO_PARAMETER_KEY_FBSP_GET_SPKR_CAL       "get_spkr_cal"
+#define AUDIO_PARAMETER_KEY_FBSP_CFG_WAIT_TIME      "fbsp_cfg_wait_time"
+#define AUDIO_PARAMETER_KEY_FBSP_CFG_FTM_TIME       "fbsp_cfg_ftm_time"
+#define AUDIO_PARAMETER_KEY_FBSP_GET_FTM_PARAM      "get_ftm_param"
+
 /*Modes of Speaker Protection*/
 enum speaker_protection_mode {
     SPKR_PROTECTION_DISABLED = -1,
@@ -138,6 +144,9 @@
     bool wsa_found;
     int spkr_1_tzn;
     int spkr_2_tzn;
+    bool trigger_cal;
+    pthread_mutex_t cal_wait_cond_mutex;
+    pthread_cond_t cal_wait_condition;
 };
 
 static struct pcm_config pcm_config_skr_prot = {
@@ -274,14 +283,15 @@
         ALOGE("%s: Invalid params", __func__);
         return true;
     }
-     if (handle.spkr_in_use) {
+    if (handle.spkr_in_use) {
         *sec = 0;
-         return true;
-     } else {
-         clock_gettime(CLOCK_BOOTTIME, &temp);
-         *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
-         return false;
-     }
+        handle.trigger_cal = false;
+        return true;
+    } else {
+        clock_gettime(CLOCK_BOOTTIME, &temp);
+        *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
+        return false;
+    }
 }
 
 
@@ -537,15 +547,6 @@
                 ALOGD("%s: spkr_prot_thread calib Success R0 %d %d",
                  __func__, status.r0[SP_V2_SPKR_1], status.r0[SP_V2_SPKR_2]);
                 FILE *fp;
-
-                vi_feed_no_channels = vi_feed_get_channels(adev);
-                ALOGD("%s: vi_feed_no_channels %d", __func__, vi_feed_no_channels);
-                if (vi_feed_no_channels < 0) {
-                    ALOGE("%s: no of channels negative !!", __func__);
-                    /* limit the number of channels to 2*/
-                    vi_feed_no_channels = 2;
-                }
-
                 fp = fopen(CALIB_FILE,"wb");
                 if (!fp) {
                     ALOGE("%s: spkr_prot_thread File open failed %s",
@@ -636,6 +637,19 @@
     return status.status;
 }
 
+static void spkr_calibrate_wait()
+{
+    struct timespec ts;
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += WAKEUP_MIN_IDLE_CHECK;
+    ts.tv_nsec = 0;
+    pthread_mutex_lock(&handle.cal_wait_cond_mutex);
+    pthread_cond_timedwait(&handle.cal_wait_condition,
+                           &handle.cal_wait_cond_mutex, &ts);
+    pthread_mutex_unlock(&handle.cal_wait_cond_mutex);
+}
+
 static void* spkr_calibration_thread()
 {
     unsigned long sec = 0;
@@ -689,14 +703,6 @@
     if (fp) {
         int i;
         bool spkr_calibrated = true;
-        /* HAL for speaker protection is always calibrating for stereo usecase*/
-        vi_feed_no_channels = vi_feed_get_channels(adev);
-        ALOGD("%s: vi_feed_no_channels %d", __func__, vi_feed_no_channels);
-        if (vi_feed_no_channels < 0) {
-            ALOGE("%s: no of channels negative !!", __func__);
-            /* limit the number of channels to 2*/
-            vi_feed_no_channels = 2;
-        }
         for (i = 0; i < vi_feed_no_channels; i++) {
             fread(&protCfg.r0[i], sizeof(protCfg.r0[i]), 1, fp);
             fread(&protCfg.t0[i], sizeof(protCfg.t0[i]), 1, fp);
@@ -741,13 +747,13 @@
             if (is_speaker_in_use(&sec)) {
                 ALOGV("%s: WSA Speaker in use retry calibration", __func__);
                 pthread_mutex_unlock(&adev->lock);
-                sleep(WAKEUP_MIN_IDLE_CHECK);
+                spkr_calibrate_wait();
                 continue;
             } else {
                 ALOGD("%s: wsa speaker idle %ld,minimum time %ld", __func__, sec, min_idle_time);
-                if (sec < min_idle_time) {
+                if (!(sec > min_idle_time || handle.trigger_cal)) {
                     pthread_mutex_unlock(&adev->lock);
-                    sleep(WAKEUP_MIN_IDLE_CHECK);
+                    spkr_calibrate_wait();
                     continue;
                }
                goahead = true;
@@ -755,7 +761,7 @@
            if (!list_empty(&adev->usecase_list)) {
                 ALOGD("%s: Usecase active re-try calibration", __func__);
                 pthread_mutex_unlock(&adev->lock);
-                sleep(WAKEUP_MIN_IDLE_CHECK);
+                spkr_calibrate_wait();
                 continue;
            }
            if (goahead) {
@@ -776,7 +782,7 @@
                    if (t0_spk_1 < TZ_TEMP_MIN_THRESHOLD ||
                        t0_spk_1 > TZ_TEMP_MAX_THRESHOLD) {
                        pthread_mutex_unlock(&adev->lock);
-                       sleep(WAKEUP_MIN_IDLE_CHECK);
+                       spkr_calibrate_wait();
                        continue;
                    }
                    ALOGD("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
@@ -799,7 +805,7 @@
                    if (t0_spk_2 < TZ_TEMP_MIN_THRESHOLD ||
                        t0_spk_2 > TZ_TEMP_MAX_THRESHOLD) {
                        pthread_mutex_unlock(&adev->lock);
-                       sleep(WAKEUP_MIN_IDLE_CHECK);
+                       spkr_calibrate_wait();
                        continue;
                    }
                    ALOGD("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
@@ -836,12 +842,12 @@
         if (is_speaker_in_use(&sec)) {
             ALOGV("%s: Speaker in use retry calibration", __func__);
             pthread_mutex_unlock(&adev->lock);
-            sleep(WAKEUP_MIN_IDLE_CHECK);
+            spkr_calibrate_wait();
             continue;
         } else {
-            if (sec < min_idle_time) {
+            if (!(sec > min_idle_time || handle.trigger_cal)) {
                 pthread_mutex_unlock(&adev->lock);
-                sleep(WAKEUP_MIN_IDLE_CHECK);
+                spkr_calibrate_wait();
                 continue;
             }
             goahead = true;
@@ -850,7 +856,7 @@
             ALOGD("%s: Usecase active re-try calibration", __func__);
             goahead = false;
             pthread_mutex_unlock(&adev->lock);
-            sleep(WAKEUP_MIN_IDLE_CHECK);
+            spkr_calibrate_wait();
             continue;
         }
         if (goahead) {
@@ -923,6 +929,319 @@
           tz_names.spkr_1_name, tz_names.spkr_2_name);
 }
 
+static int spkr_vi_channels(struct audio_device *adev)
+{
+    int vi_channels;
+
+    vi_channels = vi_feed_get_channels(adev);
+    ALOGD("%s: vi_channels %d", __func__, vi_channels);
+    if (vi_channels < 0 || vi_channels > SP_V2_NUM_MAX_SPKRS) {
+        /* limit the number of channels to SP_V2_NUM_MAX_SPKRS */
+        vi_channels = SP_V2_NUM_MAX_SPKRS;
+    }
+    return vi_channels;
+}
+
+static void get_spkr_prot_thermal_cal(char *param)
+{
+    int i, status = 0;
+    int r0[SP_V2_NUM_MAX_SPKRS] = {0}, t0[SP_V2_NUM_MAX_SPKRS] = {0};
+    double dr0[SP_V2_NUM_MAX_SPKRS] = {0}, dt0[SP_V2_NUM_MAX_SPKRS] = {0};
+
+    FILE *fp = fopen(CALIB_FILE,"rb");
+    if (fp) {
+        for (i = 0; i < vi_feed_no_channels; i++) {
+            fread(&r0[i], sizeof(int), 1, fp);
+            fread(&t0[i], sizeof(int), 1, fp);
+            /* Convert from ADSP format to readable format */
+            dr0[i] = ((double)r0[i])/(1 << 24);
+            dt0[i] = ((double)t0[i])/(1 << 6);
+        }
+        ALOGV("%s: R0= %lf, %lf, T0= %lf, %lf",
+              __func__, dr0[0], dr0[1], dt0[0], dt0[1]);
+        fclose(fp);
+    } else {
+        ALOGE("%s: failed to open cal file\n", __func__);
+        status = -EINVAL;
+    }
+    sprintf(param, "SpkrCalStatus: %d; R0: %lf, %lf; T0: %lf, %lf",
+            status, dr0[SP_V2_SPKR_1], dr0[SP_V2_SPKR_2],
+            dt0[SP_V2_SPKR_1], dt0[SP_V2_SPKR_2]);
+    ALOGD("%s:: param = %s\n", __func__, param);
+
+    return;
+}
+
+#ifdef MSM_SPKR_PROT_IN_FTM_MODE
+
+static int set_spkr_prot_ftm_cfg(int wait_time, int ftm_time)
+{
+    int ret = 0;
+    struct audio_cal_sp_th_vi_ftm_cfg th_cal_data;
+    struct audio_cal_sp_ex_vi_ftm_cfg ex_cal_data;
+
+    int cal_fd = open("/dev/msm_audio_cal",O_RDWR | O_NONBLOCK);
+    if (cal_fd < 0) {
+        ALOGE("%s: open msm_acdb failed", __func__);
+        ret = -ENODEV;
+        goto done;
+    }
+
+    memset(&th_cal_data, 0, sizeof(th_cal_data));
+    th_cal_data.hdr.data_size = sizeof(th_cal_data);
+    th_cal_data.hdr.version = VERSION_0_0;
+    th_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE;
+    th_cal_data.hdr.cal_type_size = sizeof(th_cal_data.cal_type);
+    th_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    th_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    th_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_1] = wait_time;
+    th_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_2] = wait_time;
+    th_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_1] = ftm_time;
+    th_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_2] = ftm_time;
+    th_cal_data.cal_type.cal_info.mode = MSM_SPKR_PROT_IN_FTM_MODE; // FTM mode
+    th_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_SET_CALIBRATION, &th_cal_data))
+        ALOGE("%s: failed to set TH VI FTM_CFG, errno = %d", __func__, errno);
+
+    memset(&ex_cal_data, 0, sizeof(ex_cal_data));
+    ex_cal_data.hdr.data_size = sizeof(ex_cal_data);
+    ex_cal_data.hdr.version = VERSION_0_0;
+    ex_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE;
+    ex_cal_data.hdr.cal_type_size = sizeof(ex_cal_data.cal_type);
+    ex_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    ex_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    ex_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_1] = wait_time;
+    ex_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_2] = wait_time;
+    ex_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_1] = ftm_time;
+    ex_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_2] = ftm_time;
+    ex_cal_data.cal_type.cal_info.mode = MSM_SPKR_PROT_IN_FTM_MODE; // FTM mode
+    ex_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_SET_CALIBRATION, &ex_cal_data))
+        ALOGE("%s: failed to set EX VI FTM_CFG, ret = %d", __func__, errno);
+
+    if (cal_fd > 0)
+        close(cal_fd);
+done:
+    return ret;
+}
+
+static void get_spkr_prot_ftm_param(char *param)
+{
+    struct audio_cal_sp_th_vi_param th_vi_cal_data;
+    struct audio_cal_sp_ex_vi_param ex_vi_cal_data;
+    int i;
+    int ftm_status[SP_V2_NUM_MAX_SPKRS];
+    double rdc[SP_V2_NUM_MAX_SPKRS], temp[SP_V2_NUM_MAX_SPKRS];
+    double f[SP_V2_NUM_MAX_SPKRS], r[SP_V2_NUM_MAX_SPKRS], q[SP_V2_NUM_MAX_SPKRS];
+
+    int cal_fd = open("/dev/msm_audio_cal",O_RDWR | O_NONBLOCK);
+    if (cal_fd < 0) {
+        ALOGE("%s: open msm_acdb failed", __func__);
+        goto done;
+    }
+
+    memset(&th_vi_cal_data, 0, sizeof(th_vi_cal_data));
+    th_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_1] = -EINVAL;
+    th_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_2] = -EINVAL;
+    th_vi_cal_data.hdr.data_size = sizeof(th_vi_cal_data);
+    th_vi_cal_data.hdr.version = VERSION_0_0;
+    th_vi_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE;
+    th_vi_cal_data.hdr.cal_type_size = sizeof(th_vi_cal_data.cal_type);
+    th_vi_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    th_vi_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    th_vi_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_GET_CALIBRATION, &th_vi_cal_data))
+        ALOGE("%s: Error %d in getting th_vi_cal_data", __func__, errno);
+
+    memset(&ex_vi_cal_data, 0, sizeof(ex_vi_cal_data));
+    ex_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_1] = -EINVAL;
+    ex_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_2] = -EINVAL;
+    ex_vi_cal_data.hdr.data_size = sizeof(ex_vi_cal_data);
+    ex_vi_cal_data.hdr.version = VERSION_0_0;
+    ex_vi_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE;
+    ex_vi_cal_data.hdr.cal_type_size = sizeof(ex_vi_cal_data.cal_type);
+    ex_vi_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    ex_vi_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    ex_vi_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_GET_CALIBRATION, &ex_vi_cal_data))
+        ALOGE("%s: Error %d in getting ex_vi_cal_data", __func__, errno);
+
+    for (i = 0; i < vi_feed_no_channels; i++) {
+        /* Convert from ADSP format to readable format */
+        rdc[i] = ((double)th_vi_cal_data.cal_type.cal_info.r_dc_q24[i])/(1<<24);
+        temp[i] = ((double)th_vi_cal_data.cal_type.cal_info.temp_q22[i])/(1<<22);
+        f[i] = ((double)ex_vi_cal_data.cal_type.cal_info.freq_q20[i])/(1<<20);
+        r[i] = ((double)ex_vi_cal_data.cal_type.cal_info.resis_q24[i])/(1<<24);
+        q[i] = ((double)ex_vi_cal_data.cal_type.cal_info.qmct_q24[i])/(1<<24);
+
+        if (th_vi_cal_data.cal_type.cal_info.status[i] == 0 &&
+            ex_vi_cal_data.cal_type.cal_info.status[i] == 0) {
+            ftm_status[i] = 0;
+        } else if (th_vi_cal_data.cal_type.cal_info.status[i] == -EAGAIN &&
+                   ex_vi_cal_data.cal_type.cal_info.status[i] == -EAGAIN) {
+            ftm_status[i] = -EAGAIN;
+        } else {
+            ftm_status[i] = -EINVAL;
+        }
+    }
+    sprintf(param, "SpkrParamStatus: %d, %d; Rdc: %lf, %lf; Temp: %lf, %lf;"
+            " Freq: %lf, %lf; Rect: %lf, %lf; Qmct: %lf, %lf",
+            ftm_status[SP_V2_SPKR_1], ftm_status[SP_V2_SPKR_2],
+            rdc[SP_V2_SPKR_1], rdc[SP_V2_SPKR_2], temp[SP_V2_SPKR_1],
+            temp[SP_V2_SPKR_2], f[SP_V2_SPKR_1], f[SP_V2_SPKR_2],
+            r[SP_V2_SPKR_1], r[SP_V2_SPKR_2], q[SP_V2_SPKR_1], q[SP_V2_SPKR_2]);
+    ALOGD("%s:: param = %s\n", __func__, param);
+
+    if (cal_fd > 0)
+        close(cal_fd);
+done:
+    return;
+}
+
+#else
+
+static void get_spkr_prot_ftm_param(char *param __unused)
+{
+
+    ALOGD("%s: not supported", __func__);
+    return;
+}
+
+static int set_spkr_prot_ftm_cfg(int wait_time __unused, int ftm_time __unused)
+{
+    ALOGD("%s: not supported", __func__);
+    return -ENOSYS;
+}
+#endif
+
+static void spkr_calibrate_signal()
+{
+    pthread_mutex_lock(&handle.cal_wait_cond_mutex);
+    pthread_cond_signal(&handle.cal_wait_condition);
+    pthread_mutex_unlock(&handle.cal_wait_cond_mutex);
+}
+
+int audio_extn_fbsp_set_parameters(struct str_parms *parms)
+{
+    int ret= 0 , err;
+    char *str;
+    char *value = NULL;
+    int val, len, i;
+    char *test_r = NULL;
+    char *cfg_str;
+    int wait_time, ftm_time;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    if(kv_pairs == NULL) {
+        ret = -ENOMEM;
+        ALOGE("[%s] key-value pair is NULL",__func__);
+        goto done;
+    }
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    len = strlen(kv_pairs);
+    value = (char*)calloc(len, sizeof(char));
+    if(value == NULL) {
+        ret = -ENOMEM;
+        ALOGE("[%s] failed to allocate memory",__func__);
+        goto done;
+    }
+    if (!handle.spkr_prot_enable) {
+        ALOGD("%s: Speaker protection disabled", __func__);
+        goto done;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FBSP_TRIGGER_SPKR_CAL, value,
+                            len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FBSP_TRIGGER_SPKR_CAL);
+        if ((strcmp(value, "true") == 0) || (strcmp(value, "yes") == 0)) {
+            handle.trigger_cal = true;
+            spkr_calibrate_signal();
+        }
+        goto done;
+    }
+
+    /* Expected key value pair is in below format:
+     * AUDIO_PARAM_FBSP_CFG_WAIT_TIME=waittime;AUDIO_PARAM_FBSP_CFG_FTM_TIME=ftmtime;
+     * Parse waittime and ftmtime from it.
+     */
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_WAIT_TIME,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_WAIT_TIME);
+        cfg_str = strtok_r(value, ";", &test_r);
+        if (cfg_str == NULL) {
+            ALOGE("%s: incorrect wait time cfg_str", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+        wait_time = atoi(cfg_str);
+        ALOGV(" %s: cfg_str = %s, wait_time = %d", __func__, cfg_str, wait_time);
+
+        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_FTM_TIME,
+                                value, len);
+        if (err >= 0) {
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_FTM_TIME);
+            cfg_str = strtok_r(value, ";", &test_r);
+            if (cfg_str == NULL) {
+                ALOGE("%s: incorrect ftm time cfg_str", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            ftm_time = atoi(cfg_str);
+            ALOGV(" %s: cfg_str = %s, ftm_time = %d", __func__, cfg_str, ftm_time);
+
+            ret = set_spkr_prot_ftm_cfg(wait_time, ftm_time);
+            if (ret < 0) {
+                ALOGE("%s: set_spkr_prot_ftm_cfg failed", __func__);
+                goto done;
+            }
+        }
+    }
+
+done:
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+
+    if(kv_pairs != NULL)
+        free(kv_pairs);
+    if(value != NULL)
+        free(value);
+
+    return ret;
+}
+
+int audio_extn_fbsp_get_parameters(struct str_parms *query,
+                                   struct str_parms *reply)
+{
+    int err = 0;
+    char value[1024] = {0};
+
+    if (!handle.spkr_prot_enable) {
+        ALOGD("%s: Speaker protection disabled", __func__);
+        return -EINVAL;
+    }
+
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FBSP_GET_SPKR_CAL, value,
+                                                          sizeof(value));
+    if (err >= 0) {
+        get_spkr_prot_thermal_cal(value);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FBSP_GET_SPKR_CAL, value);
+    }
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FBSP_GET_FTM_PARAM, value,
+                            sizeof(value));
+    if (err >= 0) {
+        get_spkr_prot_ftm_param(value);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FBSP_GET_FTM_PARAM, value);
+    }
+done:
+    return err;
+}
+
 void audio_extn_spkr_prot_init(void *adev)
 {
     char value[PROPERTY_VALUE_MAX];
@@ -944,6 +1263,11 @@
     handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
     handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
     handle.spkr_prot_t0 = -1;
+    handle.trigger_cal = false;
+    /* HAL for speaker protection is always calibrating for stereo usecase*/
+    vi_feed_no_channels = spkr_vi_channels(adev);
+    pthread_cond_init(&handle.cal_wait_condition, NULL);
+    pthread_mutex_init(&handle.cal_wait_cond_mutex, NULL);
 
     if (is_wsa_present()) {
         if (platform_spkr_prot_is_wsa_analog_mode(adev) == 1) {