ASoC: msm: qdsp6v2: Add dynamic chmix config support

Add support to dynamically configure channel mixing weightage
coefficients for both ASM and LSM sessions.
Currently the code is executed only for LSM session and can be
extended to ASM as well.

Change-Id: I727ea6fa2d3a99bbf6811005c5733535f680891b
Signed-off-by: Chaithanya Krishna Bacharaju <chaithan@codeaurora.org>
Signed-off-by: Bhalchandra Gajare <gajare@codeaurora.org>
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 26402f3..b9893c4 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -790,6 +790,106 @@
 EXPORT_SYMBOL(adm_set_stereo_to_custom_stereo);
 
 /*
+ * adm_set_custom_chmix_cfg:
+ *	Set the custom channel mixer configuration for ADM
+ *
+ * @port_id: Backend port id
+ * @copp_idx: ADM copp index
+ * @session_id: ID of the requesting session
+ * @params: Expected packaged params for channel mixer
+ * @params_length: Length of the params to be set
+ * @direction: RX or TX direction
+ * @stream_type: Audio or Listen stream type
+ */
+int adm_set_custom_chmix_cfg(int port_id, int copp_idx,
+			     unsigned int session_id, char *params,
+			     uint32_t params_length, int direction,
+			     int stream_type)
+{
+	struct adm_cmd_set_pspd_mtmx_strtr_params_v6 *adm_params = NULL;
+	int sz, rc = 0, port_idx;
+
+	port_id = afe_convert_virtual_to_portid(port_id);
+	port_idx = adm_validate_and_get_port_index(port_id);
+	if (port_idx < 0) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v6) +
+		params_length;
+	adm_params = kzalloc(sz, GFP_KERNEL);
+	if (!adm_params) {
+		pr_err("%s, adm params memory alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(((u8 *)adm_params +
+		sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v6)),
+		params, params_length);
+	adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	adm_params->hdr.pkt_size = sz;
+	adm_params->hdr.src_svc = APR_SVC_ADM;
+	adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+	adm_params->hdr.src_port = port_id;
+	adm_params->hdr.dest_svc = APR_SVC_ADM;
+	adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+	adm_params->hdr.dest_port = 0; /* Ignored */;
+	adm_params->hdr.token = port_idx << 16 | copp_idx;
+	adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V6;
+	adm_params->payload_addr_lsw = 0;
+	adm_params->payload_addr_msw = 0;
+	adm_params->mem_map_handle = 0;
+	adm_params->payload_size = params_length;
+	adm_params->direction = direction;
+	/* session id for this cmd to be applied on */
+	adm_params->sessionid = session_id;
+	adm_params->deviceid =
+			atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+	/* connecting stream type i.e. lsm or asm */
+	adm_params->stream_type = stream_type;
+	pr_debug("%s: deviceid %d, session_id %d, src_port %d, dest_port %d\n",
+		__func__, adm_params->deviceid, adm_params->sessionid,
+		adm_params->hdr.src_port, adm_params->hdr.dest_port);
+	atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+	rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+	if (rc < 0) {
+		pr_err("%s: Set params failed port = 0x%x rc %d\n",
+			__func__, port_id, rc);
+		rc = -EINVAL;
+		goto exit;
+	}
+	/* Wait for the callback */
+	rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+				atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx]),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!rc) {
+		pr_err("%s: Set params timed out port = 0x%x\n", __func__,
+			port_id);
+		rc = -EINVAL;
+		goto exit;
+	} else if (atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx]) > 0) {
+		pr_err("%s: DSP returned error[%s]\n", __func__,
+			adsp_err_get_err_str(atomic_read(
+				&this_adm.copp.stat
+				[port_idx][copp_idx])));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&this_adm.copp.stat
+					[port_idx][copp_idx]));
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	kfree(adm_params);
+	return rc;
+}
+EXPORT_SYMBOL(adm_set_custom_chmix_cfg);
+
+/*
  * With pre-packed data, only the opcode differes from V5 and V6.
  * Use q6common_pack_pp_params to pack the data correctly.
  */
@@ -1544,7 +1644,8 @@
 				}
 				break;
 			case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5:
-				pr_debug("%s: ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5\n",
+			case ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V6:
+				pr_debug("%s:callback received PSPD MTMX, wake up\n",
 					__func__);
 				atomic_set(&this_adm.copp.stat[port_idx]
 						[copp_idx], payload[1]);
@@ -2280,6 +2381,8 @@
 {
 	int rc = 0, idx;
 
+	pr_debug("%s: channel mode %d", __func__, channel_mode);
+
 	memset(open->dev_channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
 	switch (path) {
 	case ADM_PATH_PLAYBACK: