Browse Source

dsp: q6afe: Add v-validation support for speaker

With speaker protection in v-validation mode, speaker
samples can be tested in early factory mode. Add
support for v-validation feature from driver.

Change-Id: I92493d6d2784cf4dd58021746bffe01180f89d23
Signed-off-by: Laxminath Kasam <[email protected]>
Laxminath Kasam 6 years ago
parent
commit
2e13d95506
3 changed files with 240 additions and 14 deletions
  1. 6 2
      dsp/audio_cal_utils.c
  2. 186 12
      dsp/q6afe.c
  3. 48 0
      include/dsp/apr_audio-v2.h

+ 6 - 2
dsp/audio_cal_utils.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
  */
 #include <linux/slab.h>
 #include <linux/fs.h>
@@ -16,6 +16,7 @@ static int unmap_memory(struct cal_type_data *cal_type,
 size_t get_cal_info_size(int32_t cal_type)
 {
 	size_t size = 0;
+	size_t size1 = 0, size2 = 0;
 
 	switch (cal_type) {
 	case CVP_VOC_RX_TOPOLOGY_CAL_TYPE:
@@ -93,8 +94,11 @@ size_t get_cal_info_size(int32_t cal_type)
 		 * Since get and set parameter structures are different in size
 		 * use the maximum size of get and set parameter structure
 		 */
-		size = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg),
+		size1 = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg),
 			   sizeof(struct audio_cal_info_sp_th_vi_param));
+		size2 = max(sizeof(struct audio_cal_info_sp_th_vi_v_vali_cfg),
+			   sizeof(struct audio_cal_info_sp_th_vi_v_vali_param));
+		size = max(size1, size2);
 		break;
 	case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE:
 		/*

+ 186 - 12
dsp/q6afe.c

@@ -59,6 +59,16 @@ static char fbsp_state[MAX_FBSP_STATE][50] = {
 	[FBSP_FAILED] = "failed"
 };
 
+enum v_vali_state {
+	V_VALI_FAILED,
+	V_VALI_SUCCESS,
+	V_VALI_INCORRECT_OP_MODE,
+	V_VALI_INACTIVE,
+	V_VALI_WARMUP,
+	V_VALI_IN_PROGRESS,
+	MAX_V_VALI_STATE
+};
+
 enum {
 	USE_CALIBRATED_R0TO,
 	USE_SAFE_R0TO
@@ -72,7 +82,8 @@ enum {
 enum {
 	Q6AFE_MSM_SPKR_PROCESSING = 0,
 	Q6AFE_MSM_SPKR_CALIBRATION,
-	Q6AFE_MSM_SPKR_FTM_MODE
+	Q6AFE_MSM_SPKR_FTM_MODE,
+	Q6AFE_MSM_SPKR_V_VALI_MODE
 };
 
 enum {
@@ -124,8 +135,10 @@ struct afe_ctl {
 	struct audio_cal_info_spk_prot_cfg	prot_cfg;
 	struct afe_spkr_prot_calib_get_resp	calib_data;
 	struct audio_cal_info_sp_th_vi_ftm_cfg	th_ftm_cfg;
+	struct audio_cal_info_sp_th_vi_v_vali_cfg	v_vali_cfg;
 	struct audio_cal_info_sp_ex_vi_ftm_cfg	ex_ftm_cfg;
 	struct afe_sp_th_vi_get_param_resp	th_vi_resp;
+	struct afe_sp_th_vi_v_vali_get_param_resp	th_vi_v_vali_resp;
 	struct afe_sp_ex_vi_get_param_resp	ex_vi_resp;
 	struct afe_av_dev_drift_get_param_resp	av_dev_drift_resp;
 	struct afe_doa_tracking_mon_get_param_resp	doa_tracking_mon_resp;
@@ -364,6 +377,10 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload,
 		expected_size += sizeof(struct afe_sp_th_vi_ftm_params);
 		data_dest = (u32 *) &this_afe.th_vi_resp;
 		break;
+	case AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_PARAMS:
+		expected_size += sizeof(struct afe_sp_th_vi_v_vali_params);
+		data_dest = (u32 *) &this_afe.th_vi_v_vali_resp;
+		break;
 	case AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS:
 		expected_size += sizeof(struct afe_sp_ex_vi_ftm_params);
 		data_dest = (u32 *) &this_afe.ex_vi_resp;
@@ -1606,10 +1623,12 @@ static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id,
 		break;
 	/*
 	 * AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2 is same as
-	 * AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG
+	 * AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG. V_VALI_CFG uses
+	 * same module TH_VI.
 	 */
 	case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2:
 	case AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG:
+	case AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_CFG:
 		param_info.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
 		break;
 	case AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG:
@@ -1737,6 +1756,10 @@ static void afe_send_cal_spkr_prot_tx(int port_id)
 		if (this_afe.th_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE)
 			afe_spk_config.vi_proc_cfg.operation_mode =
 					    Q6AFE_MSM_SPKR_FTM_MODE;
+		else if (this_afe.v_vali_cfg.mode ==
+					MSM_SPKR_PROT_IN_V_VALI_MODE)
+			afe_spk_config.vi_proc_cfg.operation_mode =
+					    Q6AFE_MSM_SPKR_V_VALI_MODE;
 		afe_spk_config.vi_proc_cfg.minor_version = 1;
 		afe_spk_config.vi_proc_cfg.r0_cali_q24[SP_V2_SPKR_1] =
 			(uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_1];
@@ -1789,6 +1812,25 @@ static void afe_send_cal_spkr_prot_tx(int port_id)
 					 &afe_spk_config))
 			pr_err("%s: th vi ftm cfg failed\n", __func__);
 		this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
+	} else if ((this_afe.v_vali_cfg.mode ==
+			MSM_SPKR_PROT_IN_V_VALI_MODE) &&
+		   (this_afe.vi_tx_port == port_id)) {
+		afe_spk_config.th_vi_v_vali_cfg.minor_version = 1;
+		afe_spk_config.th_vi_v_vali_cfg.wait_time_ms[SP_V2_SPKR_1] =
+			this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_1];
+		afe_spk_config.th_vi_v_vali_cfg.wait_time_ms[SP_V2_SPKR_2] =
+			this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_2];
+		afe_spk_config.th_vi_v_vali_cfg.vali_time_ms[SP_V2_SPKR_1] =
+			this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_1];
+		afe_spk_config.th_vi_v_vali_cfg.vali_time_ms[SP_V2_SPKR_2] =
+			this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_2];
+
+		if (afe_spk_prot_prepare(port_id, 0,
+					 AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_CFG,
+					 &afe_spk_config))
+			pr_err("%s: th vi v-vali cfg failed\n", __func__);
+
+		this_afe.v_vali_cfg.mode = MSM_SPKR_PROT_DISABLED;
 	}
 	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 
@@ -7453,6 +7495,46 @@ int q6afe_check_osr_clk_freq(u32 freq)
 }
 EXPORT_SYMBOL(q6afe_check_osr_clk_freq);
 
+static int afe_get_sp_th_vi_v_vali_data(
+		struct afe_sp_th_vi_v_vali_get_param *th_vi_v_vali)
+{
+	struct param_hdr_v3 param_hdr;
+	int port = SLIMBUS_4_TX;
+	int ret = -EINVAL;
+
+	if (!th_vi_v_vali) {
+		pr_err("%s: Invalid params\n", __func__);
+		goto done;
+	}
+	if (this_afe.vi_tx_port != -1)
+		port = this_afe.vi_tx_port;
+
+	memset(&param_hdr, 0, sizeof(param_hdr));
+
+	param_hdr.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
+	param_hdr.instance_id = INSTANCE_ID_0;
+	param_hdr.param_id = AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_PARAMS;
+	param_hdr.param_size = sizeof(struct afe_sp_th_vi_v_vali_params);
+
+	ret = q6afe_get_params(port, NULL, &param_hdr);
+	if (ret) {
+		pr_err("%s: Failed to get TH VI V-Vali data\n", __func__);
+		goto done;
+	}
+
+	th_vi_v_vali->pdata = param_hdr;
+	memcpy(&th_vi_v_vali->param, &this_afe.th_vi_v_vali_resp.param,
+		sizeof(this_afe.th_vi_v_vali_resp.param));
+	pr_debug("%s:  Vrms %d %d status %d %d\n", __func__,
+		 th_vi_v_vali->param.vrms_q24[SP_V2_SPKR_1],
+		 th_vi_v_vali->param.vrms_q24[SP_V2_SPKR_2],
+		 th_vi_v_vali->param.status[SP_V2_SPKR_1],
+		 th_vi_v_vali->param.status[SP_V2_SPKR_2]);
+	ret = 0;
+done:
+	return ret;
+}
+
 int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi)
 {
 	struct param_hdr_v3 param_hdr;
@@ -7952,21 +8034,57 @@ done:
 	return ret;
 }
 
+static int afe_set_cal_sp_th_vi_v_vali_cfg(int32_t cal_type, size_t data_size,
+					void *data)
+{
+	int ret = 0;
+	struct audio_cal_type_sp_th_vi_v_vali_cfg *cal_data = data;
+
+	if (cal_data == NULL || data_size != sizeof(*cal_data))
+		goto done;
+
+	memcpy(&this_afe.v_vali_cfg, &cal_data->cal_info,
+		sizeof(this_afe.v_vali_cfg));
+done:
+	return ret;
+}
+
 static int afe_set_cal_sp_th_vi_ftm_cfg(int32_t cal_type, size_t data_size,
 					void *data)
 {
 	int ret = 0;
 	struct audio_cal_type_sp_th_vi_ftm_cfg *cal_data = data;
 
-	if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
-	    cal_data == NULL ||
-	    data_size != sizeof(*cal_data))
+	if (cal_data == NULL || data_size != sizeof(*cal_data))
 		goto done;
 
-	pr_debug("%s: cal_type = %d\n", __func__, cal_type);
-	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 	memcpy(&this_afe.th_ftm_cfg, &cal_data->cal_info,
 		sizeof(this_afe.th_ftm_cfg));
+done:
+	return ret;
+}
+
+static int afe_set_cal_sp_th_vi_cfg(int32_t cal_type, size_t data_size,
+				    void *data)
+{
+	int ret = 0;
+	struct audio_cal_type_sp_th_vi_ftm_cfg *cal_data = data;
+	uint32_t mode;
+
+	if (cal_data == NULL ||
+	    this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
+		goto done;
+
+	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+	mode = cal_data->cal_info.mode;
+	pr_debug("%s: cal_type = %d, mode = %d\n", __func__, cal_type, mode);
+	if (mode == MSM_SPKR_PROT_IN_FTM_MODE) {
+		ret = afe_set_cal_sp_th_vi_ftm_cfg(cal_type,
+						data_size, data);
+	} else if (mode == MSM_SPKR_PROT_IN_V_VALI_MODE) {
+		ret = afe_set_cal_sp_th_vi_v_vali_cfg(cal_type,
+						data_size, data);
+	}
 	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 done:
 	return ret;
@@ -8017,6 +8135,41 @@ done:
 	return ret;
 }
 
+static int afe_get_cal_sp_th_vi_v_vali_param(int32_t cal_type, size_t data_size,
+					  void *data)
+{
+	int i, ret = 0;
+	struct audio_cal_type_sp_th_vi_v_vali_param *cal_data = data;
+	struct afe_sp_th_vi_v_vali_get_param th_vi_v_vali;
+
+	if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
+	    cal_data == NULL ||
+	    data_size != sizeof(*cal_data))
+		goto done;
+
+	for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+		cal_data->cal_info.status[i] = -EINVAL;
+		cal_data->cal_info.vrms_q24[i] = -1;
+	}
+	if (!afe_get_sp_th_vi_v_vali_data(&th_vi_v_vali)) {
+		for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+			pr_debug("%s: v-vali param status = %d\n",
+				  __func__, th_vi_v_vali.param.status[i]);
+			if (th_vi_v_vali.param.status[i] ==
+					V_VALI_IN_PROGRESS) {
+				cal_data->cal_info.status[i] = -EAGAIN;
+			} else if (th_vi_v_vali.param.status[i] ==
+					V_VALI_SUCCESS) {
+				cal_data->cal_info.status[i] = V_VALI_SUCCESS;
+				cal_data->cal_info.vrms_q24[i] =
+					th_vi_v_vali.param.vrms_q24[i];
+			}
+		}
+	}
+done:
+	return ret;
+}
+
 static int afe_get_cal_sp_th_vi_ftm_param(int32_t cal_type, size_t data_size,
 					  void *data)
 {
@@ -8024,13 +8177,11 @@ static int afe_get_cal_sp_th_vi_ftm_param(int32_t cal_type, size_t data_size,
 	struct audio_cal_type_sp_th_vi_param *cal_data = data;
 	struct afe_sp_th_vi_get_param th_vi;
 
-	pr_debug("%s: cal_type = %d\n", __func__, cal_type);
 	if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
 	    cal_data == NULL ||
 	    data_size != sizeof(*cal_data))
 		goto done;
 
-	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 	for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
 		cal_data->cal_info.status[i] = -EINVAL;
 		cal_data->cal_info.r_dc_q24[i] = -1;
@@ -8051,11 +8202,34 @@ static int afe_get_cal_sp_th_vi_ftm_param(int32_t cal_type, size_t data_size,
 			}
 		}
 	}
-	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 done:
 	return ret;
 }
 
+static int afe_get_cal_sp_th_vi_param(int32_t cal_type, size_t data_size,
+				      void *data)
+{
+	struct audio_cal_type_sp_th_vi_param *cal_data = data;
+	uint32_t mode;
+	int ret = 0;
+
+	if (cal_data == NULL ||
+	    this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
+		return 0;
+
+	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+	mode = cal_data->cal_info.mode;
+	pr_debug("%s: cal_type = %d,mode = %d\n", __func__, cal_type, mode);
+	if (mode == MSM_SPKR_PROT_IN_V_VALI_MODE)
+		ret = afe_get_cal_sp_th_vi_v_vali_param(cal_type,
+						data_size, data);
+	else
+		ret = afe_get_cal_sp_th_vi_ftm_param(cal_type,
+						data_size, data);
+	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+	return ret;
+}
+
 static int afe_get_cal_sp_ex_vi_ftm_param(int32_t cal_type, size_t data_size,
 					  void *data)
 {
@@ -8313,8 +8487,8 @@ static int afe_init_cal_data(void)
 		cal_utils_match_buf_num} },
 
 		{{AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
-		{NULL, NULL, NULL, afe_set_cal_sp_th_vi_ftm_cfg,
-		afe_get_cal_sp_th_vi_ftm_param, NULL} },
+		{NULL, NULL, NULL, afe_set_cal_sp_th_vi_cfg,
+		afe_get_cal_sp_th_vi_param, NULL} },
 		{NULL, NULL, cal_utils_match_buf_num} },
 
 		{{AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,

+ 48 - 0
include/dsp/apr_audio-v2.h

@@ -10468,6 +10468,8 @@ struct asm_mode_vi_proc_cfg {
 #define AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG	0x0001026B
 #define AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG	0x0001029F
 #define AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS	0x000102A0
+#define AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_CFG	0x000102BF
+#define AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_PARAMS	0x000102C0
 
 struct afe_sp_th_vi_mode_cfg {
 	uint32_t minor_version;
@@ -10557,6 +10559,51 @@ struct afe_sp_th_vi_get_param_resp {
 	struct afe_sp_th_vi_ftm_params param;
 } __packed;
 
+struct afe_sp_th_vi_v_vali_cfg {
+	uint32_t minor_version;
+	uint32_t wait_time_ms[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Wait time to heat up speaker before collecting statistics
+	 * for V validation mode in ms.
+	 * values 100 to 1000 ms
+	 */
+	uint32_t vali_time_ms[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * duration for which V VALIDATION statistics are collected in ms.
+	 * values 1000 to 3000 ms
+	 */
+} __packed;
+
+struct afe_sp_th_vi_v_vali_params {
+	uint32_t minor_version;
+	uint32_t vrms_q24[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Vrms value in q24 format
+	 * values [0 33554432] Q24 (0 - 2Vrms)
+	 */
+	uint32_t status[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * v-vali packet status
+	 * 0 - Failed.
+	 * 1 - Success.
+	 * 2 - Incorrect operation mode.This status is returned
+	 *     when GET_PARAM is called in non v-vali Mode
+	 * 3 - Inactive mode -- Port is not yet started.
+	 * 4 - Wait state. wait_time_ms has not yet elapsed
+	 * 5 - In progress state. ftm_time_ms has not yet elapsed.
+	 */
+} __packed;
+
+struct afe_sp_th_vi_v_vali_get_param {
+	struct param_hdr_v3 pdata;
+	struct afe_sp_th_vi_v_vali_params param;
+} __packed;
+
+struct afe_sp_th_vi_v_vali_get_param_resp {
+	uint32_t status;
+	struct param_hdr_v3 pdata;
+	struct afe_sp_th_vi_v_vali_params param;
+} __packed;
 
 #define AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI	0x0001026F
 #define AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG	0x000102A1
@@ -10641,6 +10688,7 @@ union afe_spkr_prot_config {
 	struct asm_mode_vi_proc_cfg mode_vi_proc_cfg;
 	struct afe_sp_th_vi_mode_cfg th_vi_mode_cfg;
 	struct afe_sp_th_vi_ftm_cfg th_vi_ftm_cfg;
+	struct afe_sp_th_vi_v_vali_cfg th_vi_v_vali_cfg;
 	struct afe_sp_ex_vi_mode_cfg ex_vi_mode_cfg;
 	struct afe_sp_ex_vi_ftm_cfg ex_vi_ftm_cfg;
 	struct afe_sp_rx_limiter_th_param limiter_th_cfg;