Browse Source

lsm: add support for SVA multi sound model

Add support in audio drivers to support multiple sound models
to be registered individually to the same module within a single
instance in ADSP.

Change-Id: I7d1abb206c7505ed10f0384b8286d5000416e1be
Signed-off-by: Xiaoyu Ye <[email protected]>
Xiaoyu Ye 5 years ago
parent
commit
18ab344528
4 changed files with 510 additions and 188 deletions
  1. 321 109
      asoc/msm-lsm-client.c
  2. 163 73
      dsp/q6lsm.c
  3. 19 4
      include/dsp/q6lsm.h
  4. 7 2
      include/uapi/audio/sound/lsm_params.h

+ 321 - 109
asoc/msm-lsm-client.c

@@ -499,38 +499,71 @@ static int msm_lsm_get_conf_levels(struct lsm_client *client,
 {
 	int rc = 0;
 
-	if (client->num_confidence_levels == 0) {
-		pr_debug("%s: no confidence levels provided\n",
-			__func__);
-		client->confidence_levels = NULL;
-		goto done;
-	}
+	if (client->num_sound_models != 0) {
+		if (client->num_keywords == 0) {
+			pr_debug("%s: no number of confidence_values provided\n",
+				 __func__);
+			client->multi_snd_model_confidence_levels = NULL;
+			goto done;
+		}
+
+		client->multi_snd_model_confidence_levels =
+			kzalloc((sizeof(uint32_t) * client->num_keywords),
+				 GFP_KERNEL);
+		if (!client->multi_snd_model_confidence_levels) {
+			pr_err("%s: No memory for confidence\n"
+				"levels num of level from user = %d\n",
+				__func__, client->num_keywords);
+				rc = -ENOMEM;
+				goto done;
+		}
 
-	client->confidence_levels =
-		kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
-			 GFP_KERNEL);
-	if (!client->confidence_levels) {
-		pr_err("%s: No memory for confidence\n"
-			"levels num of level from user = %d\n",
-			__func__, client->num_confidence_levels);
-			rc = -ENOMEM;
+		if (copy_from_user((u8 *)client->multi_snd_model_confidence_levels,
+				   conf_levels_ptr,
+				   sizeof(uint32_t) * client->num_keywords)) {
+			pr_err("%s: copy from user failed, number of keywords = %d\n",
+			       __func__, client->num_keywords);
+			rc = -EFAULT;
+			goto copy_err;
+		}
+	} else {
+		if (client->num_confidence_levels == 0) {
+			pr_debug("%s: no confidence levels provided\n",
+				 __func__);
+			client->confidence_levels = NULL;
 			goto done;
-	}
+		}
 
-	if (copy_from_user(client->confidence_levels,
-			   conf_levels_ptr,
-			   client->num_confidence_levels)) {
-		pr_err("%s: copy from user failed, size = %d\n",
-		       __func__, client->num_confidence_levels);
-		rc = -EFAULT;
-		goto copy_err;
-	}
+		client->confidence_levels =
+			kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
+				 GFP_KERNEL);
+		if (!client->confidence_levels) {
+			pr_err("%s: No memory for confidence\n"
+				"levels num of level from user = %d\n",
+				__func__, client->num_confidence_levels);
+				rc = -ENOMEM;
+				goto done;
+		}
 
+		if (copy_from_user(client->confidence_levels,
+				   conf_levels_ptr,
+				   client->num_confidence_levels)) {
+			pr_err("%s: copy from user failed, size = %d\n",
+			       __func__, client->num_confidence_levels);
+			rc = -EFAULT;
+			goto copy_err;
+		}
+	}
 	return rc;
 
 copy_err:
-	kfree(client->confidence_levels);
-	client->confidence_levels = NULL;
+	if (client->num_sound_models != 0) {
+		kfree(client->multi_snd_model_confidence_levels);
+		client->multi_snd_model_confidence_levels = NULL;
+	} else {
+		kfree(client->confidence_levels);
+		client->confidence_levels = NULL;
+	}
 done:
 	return rc;
 
@@ -652,35 +685,67 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int rc = 0;
 
-	if (p_info->param_size > MAX_NUM_CONFIDENCE) {
-		dev_err(rtd->dev,
-			"%s: invalid confidence levels %d\n",
-			__func__, p_info->param_size);
-		return -EINVAL;
-	}
+	if (p_info->param_type == LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS) {
+		if (p_info->param_size > MAX_KEYWORDS_SUPPORTED) {
+			dev_err(rtd->dev,
+				"%s: invalid number of snd_model keywords %d, the max is %d\n",
+				__func__, p_info->param_size, MAX_KEYWORDS_SUPPORTED);
+			return -EINVAL;
+		}
 
-	prtd->lsm_client->num_confidence_levels =
-			p_info->param_size;
-	rc = msm_lsm_get_conf_levels(prtd->lsm_client,
-				     p_info->param_data);
-	if (rc) {
-		dev_err(rtd->dev,
-			"%s: get_conf_levels failed, err = %d\n",
-			__func__, rc);
-		return rc;
-	}
+		prtd->lsm_client->num_keywords = p_info->param_size;
+		rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+					     p_info->param_data);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: get_conf_levels failed for snd_model %d, err = %d\n",
+				__func__, p_info->model_id, rc);
+			return rc;
+		}
 
-	rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
-				 prtd->lsm_client->confidence_levels,
-				 LSM_MIN_CONFIDENCE_LEVELS);
-	if (rc)
-		dev_err(rtd->dev,
-			"%s: Failed to set min_conf_levels, err = %d\n",
-			__func__, rc);
+		rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+					 prtd->lsm_client->multi_snd_model_confidence_levels,
+					 LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS);
+		if (rc)
+			dev_err(rtd->dev,
+				"%s: Failed to set multi_snd_model_confidence_levels, err = %d\n",
+				__func__, rc);
 
-	if (prtd->lsm_client->confidence_levels) {
-		kfree(prtd->lsm_client->confidence_levels);
-		prtd->lsm_client->confidence_levels = NULL;
+		if (prtd->lsm_client->multi_snd_model_confidence_levels) {
+			kfree(prtd->lsm_client->multi_snd_model_confidence_levels);
+			prtd->lsm_client->multi_snd_model_confidence_levels = NULL;
+		}
+	} else {
+		if (p_info->param_size > MAX_NUM_CONFIDENCE) {
+			dev_err(rtd->dev,
+				"%s: invalid confidence levels %d\n",
+				__func__, p_info->param_size);
+			return -EINVAL;
+		}
+
+		prtd->lsm_client->num_confidence_levels =
+				p_info->param_size;
+		rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+					     p_info->param_data);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: get_conf_levels failed, err = %d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+					 prtd->lsm_client->confidence_levels,
+					 LSM_MIN_CONFIDENCE_LEVELS);
+		if (rc)
+			dev_err(rtd->dev,
+				"%s: Failed to set min_conf_levels, err = %d\n",
+				__func__, rc);
+
+		if (prtd->lsm_client->confidence_levels) {
+			kfree(prtd->lsm_client->confidence_levels);
+			prtd->lsm_client->confidence_levels = NULL;
+		}
 	}
 	return rc;
 }
@@ -691,66 +756,166 @@ static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int rc = 0;
+	int rc = 0, stage_idx = p_info->stage_idx;
 	struct lsm_sound_model *sm = NULL;
 	size_t offset = sizeof(union param_hdrs);
+	struct lsm_client *client = prtd->lsm_client;
 
-	rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
-				       p_info->param_size, p_info);
-	if (rc) {
-		dev_err(rtd->dev,
-			"%s: snd_model buf alloc failed, size = %d\n",
-			__func__, p_info->param_size);
-		return rc;
-	}
+	if (p_info->model_id != 0 &&
+	    p_info->param_type == LSM_REG_MULTI_SND_MODEL) {
+		sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+		if (sm == NULL) {
+			dev_err(rtd->dev, "%s: snd_model kzalloc failed\n", __func__);
+			return -ENOMEM;
+		}
 
-	q6lsm_sm_set_param_data(prtd->lsm_client, p_info, &offset);
+		INIT_LIST_HEAD(&sm->list);
 
-	/*
-	 * For set_param, advance the sound model data with the
-	 * number of bytes required by param_data.
-	 */
+		rc = q6lsm_snd_model_buf_alloc(client, p_info->param_size, p_info, sm);
+		if (rc) {
+			dev_err(rtd->dev, "%s: snd_model buf alloc failed, size = %d\n",
+				__func__, p_info->param_size);
+			goto err_buf_alloc;
+		}
 
-	sm = &prtd->lsm_client->stage_cfg[p_info->stage_idx].sound_model;
-	if (copy_from_user((u8 *)sm->data + offset,
-			   p_info->param_data, p_info->param_size)) {
-		dev_err(rtd->dev,
-			"%s: copy_from_user for snd_model failed, size = %d\n",
-			__func__, p_info->param_size);
-		rc = -EFAULT;
-		goto err_copy;
-	}
-	rc = q6lsm_set_one_param(prtd->lsm_client, p_info, NULL,
-				 LSM_REG_SND_MODEL);
-	if (rc) {
+		q6lsm_sm_set_param_data(client, p_info, &offset, sm);
+
+		/*
+		 * For set_param, advance the sound model data with the
+		 * number of bytes required by param_data.
+		 */
+		if (copy_from_user((u8 *)sm->data + offset,
+			p_info->param_data, p_info->param_size)) {
+			dev_err(rtd->dev,
+				"%s: copy_from_user for snd_model %d failed, size = %d\n",
+				__func__, p_info->model_id, p_info->param_size);
+			rc = -EFAULT;
+			goto err_copy;
+		}
+		/* Add this sound model to the list of multi sound models */
+		list_add_tail(&sm->list, &client->stage_cfg[stage_idx].sound_models);
+
+		rc = q6lsm_set_one_param(client, p_info, NULL,
+					 LSM_REG_MULTI_SND_MODEL);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: Failed to register snd_model %d, err = %d\n",
+				__func__, p_info->model_id, rc);
+			goto err_copy;
+		}
+
+		client->num_sound_models++;
+		dev_dbg(rtd->dev,
+			"%s: registered snd_model: %d, total num of snd_model: %d\n",
+			__func__, p_info->model_id, client->num_sound_models);
+	} else if (p_info->model_id == 0 &&
+		   p_info->param_type == LSM_REG_SND_MODEL) {
+		sm = &client->stage_cfg[stage_idx].sound_model;
+
+		rc = q6lsm_snd_model_buf_alloc(client, p_info->param_size, p_info, sm);
+		if (rc) {
+			dev_err(rtd->dev, "%s: snd_model buf alloc failed, size = %d\n",
+				__func__, p_info->param_size);
+			return rc;
+		}
+
+		q6lsm_sm_set_param_data(client, p_info, &offset, sm);
+
+		/*
+		 * For set_param, advance the sound model data with the
+		 * number of bytes required by param_data.
+		 */
+
+		if (copy_from_user((u8 *)sm->data + offset,
+		    p_info->param_data, p_info->param_size)) {
+			dev_err(rtd->dev,
+				"%s: copy_from_user for snd_model failed, size = %d\n",
+				__func__, p_info->param_size);
+			rc = -EFAULT;
+			goto err_copy;
+		}
+		rc = q6lsm_set_one_param(client, p_info, NULL, LSM_REG_SND_MODEL);
+		if (rc) {
+			dev_err(rtd->dev, "%s: Failed to register snd_model, err = %d\n",
+				__func__, rc);
+			goto err_copy;
+		}
+	} else {
 		dev_err(rtd->dev,
-			"%s: Failed to set sound_model, err = %d\n",
-			__func__, rc);
-		goto err_copy;
+			"%s: snd_model id %d is invalid for param type %d\n",
+			__func__, p_info->model_id, p_info->param_type);
 	}
 	return rc;
 
 err_copy:
-	q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
+	q6lsm_snd_model_buf_free(client, p_info, sm);
+err_buf_alloc:
+	if (p_info->model_id != 0) {
+		list_del(&sm->list);
+		kfree(sm);
+		sm = NULL;
+	}
 	return rc;
 }
 
 static int msm_lsm_dereg_model(struct snd_pcm_substream *substream,
-		struct lsm_params_info_v2 *p_info)
+			struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct lsm_sound_model *sm = NULL;
+	struct lsm_client *client = prtd->lsm_client;
 	int rc = 0;
 
-	rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
-				 NULL, LSM_DEREG_SND_MODEL);
-	if (rc)
-		dev_err(rtd->dev,
-			"%s: Failed to set det_mode param, err = %d\n",
-			__func__, rc);
+	if (p_info->model_id != 0 &&
+		p_info->param_type == LSM_DEREG_MULTI_SND_MODEL) {
+		list_for_each_entry(sm,
+				   &client->stage_cfg[p_info->stage_idx].sound_models,
+				   list) {
+			dev_dbg(rtd->dev,
+				"%s: current snd_model: %d, looking for snd_model %d\n",
+				 __func__, sm->model_id, p_info->model_id);
+			if (sm->model_id == p_info->model_id)
+				break;
+		}
 
-	q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
+		if (sm->model_id == p_info->model_id) {
+			rc = q6lsm_set_one_param(client, p_info, NULL,
+						 LSM_DEREG_MULTI_SND_MODEL);
+			if (rc)
+				dev_err(rtd->dev,
+					"%s: Failed to deregister snd_model %d, err = %d\n",
+					__func__, p_info->model_id, rc);
+
+			q6lsm_snd_model_buf_free(client, p_info, sm);
+			list_del(&sm->list);
+			kfree(sm);
+			sm = NULL;
+			client->num_sound_models--;
+		} else {
+			rc = -EINVAL;
+			dev_err(rtd->dev,
+				"%s: Failed to find snd_model, invalid model_id %d\n",
+				__func__, p_info->model_id);
+		}
+	} else if (p_info->model_id == 0 &&
+		   p_info->param_type == LSM_DEREG_SND_MODEL) {
+		rc = q6lsm_set_one_param(client, p_info, NULL,
+					 LSM_DEREG_SND_MODEL);
+		if (rc)
+			dev_err(rtd->dev,
+				"%s: Failed to deregister snd_model, err = %d\n",
+				__func__, rc);
+
+		sm = &client->stage_cfg[p_info->stage_idx].sound_model;
+		q6lsm_snd_model_buf_free(client, p_info, sm);
+	} else {
+		rc = -EINVAL;
+		dev_err(rtd->dev,
+			"%s: snd_model id %d is invalid for param type %d\n",
+			__func__, p_info->model_id, p_info->param_type);
+	}
 
 	return rc;
 }
@@ -992,6 +1157,22 @@ static int msm_lsm_process_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
+	if (p_info->param_type == LSM_REG_MULTI_SND_MODEL &&
+		prtd->lsm_client->num_sound_models == LSM_MAX_SOUND_MODELS_SUPPORTED) {
+		dev_err(rtd->dev,
+			"%s: maximum supported sound models(8) have already reached\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (p_info->param_type == LSM_DEREG_MULTI_SND_MODEL &&
+		prtd->lsm_client->num_sound_models == 0) {
+		dev_err(rtd->dev,
+			"%s: no available sound model to be deregistered\n",
+			__func__);
+		return -EINVAL;
+	}
+
 	switch (p_info->param_type) {
 	case LSM_ENDPOINT_DETECT_THRESHOLD:
 		rc = msm_lsm_set_epd(substream, p_info);
@@ -1003,12 +1184,15 @@ static int msm_lsm_process_params(struct snd_pcm_substream *substream,
 		rc = msm_lsm_set_gain(substream, p_info);
 		break;
 	case LSM_MIN_CONFIDENCE_LEVELS:
+	case LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS:
 		rc = msm_lsm_set_conf(substream, p_info);
 		break;
 	case LSM_REG_SND_MODEL:
+	case LSM_REG_MULTI_SND_MODEL:
 		rc = msm_lsm_reg_model(substream, p_info);
 		break;
 	case LSM_DEREG_SND_MODEL:
+	case LSM_DEREG_MULTI_SND_MODEL:
 		rc = msm_lsm_dereg_model(substream, p_info);
 		break;
 	case LSM_CUSTOM_PARAMS:
@@ -1176,7 +1360,10 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 		 * also set stage index to LSM_STAGE_INDEX_FIRST.
 		 */
 		struct lsm_params_info_v2 p_info = {0};
+		struct lsm_sound_model *sm = NULL;
 		p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+		p_info.param_type = LSM_DEREG_SND_MODEL;
+		sm = &prtd->lsm_client->stage_cfg[p_info.stage_idx].sound_model;
 
 		dev_dbg(rtd->dev, "%s: Registering sound model V2\n",
 			__func__);
@@ -1192,21 +1379,20 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			break;
 		}
 		rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
-					snd_model_v2.data_size, &p_info);
+					snd_model_v2.data_size, &p_info, sm);
 		if (rc) {
 			dev_err(rtd->dev,
 				"%s: q6lsm buffer alloc failed V2, size %d\n",
 			       __func__, snd_model_v2.data_size);
 			break;
 		}
-		if (copy_from_user(
-				prtd->lsm_client->stage_cfg[p_info.stage_idx].sound_model.data,
-				snd_model_v2.data, snd_model_v2.data_size)) {
+		if (copy_from_user(sm->data, snd_model_v2.data,
+						   snd_model_v2.data_size)) {
 			dev_err(rtd->dev,
 				"%s: copy from user data failed\n"
 			       "data %pK size %d\n", __func__,
 			       snd_model_v2.data, snd_model_v2.data_size);
-			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
+			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info, sm);
 			rc = -EFAULT;
 			break;
 		}
@@ -1234,7 +1420,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			dev_err(rtd->dev,
 				"%s: Register snd Model v2 failed =%d\n",
 			       __func__, rc);
-			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
+			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info, sm);
 		}
 		if (prtd->lsm_client->confidence_levels) {
 			kfree(prtd->lsm_client->confidence_levels);
@@ -1697,6 +1883,7 @@ struct lsm_params_info_v2_32 {
 	uint32_t param_type;
 	u16 instance_id;
 	u16 stage_idx;
+	u32 model_id;
 };
 
 struct snd_lsm_module_params_32 {
@@ -2033,9 +2220,9 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 
 		if (p_data.data_size != expected_size) {
 			dev_err(rtd->dev,
-				"%s: %s: Invalid size %d\n",
+				"%s: %s: Invalid size %d, expected_size %d\n",
 				__func__, "SET_MODULE_PARAMS(_V2)_32",
-				p_data.data_size);
+				p_data.data_size, expected_size);
 			err = -EINVAL;
 			goto done;
 		}
@@ -2071,6 +2258,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 
 				p_info.instance_id = INSTANCE_ID_0;
 				p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+				p_info.model_id = 0;
 
 				p_info_32++;
 			} else {
@@ -2082,6 +2270,14 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 
 				p_info.instance_id = p_info_v2_32->instance_id;
 				p_info.stage_idx = p_info_v2_32->stage_idx;
+				/* set sound model id to 0 for backward compatibility */
+				p_info.model_id = 0;
+
+				if (LSM_REG_MULTI_SND_MODEL == p_info_v2_32->param_type ||
+				    LSM_DEREG_MULTI_SND_MODEL == p_info_v2_32->param_type ||
+				    LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS ==
+								p_info_v2_32->param_type)
+					p_info.model_id = p_info_v2_32->model_id;
 
 				p_info_v2_32++;
 			}
@@ -2208,7 +2404,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 	case SNDRV_LSM_SET_MODULE_PARAMS_V2: {
 		struct snd_lsm_module_params p_data;
 		struct lsm_params_info *temp_ptr_info = NULL;
-		struct lsm_params_info_v2 info_v2;
 		struct lsm_params_info_v2 *ptr_info_v2 = NULL, *temp_ptr_info_v2 = NULL;
 		size_t p_size = 0, count;
 		u8 *params;
@@ -2277,26 +2472,37 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 		for (count = 0; count < p_data.num_params; count++) {
 			if (cmd == SNDRV_LSM_SET_MODULE_PARAMS) {
 				/* convert to V2 param info struct from legacy param info */
-				info_v2.module_id = temp_ptr_info->module_id;
-				info_v2.param_id = temp_ptr_info->param_id;
-				info_v2.param_size = temp_ptr_info->param_size;
-				info_v2.param_data = temp_ptr_info->param_data;
-				info_v2.param_type = temp_ptr_info->param_type;
+				ptr_info_v2->module_id = temp_ptr_info->module_id;
+				ptr_info_v2->param_id = temp_ptr_info->param_id;
+				ptr_info_v2->param_size = temp_ptr_info->param_size;
+				ptr_info_v2->param_data = temp_ptr_info->param_data;
+				ptr_info_v2->param_type = temp_ptr_info->param_type;
 
-				info_v2.instance_id = INSTANCE_ID_0;
-				info_v2.stage_idx = LSM_STAGE_INDEX_FIRST;
+				ptr_info_v2->instance_id = INSTANCE_ID_0;
+				ptr_info_v2->stage_idx = LSM_STAGE_INDEX_FIRST;
+				ptr_info_v2->model_id = 0;
 
-				ptr_info_v2 = &info_v2;
 				temp_ptr_info++;
 			} else {
-				/* Just copy the pointer as user already provided v2 params */
+				if (LSM_REG_MULTI_SND_MODEL != temp_ptr_info_v2->param_type ||
+				    LSM_DEREG_MULTI_SND_MODEL !=
+								temp_ptr_info_v2->param_type ||
+				    LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS !=
+								temp_ptr_info_v2->param_type) {
+					/* set sound model id to 0 for backward compatibility */
+					temp_ptr_info_v2->model_id = 0;
+				}
+				/*
+				 * Just copy the pointer as user
+				 * already provided sound model id
+				 */
 				ptr_info_v2 = temp_ptr_info_v2;
 				temp_ptr_info_v2++;
 			}
 			err = msm_lsm_process_params(substream, ptr_info_v2);
 			if (err)
 				dev_err(rtd->dev,
-					"%s: Failed to process param, type%d stage=%d err=%d\n",
+					"%s: Failed to process param, type=%d stage=%d err=%d\n",
 					__func__, ptr_info_v2->param_type,
 					ptr_info_v2->stage_idx, err);
 		}
@@ -2464,7 +2670,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int ret = 0;
+	int ret = 0, i;
 
 	pr_debug("%s\n", __func__);
 	prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
@@ -2530,6 +2736,12 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
 	prtd->lsm_client->event_type = LSM_DET_EVENT_TYPE_LEGACY;
 	prtd->lsm_client->fe_id = rtd->dai_link->id;
 	prtd->lsm_client->unprocessed_data = 0;
+	prtd->lsm_client->num_sound_models = 0;
+	prtd->lsm_client->num_keywords = 0;
+	prtd->lsm_client->multi_snd_model_confidence_levels = NULL;
+
+	for (i = 0; i < LSM_MAX_STAGES_PER_SESSION; i++)
+		INIT_LIST_HEAD(&prtd->lsm_client->stage_cfg[i].sound_models);
 
 	prtd->ws = wakeup_source_register(rtd->dev, "lsm-client");
 

+ 163 - 73
dsp/q6lsm.c

@@ -908,17 +908,15 @@ done:
  * @client: LSM client handle
  * @p_info: param info
  * @offset: pointer to retrieve size
- *
+ * @sm: pointer to sound model
  */
 void q6lsm_sm_set_param_data(struct lsm_client *client,
-		struct lsm_params_info_v2 *p_info,
-		size_t *offset)
+			     struct lsm_params_info_v2 *p_info,
+			     size_t *offset, struct lsm_sound_model *sm)
 {
 	struct param_hdr_v3 param_hdr;
 	int ret;
-	struct lsm_sound_model *sm;
 
-	sm = &client->stage_cfg[p_info->stage_idx].sound_model;
 	memset(&param_hdr, 0, sizeof(param_hdr));
 
 	param_hdr.module_id = p_info->module_id;
@@ -926,6 +924,8 @@ void q6lsm_sm_set_param_data(struct lsm_client *client,
 	param_hdr.param_id = p_info->param_id;
 	param_hdr.param_size = p_info->param_size;
 
+	sm->model_id = p_info->model_id;
+
 	ret = q6lsm_pack_params(sm->data, &param_hdr,
 				NULL, offset, LSM_SESSION_CMD_SET_PARAMS_V2);
 	if (ret)
@@ -1010,42 +1010,78 @@ EXPORT_SYMBOL(q6lsm_open);
 
 static int q6lsm_send_confidence_levels(struct lsm_client *client,
 					struct param_hdr_v3 *param_info,
-					uint32_t set_param_opcode)
+					uint32_t set_param_opcode, uint32_t model_id)
 {
 	struct lsm_param_confidence_levels *conf_levels = NULL;
 	uint32_t num_conf_levels = client->num_confidence_levels;
+	struct lsm_param_multi_snd_model_conf_levels *multi_sm_conf_levels = NULL;
+	uint32_t num_keywords = client->num_keywords;
 	uint8_t i = 0;
 	uint8_t padd_size = 0;
 	uint32_t param_size = 0;
 	int rc = 0;
 
-	/* Data must be 4 byte aligned so add any necessary padding. */
-	padd_size = (4 - (num_conf_levels % 4)) - 1;
-	param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
-		     sizeof(uint8_t);
-	param_info->param_size = param_size;
-	pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
+	if (model_id != 0) {
+		/* No padding is need since the structure is always 4 byte aligend.
+		 * The number "2" below represents the first two u32 variables in
+		 * struct lsm_param_multi_snd_model_conf_levels.
+		 */
+		param_size = (2 + num_keywords) * sizeof(uint32_t);
+		param_info->param_size = param_size;
+		pr_debug("%s: Set Conf Levels PARAM SIZE: %d\n", __func__, param_size);
 
-	conf_levels = kzalloc(param_size, GFP_KERNEL);
-	if (!conf_levels)
-		return -ENOMEM;
+		multi_sm_conf_levels = kzalloc(param_size, GFP_KERNEL);
+		if (!multi_sm_conf_levels)
+			return -ENOMEM;
 
-	conf_levels->num_confidence_levels = num_conf_levels;
-	pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
+		multi_sm_conf_levels->model_id = model_id;
+		multi_sm_conf_levels->num_keywords = num_keywords;
+		pr_debug("%s: snd_model id: %d, num_keywords: %d\n",
+			 __func__, model_id, num_keywords);
+
+		memcpy(multi_sm_conf_levels->confidence_levels,
+		       client->multi_snd_model_confidence_levels,
+		       sizeof(uint32_t) * num_keywords);
+		for (i = 0; i < num_keywords; i++)
+			pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
+				 multi_sm_conf_levels->confidence_levels[i]);
+
+		rc = q6lsm_pack_and_set_params(client, param_info,
+					       (uint8_t *) multi_sm_conf_levels,
+					       set_param_opcode);
+		if (rc)
+			pr_err("%s: Send multi_snd_model_conf_levels cmd failed, err %d\n",
+			       __func__, rc);
+		kfree(multi_sm_conf_levels);
+	} else {
+		/* Data must be 4 byte aligned so add any necessary padding. */
+		padd_size = (4 - (num_conf_levels % 4)) - 1;
+		param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
+			      sizeof(uint8_t);
+		param_info->param_size = param_size;
+		pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
+
+		conf_levels = kzalloc(param_size, GFP_KERNEL);
+		if (!conf_levels)
+			return -ENOMEM;
 
-	memcpy(conf_levels->confidence_levels, client->confidence_levels,
-	       num_conf_levels);
-	for (i = 0; i < num_conf_levels; i++)
-		pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
-			 conf_levels->confidence_levels[i]);
+		conf_levels->num_confidence_levels = num_conf_levels;
+		pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
 
-	rc = q6lsm_pack_and_set_params(client, param_info,
-				       (uint8_t *) conf_levels,
-				       set_param_opcode);
-	if (rc)
-		pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
-		       __func__, rc);
-	kfree(conf_levels);
+		memcpy(conf_levels->confidence_levels, client->confidence_levels,
+		       num_conf_levels);
+		for (i = 0; i < num_conf_levels; i++)
+			pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
+				 conf_levels->confidence_levels[i]);
+
+		rc = q6lsm_pack_and_set_params(client, param_info,
+					       (uint8_t *) conf_levels,
+					       set_param_opcode);
+		if (rc)
+			pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
+			       __func__, rc);
+		kfree(conf_levels);
+	}
 	return rc;
 }
 
@@ -1459,7 +1495,7 @@ int q6lsm_set_data(struct lsm_client *client,
 
 	param_hdr.param_id = LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
 	rc = q6lsm_send_confidence_levels(client, &param_hdr,
-					  LSM_SESSION_CMD_SET_PARAMS);
+					  LSM_SESSION_CMD_SET_PARAMS, 0);
 	if (rc) {
 		pr_err("%s: Failed to send conf_levels, err = %d\n",
 			__func__, rc);
@@ -1537,8 +1573,9 @@ EXPORT_SYMBOL(q6lsm_register_sound_model);
  */
 int q6lsm_deregister_sound_model(struct lsm_client *client)
 {
-	int rc;
+	int rc = 0;
 	struct lsm_cmd_reg_snd_model cmd;
+	struct lsm_sound_model *sm = NULL, *next = NULL;
 	/*
 	 * With multi-stage support sm buff allocation/free usage param info
 	 * to check stage index for which this sound model is being set, and
@@ -1564,19 +1601,39 @@ int q6lsm_deregister_sound_model(struct lsm_client *client)
 		return -EINVAL;
 	}
 
-	memset(&cmd, 0, sizeof(cmd));
-	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
-	cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
-
-	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
-	if (rc) {
-		pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
-		       cmd.hdr.opcode, rc);
+	if (client->num_sound_models > 0) {
+		p_info.param_type = LSM_DEREG_MULTI_SND_MODEL;
+		list_for_each_entry_safe(sm, next,
+				&client->stage_cfg[p_info.stage_idx].sound_models,
+				list) {
+			pr_debug("%s: current snd_model: %d, num of sound models left %d\n",
+				 __func__, sm->model_id, client->num_sound_models);
+			q6lsm_snd_model_buf_free(client, &p_info, sm);
+			list_del(&sm->list);
+			kfree(sm);
+			sm = NULL;
+			client->num_sound_models--;
+
+			if (0 == client->num_sound_models)
+				break;
+		}
 	} else {
-		pr_debug("%s: Deregister sound model succeeded\n", __func__);
-	}
+		memset(&cmd, 0, sizeof(cmd));
+		q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+		cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+		rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+		if (rc) {
+			pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+			       cmd.hdr.opcode, rc);
+		} else {
+			pr_debug("%s: Deregister sound model succeeded\n", __func__);
+		}
 
-	q6lsm_snd_model_buf_free(client, &p_info);
+		p_info.param_type = LSM_DEREG_SND_MODEL;
+		sm = &client->stage_cfg[p_info.stage_idx].sound_model;
+		q6lsm_snd_model_buf_free(client, &p_info, sm);
+	}
 
 	return rc;
 }
@@ -1825,14 +1882,15 @@ fail:
  *
  * @client: LSM client handle
  * @p_info: sound model param info
+ * @sm: pointer to sound model
  *
  * Returns 0 on success or error on failure
  */
 int q6lsm_snd_model_buf_free(struct lsm_client *client,
-			struct lsm_params_info_v2 *p_info)
+			     struct lsm_params_info_v2 *p_info,
+			     struct lsm_sound_model *sm)
 {
 	int rc = 0, stage_idx = p_info->stage_idx;
-	struct lsm_sound_model *sm = NULL;
 
 	pr_debug("%s: Session id %d\n", __func__, client->session);
 	if (CHECK_SESSION(client->session)) {
@@ -1840,11 +1898,11 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client,
 		return -EINVAL;
 	}
 
-	if (!client->stage_cfg[stage_idx].sound_model.data)
+	if (p_info->param_type == LSM_DEREG_SND_MODEL &&
+	    !client->stage_cfg[stage_idx].sound_model.data)
 		return 0;
 
 	mutex_lock(&client->cmd_lock);
-	sm = &client->stage_cfg[stage_idx].sound_model;
 	if (sm->mem_map_handle != 0) {
 		rc = q6lsm_memory_unmap_regions(client, sm->mem_map_handle);
 		if (rc)
@@ -1858,7 +1916,10 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client,
 	sm->phys = 0;
 	mutex_unlock(&client->cmd_lock);
 
-	rc = q6lsm_snd_cal_free(client, p_info);
+	if ((p_info->param_type == LSM_DEREG_MULTI_SND_MODEL &&
+	    client->num_sound_models == 1) ||
+	    p_info->param_type == LSM_DEREG_SND_MODEL)
+		rc = q6lsm_snd_cal_free(client, p_info);
 	return rc;
 }
 EXPORT_SYMBOL(q6lsm_snd_model_buf_free);
@@ -1980,20 +2041,20 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
  * Returns 0 on success or error on failure
  */
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
-			      struct lsm_params_info_v2 *p_info)
+			      struct lsm_params_info_v2 *p_info,
+			      struct lsm_sound_model *sm)
 {
 	int rc = -EINVAL, stage_idx = p_info->stage_idx;
+	int model_id = p_info->model_id;
 	size_t total_mem = 0;
-	struct lsm_sound_model *sm = NULL;
 
 	if (!client)
 		return rc;
 
-	pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
-			__func__, len, stage_idx);
+	pr_debug("%s:Snd Model len %zd, stage_idx %d, model_id %d\n",
+		 __func__, len, stage_idx, model_id);
 
 	mutex_lock(&client->cmd_lock);
-	sm = &client->stage_cfg[stage_idx].sound_model;
 	if (!sm->data) {
 		/*
 		 * If sound model is sent as set_param, i.e. param_id != 0,
@@ -2008,7 +2069,7 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
 		pr_debug("%s: sm param size %zd Total mem %zd, stage_idx %d\n",
 				 __func__, len, total_mem, stage_idx);
 		rc = msm_audio_ion_alloc(&sm->dma_buf, total_mem,
-								&sm->phys, &len, &sm->data);
+					 &sm->phys, &len, &sm->data);
 		if (rc) {
 			pr_err("%s: Audio ION alloc is failed, rc = %d, stage_idx = %d\n",
 				__func__, rc, stage_idx);
@@ -2040,7 +2101,7 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
 fail:
 	mutex_unlock(&client->cmd_lock);
 fail_1:
-	q6lsm_snd_model_buf_free(client, p_info);
+	q6lsm_snd_model_buf_free(client, p_info, sm);
 	return rc;
 }
 EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc);
@@ -2126,8 +2187,8 @@ static int q6lsm_send_param_gain(struct lsm_client *client, u16 gain,
  * Returns 0 on success or error on failure
  */
 int q6lsm_set_one_param(struct lsm_client *client,
-	struct lsm_params_info_v2 *p_info, void *data,
-	uint32_t param_type)
+			struct lsm_params_info_v2 *p_info,
+			void *data, uint32_t param_type)
 {
 	struct param_hdr_v3 param_info;
 	int rc = 0;
@@ -2186,14 +2247,19 @@ int q6lsm_set_one_param(struct lsm_client *client,
 	}
 
 	case LSM_MIN_CONFIDENCE_LEVELS:
+	case LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS:
 		param_info.module_id = p_info->module_id;
 		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		rc = q6lsm_send_confidence_levels(
-			client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2);
+			client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2,
+			p_info->model_id);
 		if (rc)
-			pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
-				 __func__, rc);
+			pr_err("%s: %s cmd failed, rc %d\n",
+				 __func__,
+				 param_type == LSM_MIN_CONFIDENCE_LEVELS ?
+				 "LSM_MIN_CONFIDENCE_LEVELS" :
+				 "LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS", rc);
 		break;
 	case LSM_POLLING_ENABLE: {
 		struct snd_lsm_poll_enable *lsm_poll_enable =
@@ -2210,7 +2276,8 @@ int q6lsm_set_one_param(struct lsm_client *client,
 		break;
 	}
 
-	case LSM_REG_SND_MODEL: {
+	case LSM_REG_SND_MODEL:
+	case LSM_REG_MULTI_SND_MODEL: {
 		struct mem_mapping_hdr mem_hdr;
 		u32 payload_size;
 		struct lsm_sound_model *sm = NULL;
@@ -2224,8 +2291,18 @@ int q6lsm_set_one_param(struct lsm_client *client,
 			payload_size = p_info->param_size +
 				       sizeof(struct param_hdr_v2);
 
-		sm = &client->stage_cfg[p_info->stage_idx].sound_model;
-
+		if (param_type == LSM_REG_MULTI_SND_MODEL) {
+			list_for_each_entry(sm,
+					    &client->stage_cfg[p_info->stage_idx].sound_models,
+					    list) {
+				pr_debug("%s: current snd_model: %d, looking for snd_model %d\n",
+					__func__, sm->model_id, p_info->model_id);
+				if (sm->model_id == p_info->model_id)
+					break;
+			}
+		} else {
+			sm = &client->stage_cfg[p_info->stage_idx].sound_model;
+		}
 		mem_hdr.data_payload_addr_lsw =
 			lower_32_bits(sm->phys);
 		mem_hdr.data_payload_addr_msw =
@@ -2236,28 +2313,41 @@ int q6lsm_set_one_param(struct lsm_client *client,
 		rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size,
 				      LSM_SESSION_CMD_SET_PARAMS_V2);
 		if (rc) {
-			pr_err("%s: REG_SND_MODEL failed, rc %d\n",
-				__func__, rc);
+			pr_err("%s: %s failed, rc %d\n",
+				__func__, param_type == LSM_REG_SND_MODEL ?
+				"LSM_REG_SND_MODEL" : "LSM_REG_MULTI_SND_MODEL", rc);
 			return rc;
 		}
 
-		rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
-		if (rc)
-			pr_err("%s: Failed to send lsm cal, err = %d\n",
-				__func__, rc);
+		if (client->num_sound_models == 0) {
+			rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
+			if (rc)
+				pr_err("%s: Failed to send lsm cal, err = %d\n",
+					__func__, rc);
+		}
 		break;
 	}
 
-	case LSM_DEREG_SND_MODEL: {
+	case LSM_DEREG_SND_MODEL:
+	case LSM_DEREG_MULTI_SND_MODEL: {
 		param_info.module_id = p_info->module_id;
 		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		param_info.param_size = 0;
-		rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
-					       LSM_SESSION_CMD_SET_PARAMS_V2);
+
+		if (param_type == LSM_DEREG_MULTI_SND_MODEL) {
+			param_info.param_size = p_info->param_size;
+			rc = q6lsm_pack_and_set_params(client, &param_info,
+							(uint8_t *)&p_info->model_id,
+							LSM_SESSION_CMD_SET_PARAMS_V2);
+		} else {
+			rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
+							LSM_SESSION_CMD_SET_PARAMS_V2);
+		}
 		if (rc)
-			pr_err("%s: DEREG_SND_MODEL failed, rc %d\n",
-				__func__, rc);
+			pr_err("%s: %s failed, rc %d\n",
+				__func__,  param_type == LSM_DEREG_SND_MODEL ?
+				"LSM_DEREG_SND_MODEL" : "LSM_DEREG_MULTI_SND_MODEL", rc);
 		break;
 	}
 

+ 19 - 4
include/dsp/q6lsm.h

@@ -22,6 +22,10 @@
 
 #define MAX_LSM_SESSIONS 8
 
+#define MAX_KEYWORDS_SUPPORTED 8
+
+#define LSM_MAX_SOUND_MODELS_SUPPORTED 8
+
 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
 		       uint32_t *payload, uint16_t client_size, void *priv);
 
@@ -32,6 +36,8 @@ struct lsm_sound_model {
 	uint32_t	actual_size; /* actual number of bytes read by DSP */
 	struct dma_buf	*dma_buf;
 	uint32_t	mem_map_handle;
+	uint32_t	model_id;
+	struct list_head	list;
 };
 
 struct snd_lsm_event_status_v2 {
@@ -71,6 +77,7 @@ struct lsm_stage_config {
 	bool	lab_enable;
 	struct lsm_sound_model	sound_model;
 	struct lsm_cal_data_info	cal_info;
+	struct list_head	sound_models;
 };
 
 
@@ -106,6 +113,9 @@ struct lsm_client {
 	struct lsm_stage_config	stage_cfg[LSM_MAX_STAGES_PER_SESSION];
 	uint64_t	fe_id;
 	uint16_t	unprocessed_data;
+	uint32_t	num_sound_models;
+	uint32_t	num_keywords;
+	uint32_t	*multi_snd_model_confidence_levels;
 };
 
 struct lsm_stream_cmd_open_tx {
@@ -193,6 +203,11 @@ struct lsm_param_media_fmt_v2 {
 	uint8_t		channel_mapping[0];
 } __packed;
 
+struct lsm_param_multi_snd_model_conf_levels {
+	uint32_t model_id;
+	uint32_t num_keywords;
+	uint32_t confidence_levels[0];
+} __packed;
 
 struct lsm_param_confidence_levels {
 	uint8_t num_confidence_levels;
@@ -268,9 +283,9 @@ int q6lsm_open(struct lsm_client *client, uint16_t app_id);
 int q6lsm_start(struct lsm_client *client, bool wait);
 int q6lsm_stop(struct lsm_client *client, bool wait);
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
-			struct lsm_params_info_v2 *p_info);
+			struct lsm_params_info_v2 *p_info, struct lsm_sound_model *sm);
 int q6lsm_snd_model_buf_free(struct lsm_client *client,
-			struct lsm_params_info_v2 *p_info);
+			struct lsm_params_info_v2 *p_info, struct lsm_sound_model *sm);
 int q6lsm_close(struct lsm_client *client);
 int q6lsm_register_sound_model(struct lsm_client *client,
 			       enum lsm_detection_mode mode,
@@ -290,8 +305,8 @@ int q6lsm_set_one_param(struct lsm_client *client,
 			struct lsm_params_info_v2 *p_info, void *data,
 			uint32_t param_type);
 void q6lsm_sm_set_param_data(struct lsm_client *client,
-		struct lsm_params_info_v2 *p_info,
-		size_t *offset);
+		struct lsm_params_info_v2 *p_info, size_t *offset,
+		struct lsm_sound_model *sm);
 int q6lsm_set_port_connected(struct lsm_client *client);
 int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
 int q6lsm_set_media_fmt_params(struct lsm_client *client);

+ 7 - 2
include/uapi/audio/sound/lsm_params.h

@@ -6,7 +6,7 @@
 
 #include <linux/types.h>
 
-#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 1)
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 2)
 
 #define LSM_MAX_STAGES_PER_SESSION 2
 #define LSM_STAGE_INDEX_FIRST 0
@@ -33,7 +33,10 @@
 #define LSM_POLLING_ENABLE (7)
 #define LSM_DET_EVENT_TYPE (8)
 #define LSM_LAB_CONTROL (9)
-#define LSM_PARAMS_MAX (LSM_LAB_CONTROL + 1)
+#define LSM_REG_MULTI_SND_MODEL (10)
+#define LSM_DEREG_MULTI_SND_MODEL (11)
+#define LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS (12)
+#define LSM_PARAMS_MAX (LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS + 1)
 
 #define LSM_EVENT_NON_TIME_STAMP_MODE (0)
 #define LSM_EVENT_TIME_STAMP_MODE (1)
@@ -226,6 +229,7 @@ struct lsm_params_info {
  * Member variables applicable only to V2:
  * @instance_id: instance id of the param to which parameter is to be set
  * @stage_idx: detection stage for which the param is applicable
+ * @model_id: an unique number to identify sound models in DSP
  */
 struct lsm_params_info_v2 {
 	__u32 module_id;
@@ -235,6 +239,7 @@ struct lsm_params_info_v2 {
 	__u32 param_type;
 	__u16 instance_id;
 	__u16 stage_idx;
+	__u32 model_id;
 };
 
 /*