ASoC: msm: add api to query status of Audio services in QDSP6

After QDSP6 boots audio services might take some time to comes to a
state where they can serve clients on Host Processor. Add an api to
query status of Audio services in QDPS6.

CRs-Fixed: 487983
Change-Id: Ib222874ce645af78bd5647b45506b50af1f6062d
Signed-off-by: Kiran Kandi <kkandi@codeaurora.org>
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 5fec0c1..e9352df 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -30,6 +30,7 @@
 	wait_queue_head_t bus_bw_req_wait;
 	u32 bus_bw_resp_received;
 	struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
+	u32 param;
 };
 
 static struct q6core_str q6core_lcl;
@@ -102,6 +103,17 @@
 		break;
 	}
 
+	case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
+		payload1 = data->payload;
+		q6core_lcl.param = payload1[0];
+		pr_debug("%s: Received ADSP get state response 0x%x\n",
+			 __func__, q6core_lcl.param);
+		/* ensure .param is updated prior to .bus_bw_resp_received */
+		wmb();
+		q6core_lcl.bus_bw_resp_received = 1;
+		wake_up(&q6core_lcl.bus_bw_req_wait);
+		break;
+
 	default:
 		pr_err("Message id from adsp core svc: %d\n", data->opcode);
 		break;
@@ -197,6 +209,39 @@
 	return ret;
 }
 
+bool q6core_is_adsp_ready(void)
+{
+	int rc;
+	bool ret = false;
+	struct apr_hdr hdr;
+
+	pr_debug("%s: enter\n", __func__);
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
+	hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
+
+	ocm_core_open();
+	q6core_lcl.bus_bw_resp_received = 0;
+	rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+	if (rc < 0) {
+		pr_err("%s: Get ADSP state APR packet send event\n", __func__);
+		goto bail;
+	}
+
+	rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+				(q6core_lcl.bus_bw_resp_received == 1),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+		/* ensure to read updated param by callback thread */
+		rmb();
+		ret = !!q6core_lcl.param;
+	}
+bail:
+	pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
+	return ret;
+}
 
 static int __init core_init(void)
 {
diff --git a/sound/soc/msm/qdsp6v2/q6core.h b/sound/soc/msm/qdsp6v2/q6core.h
index 39bf4ab..e5a59bc 100644
--- a/sound/soc/msm/qdsp6v2/q6core.h
+++ b/sound/soc/msm/qdsp6v2/q6core.h
@@ -25,6 +25,9 @@
 
 #define AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO           0x00012904
 
+#define AVCS_CMD_ADSP_EVENT_GET_STATE		0x0001290C
+#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE	0x0001290D
+
 /* @brief AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO payload
  * structure. Payload for this event comprises one instance of
  * avcs_cmd_rsp_get_low_power_segments_info_t, followed
@@ -89,6 +92,7 @@
 
 int core_get_low_power_segments(
 			struct avcs_cmd_rsp_get_low_power_segments_info_t **);
+bool q6core_is_adsp_ready(void);
 
 #define ADSP_CMD_SET_DOLBY_MANUFACTURER_ID 0x00012918