Merge "ASoC: qdsp6v2: Add support of ULL and LL"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 0a45ede..6277054 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -21,6 +21,12 @@
       - qti,msm-pcm-low-latency : Flag indicating whether
         the device node is of type low latency.
 
+      - qti,latency-level : Flag indicating whether the device node
+                            is of type regular low latency or ultra
+                            low latency.
+                            regular : regular low latency stream
+                            ultra : ultra low latency stream
+
 * msm-pcm-routing
 
 Required properties:
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index ca06adc..5941f71 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -31,7 +31,7 @@
 int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
 
 int adm_open(int port, int path, int rate, int mode, int topology,
-				bool perf_mode, uint16_t bits_per_sample);
+				int perf_mode, uint16_t bits_per_sample);
 
 int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
 			uint32_t params_length, char *params);
@@ -40,7 +40,7 @@
 				 uint32_t params_length);
 
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
-			int topology, bool perf_mode, uint16_t bits_per_sample);
+			int topology, int perf_mode, uint16_t bits_per_sample);
 
 int adm_unmap_cal_blocks(void);
 
@@ -53,10 +53,10 @@
 
 int adm_memory_unmap_regions(int port_id);
 
-int adm_close(int port, bool perf_mode);
+int adm_close(int port, int perf_mode);
 
 int adm_matrix_map(int session_id, int path, int num_copps,
-		unsigned int *port_id, int copp_id, bool perf_mode);
+		unsigned int *port_id, int copp_id, int perf_mode);
 
 int adm_connect_afe_port(int mode, int session_id, int port_id);
 
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index b00cfc9..a78c333 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -175,7 +175,7 @@
 	struct audio_port_data port[2];
 	wait_queue_head_t      cmd_wait;
 	wait_queue_head_t      time_wait;
-	bool                   perf_mode;
+	int                    perf_mode;
 	int					   stream_id;
 	/* audio cache operations fptr*/
 	int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index fd6a490..8ac835c 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -15,6 +15,13 @@
 
 #include <mach/qdsp6v2/apr.h>
 
+enum {
+	LEGACY_PCM_MODE = 0,
+	LOW_LATENCY_PCM_MODE,
+	ULTRA_LOW_LATENCY_PCM_MODE,
+};
+
+
 int q6audio_get_port_index(u16 port_id);
 
 int q6audio_convert_virtual_to_portid(u16 port_id);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index a13b3f2..3ddc3e0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -25,6 +25,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/q6audio-v2.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_ion.h>
@@ -916,6 +917,7 @@
 	int rc;
 	int id;
 	struct msm_plat_data *pdata;
+	const char *latency_level;
 
 	rc = of_property_read_u32(pdev->dev.of_node,
 				"qti,msm-pcm-dsp-id", &id);
@@ -932,10 +934,17 @@
 	}
 
 	if (of_property_read_bool(pdev->dev.of_node,
-				"qti,msm-pcm-low-latency"))
-		pdata->perf_mode = 1;
-	else
-		pdata->perf_mode = 0;
+				"qti,msm-pcm-low-latency")) {
+
+		pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+		rc = of_property_read_string(pdev->dev.of_node,
+			"qti,latency-level", &latency_level);
+		if (!rc) {
+			if (!strcmp(latency_level, "ultra"))
+				pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+		}
+	} else
+		pdata->perf_mode = LEGACY_PCM_MODE;
 
 	dev_set_drvdata(&pdev->dev, pdata);
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 711291da..91c0744 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -290,7 +290,7 @@
 /* Track performance mode of all front-end multimedia sessions.
  * Performance mode is only valid when session is valid.
  */
-static bool fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
+static int fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
 
 static uint8_t is_be_dai_extproc(int be_dai)
 {
@@ -303,7 +303,7 @@
 }
 
 static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
-	int path_type, bool perf_mode)
+	int path_type, int perf_mode)
 {
 	int i, port_type;
 	struct route_payload payload;
@@ -365,7 +365,7 @@
 	mutex_unlock(&routing_lock);
 }
 
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
 					int dspst_id, int stream_type)
 {
 	int i, session_type, path_type, port_type, port_id, topology;
@@ -437,7 +437,7 @@
 			port_id = srs_port_id = msm_bedais[i].port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!perf_mode))
+			    (perf_mode == LEGACY_PCM_MODE))
 				if (dolby_dap_init(port_id,
 						msm_bedais[i].channel) < 0)
 					pr_err("%s: Err init dolby dap\n",
@@ -494,7 +494,8 @@
 			adm_close(msm_bedais[i].port_id,
 				  fe_dai_perf_mode[fedai_id][session_type]);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[fedai_id][session_type] == false))
+			    (fe_dai_perf_mode[fedai_id][session_type] ==
+							LEGACY_PCM_MODE))
 				dolby_dap_deinit(msm_bedais[i].port_id);
 		}
 	}
@@ -604,7 +605,8 @@
 			port_id = srs_port_id = msm_bedais[reg].port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[val][session_type] == false))
+			    (fe_dai_perf_mode[val][session_type] ==
+							LEGACY_PCM_MODE))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
@@ -621,7 +623,8 @@
 			adm_close(msm_bedais[reg].port_id,
 				  fe_dai_perf_mode[val][session_type]);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[val][session_type] == false))
+			    (fe_dai_perf_mode[val][session_type] ==
+							LEGACY_PCM_MODE))
 				dolby_dap_deinit(msm_bedais[reg].port_id);
 			msm_pcm_routing_build_matrix(val,
 				fdai->strm_id, path_type,
@@ -3960,7 +3963,8 @@
 				  fe_dai_perf_mode[i][session_type]);
 			srs_port_id = -1;
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[i][session_type] == false))
+			    (fe_dai_perf_mode[i][session_type] ==
+							LEGACY_PCM_MODE))
 				dolby_dap_deinit(bedai->port_id);
 		}
 	}
@@ -4060,7 +4064,8 @@
 			port_id = srs_port_id = bedai->port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[i][session_type] == false))
+			    (fe_dai_perf_mode[i][session_type] ==
+							LEGACY_PCM_MODE))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4f7c4e3..54f5e4a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -143,7 +143,7 @@
  * dspst_id:  DSP audio stream ID
  * stream_type: playback or capture
  */
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id,
 	int stream_type);
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index d837f06..54b1263 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -733,7 +733,7 @@
 	adm_params.hdr.dest_svc = APR_SVC_ADM;
 	adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
 
-	if (!perf_mode)
+	if (perf_mode == LEGACY_PCM_MODE)
 		adm_params.hdr.dest_port =
 			atomic_read(&this_adm.copp_id[index]);
 	else
@@ -1056,7 +1056,7 @@
 }
 
 int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
-			bool perf_mode, uint16_t bits_per_sample)
+			int perf_mode, uint16_t bits_per_sample)
 {
 	struct adm_cmd_device_open_v5	open;
 	int ret = 0;
@@ -1087,7 +1087,7 @@
 		rtac_set_adm_handle(this_adm.apr);
 	}
 
-	if (!perf_mode) {
+	if (perf_mode == LEGACY_PCM_MODE) {
 		atomic_set(&this_adm.copp_perf_mode[index], 0);
 		send_adm_custom_topology(port_id);
 	} else {
@@ -1095,8 +1095,9 @@
 	}
 
 	/* Create a COPP if port id are not enabled */
-	if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
-		(perf_mode &&
+	if ((perf_mode == LEGACY_PCM_MODE &&
+		(atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+		(perf_mode != LEGACY_PCM_MODE &&
 		(atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
 		pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
 			perf_mode);
@@ -1111,12 +1112,12 @@
 		open.hdr.dest_port = tmp_port;
 		open.hdr.token = port_id;
 		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
-		open.flags = 0x00;
-		if (perf_mode) {
-			open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
-		} else {
-			open.flags |= ADM_LEGACY_DEVICE_SESSION;
-		}
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+			open.flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
+		else if (perf_mode == LOW_LATENCY_PCM_MODE)
+			open.flags = ADM_LOW_LATENCY_DEVICE_SESSION;
+		else
+			open.flags = ADM_LEGACY_DEVICE_SESSION;
 
 		open.mode_of_operation = path;
 		open.endpoint_id_1 = tmp_port;
@@ -1133,7 +1134,7 @@
 			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 
-		if (perf_mode) {
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
 			open.topology_id = NULL_COPP_TOPOLOGY;
 			rate = ULL_SUPPORTED_SAMPLE_RATE;
 			if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
@@ -1141,7 +1142,8 @@
 		}
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
-		WARN_ON(perf_mode && (rate != 48000));
+		WARN_ON(perf_mode == ULTRA_LOW_LATENCY_PCM_MODE &&
+							(rate != 48000));
 		open.sample_rate  = rate;
 		memset(open.dev_channel_mapping, 0, 8);
 
@@ -1216,7 +1218,8 @@
 			goto fail_cmd;
 		}
 	}
-	if (perf_mode) {
+	if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+			perf_mode == LOW_LATENCY_PCM_MODE) {
 		atomic_inc(&this_adm.copp_low_latency_cnt[index]);
 		pr_debug("%s: index: %d coppid: %d", __func__, index,
 			atomic_read(&this_adm.copp_low_latency_id[index]));
@@ -1233,7 +1236,7 @@
 }
 
 int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
-			int topology, bool perf_mode, uint16_t bits_per_sample)
+			int topology, int perf_mode, uint16_t bits_per_sample)
 {
 	int ret = 0;
 
@@ -1244,7 +1247,7 @@
 }
 
 int adm_matrix_map(int session_id, int path, int num_copps,
-			unsigned int *port_id, int copp_id, bool perf_mode)
+			unsigned int *port_id, int copp_id, int perf_mode)
 {
 	struct adm_cmd_matrix_map_routings_v5	*route;
 	struct adm_session_map_node_v5 *node;
@@ -1283,7 +1286,8 @@
 	route->hdr.src_port = copp_id;
 	route->hdr.dest_svc = APR_SVC_ADM;
 	route->hdr.dest_domain = APR_DOMAIN_ADSP;
-	if (perf_mode) {
+	if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+			perf_mode == LOW_LATENCY_PCM_MODE) {
 		route->hdr.dest_port =
 			atomic_read(&this_adm.copp_low_latency_id[index]);
 	} else {
@@ -1321,7 +1325,8 @@
 
 
 		if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
-			if (perf_mode)
+			if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+					perf_mode == LOW_LATENCY_PCM_MODE)
 				copps_list[i] =
 				atomic_read(&this_adm.copp_low_latency_id[tmp]);
 			else
@@ -1352,23 +1357,27 @@
 		goto fail_cmd;
 	}
 
-	for (i = 0; i < num_copps; i++)
-		send_adm_cal(port_id[i], path, perf_mode);
+	if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
+		for (i = 0; i < num_copps; i++)
+			send_adm_cal(port_id[i], path, perf_mode);
 
-	for (i = 0; i < num_copps; i++) {
-		int tmp, copp_id;
-		tmp = afe_get_port_index(port_id[i]);
-		if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
-			if (!perf_mode)
-				copp_id = atomic_read(&this_adm.copp_id[tmp]);
-			else
-				copp_id =
-				atomic_read(&this_adm.copp_low_latency_id[tmp]);
-			rtac_add_adm_device(port_id[i],
+		for (i = 0; i < num_copps; i++) {
+			int tmp, copp_id;
+			tmp = afe_get_port_index(port_id[i]);
+			if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+				if (perf_mode == LEGACY_PCM_MODE)
+					copp_id = atomic_read(
+					&this_adm.copp_id[tmp]);
+				else
+					copp_id = atomic_read(
+					&this_adm.copp_low_latency_id[tmp]);
+				rtac_add_adm_device(port_id[i],
 						copp_id, path, session_id);
-			pr_debug("%s, copp_id: %d\n", __func__, copp_id);
-		} else {
-			pr_debug("%s: Invalid port index %d", __func__, tmp);
+				pr_debug("%s, copp_id: %d\n",
+							__func__, copp_id);
+			} else
+				pr_debug("%s: Invalid port index %d",
+							__func__, tmp);
 		}
 	}
 
@@ -1570,7 +1579,7 @@
 	pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
 }
 
-int adm_close(int port_id, bool perf_mode)
+int adm_close(int port_id, int perf_mode)
 {
 	struct apr_hdr close;
 
@@ -1587,7 +1596,8 @@
 	pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
 		index, perf_mode);
 
-	if (perf_mode) {
+	if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+				perf_mode == LOW_LATENCY_PCM_MODE) {
 		if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
 			pr_err("%s: copp count for port[%#x]is 0\n", __func__,
 				port_id);
@@ -1602,8 +1612,9 @@
 		}
 		atomic_dec(&this_adm.copp_cnt[index]);
 	}
-	if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
-		(perf_mode &&
+	if ((perf_mode == LEGACY_PCM_MODE &&
+		!(atomic_read(&this_adm.copp_cnt[index]))) ||
+		((perf_mode != LEGACY_PCM_MODE) &&
 		!(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
 
 		pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
@@ -1616,7 +1627,8 @@
 		close.src_port = port_id;
 		close.dest_svc = APR_SVC_ADM;
 		close.dest_domain = APR_DOMAIN_ADSP;
-		if (perf_mode)
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+				perf_mode == LOW_LATENCY_PCM_MODE)
 			close.dest_port =
 			     atomic_read(&this_adm.copp_low_latency_id[index]);
 		else
@@ -1626,7 +1638,8 @@
 
 		atomic_set(&this_adm.copp_stat[index], 0);
 
-		if (perf_mode) {
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+				perf_mode == LOW_LATENCY_PCM_MODE) {
 			copp_id = atomic_read(
 				&this_adm.copp_low_latency_id[index]);
 			pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
@@ -1666,8 +1679,10 @@
 		}
 	}
 
-	pr_debug("%s: remove adm device from rtac\n", __func__);
-	rtac_remove_adm_device(port_id, copp_id);
+	if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
+		pr_debug("%s: remove adm device from rtac\n", __func__);
+		rtac_remove_adm_device(port_id, copp_id);
+	}
 
 fail_cmd:
 	return ret;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 631e9bd..24f5f3b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -39,6 +39,7 @@
 
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
+#include <sound/q6audio-v2.h>
 
 #include "audio_acdb.h"
 
@@ -354,7 +355,7 @@
 	session[ac->session] = 0;
 	mutex_unlock(&session_lock);
 	ac->session = 0;
-	ac->perf_mode = 0;
+	ac->perf_mode = LEGACY_PCM_MODE;
 	ac->fptr_cache_ops = NULL;
 	return;
 }
@@ -810,7 +811,7 @@
 	ac->cb = cb;
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
-	ac->perf_mode = false;
+	ac->perf_mode = LEGACY_PCM_MODE;
 	ac->fptr_cache_ops = NULL;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
@@ -1695,7 +1696,7 @@
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
-	if (ac->perf_mode) {
+	if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
 		open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
 				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
 	} else {
@@ -1781,8 +1782,10 @@
 
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
-	if (ac->perf_mode)
+	if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
 		open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
+	else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+		open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
 	else {
 		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
 		if (is_gapless_mode)