Merge "asoc: Add support for rouleur codec in machine driver"
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index f01a23e..6221a2f 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  */
 
 
@@ -81,6 +81,8 @@
 #define COMPRESSED_PERF_MODE_FLAG 0
 #endif
 
+#define DSD_BLOCK_SIZE_4 4
+
 struct msm_compr_gapless_state {
 	bool set_next_stream_id;
 	int32_t stream_opened[MAX_NUMBER_OF_STREAMS];
@@ -1240,6 +1242,11 @@
 		dsd_cfg.num_version = 0;
 		dsd_cfg.is_bitwise_big_endian = 1;
 		dsd_cfg.dsd_channel_block_size = 1;
+
+		if (codec_options->dsd_dec.blk_size == DSD_BLOCK_SIZE_4)
+			dsd_cfg.dsd_channel_block_size =
+				codec_options->dsd_dec.blk_size;
+
 		ret = q6asm_media_format_block_dsd(prtd->audio_client,
 						   &dsd_cfg, stream_id);
 		if (ret < 0)
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 7c2d118..a0d9895 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -329,7 +329,8 @@
 	"NA6",
 	"NA7",
 	"NA8",
-	"DSD_DOP_W_MARKER"
+	"DSD_DOP_W_MARKER",
+	"NATIVE_DSD_DATA"
 };
 
 static const char *const mi2s_vi_feed_mono[] = {
@@ -338,7 +339,7 @@
 };
 
 static const struct soc_enum mi2s_config_enum[] = {
-	SOC_ENUM_SINGLE_EXT(10, mi2s_format),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mi2s_format), mi2s_format),
 	SOC_ENUM_SINGLE_EXT(2, mi2s_vi_feed_mono),
 };
 
@@ -5624,6 +5625,7 @@
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
 		mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.ws_src = 1;
 		mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.ws_src = 1;
 		break;
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index e4e6e6f..f9d6856 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -1554,7 +1554,7 @@
 				adm_open(port_id, path_type, sample_rate,
 					 channels, topology, perf_mode,
 					 bit_width, app_type, acdb_dev_id,
-					 session_type);
+					 session_type, passthr_mode);
 			if ((copp_idx < 0) ||
 				(copp_idx >= MAX_COPPS_PER_PORT)) {
 				pr_err("%s:adm open failed coppid:%d\n",
@@ -1906,7 +1906,7 @@
 					    sample_rate, channels, topology,
 					    perf_mode, bits_per_sample,
 					    app_type, acdb_dev_id,
-					    session_type);
+					    session_type, passthr_mode);
 			if ((copp_idx < 0) ||
 				(copp_idx >= MAX_COPPS_PER_PORT)) {
 				pr_err("%s: adm open failed copp_idx:%d\n",
@@ -2187,7 +2187,7 @@
 					    sample_rate, channels, topology,
 					    fdai->perf_mode, bits_per_sample,
 					    app_type, acdb_dev_id,
-					    session_type);
+					    session_type, passthr_mode);
 			if ((copp_idx < 0) ||
 			    (copp_idx >= MAX_COPPS_PER_PORT)) {
 				pr_err("%s: adm open failed\n", __func__);
@@ -29738,7 +29738,7 @@
 					    sample_rate, channels, topology,
 					    fdai->perf_mode, bits_per_sample,
 					    app_type, acdb_dev_id,
-					    session_type);
+					    session_type, fdai->passthr_mode);
 			if ((copp_idx < 0) ||
 				(copp_idx >= MAX_COPPS_PER_PORT)) {
 				pr_err("%s: adm open failed\n", __func__);
diff --git a/asoc/qcs405.c b/asoc/qcs405.c
index 18dfb82..e9e781f 100644
--- a/asoc/qcs405.c
+++ b/asoc/qcs405.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -21,6 +21,7 @@
 #include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <dsp/audio_notifier.h>
+#include <dsp/apr_audio-v2.h>
 #include <dsp/q6afe-v2.h>
 #include <dsp/q6core.h>
 #include <dsp/msm_mdf.h>
@@ -173,6 +174,7 @@
 	u32 sample_rate;
 	u32 bit_format;
 	u32 channels;
+	u32 data_format;
 };
 
 struct msm_wsa881x_dev_info {
@@ -201,6 +203,7 @@
 	u32 tdm_micb_voltage;
 	u32 tdm_micb_current;
 	bool codec_is_csra;
+	void __iomem *mi2s_dsd_mode[MI2S_MAX];
 };
 
 struct msm_asoc_wcd93xx_codec {
@@ -471,6 +474,19 @@
 static const char *const vi_feed_ch_text[] = {"One", "Two"};
 static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
 					  "S32_LE"};
+static const char *const data_format_text[] = {
+	"LPCM",
+	"Compr",
+	"LPCM-60958",
+	"Compr-60958",
+	"NA4",
+	"NA5",
+	"NA6",
+	"NA7",
+	"NA8",
+	"DSD_DOP_W_MARKER",
+	"NATIVE_DSD_DATA"
+};
 static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
 					"KHZ_32", "KHZ_44P1", "KHZ_48",
 					"KHZ_88P2", "KHZ_96", "KHZ_176P4",
@@ -599,6 +615,8 @@
 static SOC_ENUM_SINGLE_EXT_DECL(sen_mi2s_tx_chs, mi2s_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_data_format, data_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_data_format, data_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_sample_rate, mi2s_rate_text);
@@ -3049,7 +3067,8 @@
 		return idx;
 
 	/* check for PRIM_MI2S and CSRAx config to allow 24bit BE config only */
-	if ((PRIM_MI2S == idx) && (true==pdata->codec_is_csra))
+	if ((idx == PRIM_MI2S) && (pdata->codec_is_csra == true)
+			&& mi2s_rx_cfg[idx].data_format != AFE_DSD_DATA)
 	{
 		mi2s_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
 		pr_debug("%s: Keeping default format idx[%d]_rx_format = %d, item = %d\n",
@@ -3103,6 +3122,74 @@
 	return 0;
 }
 
+static int msm_mi2s_tx_data_format_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	mi2s_tx_cfg[idx].data_format = ucontrol->value.enumerated.item[0];
+
+	pr_debug("%s: idx[%d]_data_format = %d, item = %d\n", __func__,
+		  idx, mi2s_tx_cfg[idx].data_format,
+		  ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_mi2s_rx_data_format_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	mi2s_rx_cfg[idx].data_format = ucontrol->value.enumerated.item[0];
+
+	pr_debug("%s: idx[%d]_data_format = %d, item = %d\n", __func__,
+		  idx, mi2s_rx_cfg[idx].data_format,
+		  ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_mi2s_tx_data_format_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].data_format;
+
+	pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+		idx, mi2s_tx_cfg[idx].data_format,
+		ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_mi2s_rx_data_format_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].data_format;
+
+	pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+		idx, mi2s_rx_cfg[idx].data_format,
+		ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
 static int msm_meta_mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
 {
 	int idx = 0;
@@ -4125,6 +4212,18 @@
 			msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
 	SOC_ENUM_EXT("SEN_MI2S_TX Channels", sen_mi2s_tx_chs,
 			msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+	SOC_ENUM_EXT("PRIM_MI2S_TX DataFormat", mi2s_tx_data_format,
+			msm_mi2s_tx_data_format_get,
+				msm_mi2s_tx_data_format_put),
+	SOC_ENUM_EXT("QUAT_MI2S_TX DataFormat", mi2s_tx_data_format,
+			msm_mi2s_tx_data_format_get,
+				msm_mi2s_tx_data_format_put),
+	SOC_ENUM_EXT("PRIM_MI2S_RX DataFormat", mi2s_rx_data_format,
+			msm_mi2s_rx_data_format_get,
+				msm_mi2s_rx_data_format_put),
+	SOC_ENUM_EXT("QUAT_MI2S_RX DataFormat", mi2s_rx_data_format,
+			msm_mi2s_rx_data_format_get,
+				msm_mi2s_rx_data_format_put),
 	SOC_ENUM_EXT("PRIM_MI2S_RX Format", mi2s_rx_format,
 			msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
 	SOC_ENUM_EXT("PRIM_MI2S_TX Format", mi2s_tx_format,
@@ -6107,7 +6206,7 @@
 
 static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
 {
-	int ret = 0;
+	int ret = 0, val = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
@@ -6115,6 +6214,12 @@
 	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int data_format;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		data_format = mi2s_rx_cfg[index].data_format;
+	else
+		data_format = mi2s_tx_cfg[index].data_format;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
@@ -6140,6 +6245,9 @@
 			mi2s_clk[index].clk_id = mi2s_ebit_clk[index];
 			fmt = SND_SOC_DAIFMT_CBM_CFM;
 		}
+
+		if (data_format == AFE_DSD_DATA)
+			fmt = SND_SOC_DAIFMT_CBM_CFS;
 		ret = msm_mi2s_set_sclk(substream, true);
 		if (ret < 0) {
 			dev_err(rtd->card->dev,
@@ -6154,9 +6262,34 @@
 				__func__, index, ret);
 			goto clk_off;
 		}
-		if (pdata->mi2s_gpio_p[index])
-			msm_cdc_pinctrl_select_active_state(
+
+		if (pdata->mi2s_gpio_p[index]) {
+			if ((data_format == AFE_DSD_DATA) &&
+					((index == QUAT_MI2S) ||
+						(index == PRIM_MI2S))) {
+				msm_cdc_pinctrl_select_alt_active_state(
+						pdata->mi2s_gpio_p[index]);
+			} else {
+				msm_cdc_pinctrl_select_active_state(
 					pdata->mi2s_gpio_p[index]);
+			}
+		}
+
+		if (index == QUAT_MI2S || index == PRIM_MI2S) {
+			switch (data_format) {
+			case AFE_DSD_DATA:
+				if (pdata->mi2s_dsd_mode[index]) {
+					val = ioread32(
+						pdata->mi2s_dsd_mode[index]);
+					val = val | 0x1;
+					iowrite32(val,
+						pdata->mi2s_dsd_mode[index]);
+				}
+				break;
+			default:
+				break;
+			}
+		}
 	}
 
 	ret = qcs405_send_island_vad_config(dai_link->id);
@@ -6180,11 +6313,18 @@
 static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
 {
 	int ret;
+	int val;
+	int data_format;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int index = rtd->cpu_dai->id;
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		data_format = mi2s_rx_cfg[index].data_format;
+	else
+		data_format = mi2s_tx_cfg[index].data_format;
+
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
 	if (index < PRIM_MI2S || index >= MI2S_MAX) {
@@ -6198,6 +6338,22 @@
 			msm_cdc_pinctrl_select_sleep_state(
 					pdata->mi2s_gpio_p[index]);
 
+		if (index == QUAT_MI2S || index == PRIM_MI2S) {
+			switch (data_format) {
+			case AFE_DSD_DATA:
+				if (pdata->mi2s_dsd_mode[index]) {
+					val = ioread32(
+						pdata->mi2s_dsd_mode[index]);
+					val = val & ~1;
+					iowrite32(val,
+						pdata->mi2s_dsd_mode[index]);
+				}
+				break;
+			default:
+				break;
+			}
+		}
+
 		ret = msm_mi2s_set_sclk(substream, false);
 		if (ret < 0)
 			pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
@@ -9436,6 +9592,7 @@
 	const char *micb_supply_str1 = "tdm-vdd-micb";
 	const char *micb_voltage_str = "qcom,tdm-vdd-micb-voltage";
 	const char *micb_current_str = "qcom,tdm-vdd-micb-current";
+	u32 v_base_addr;
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -9447,6 +9604,31 @@
 	if (!pdata)
 		return -ENOMEM;
 
+	ret = of_property_read_u32(
+		pdev->dev.of_node, "tcsr_i2s_dsd_prim", &v_base_addr);
+	if (ret) {
+		dev_err(&pdev->dev, "MUX addr invalid for MI2S dsd prim\n");
+	} else {
+		pdata->mi2s_dsd_mode[PRIM_MI2S] =
+			devm_ioremap(&pdev->dev, v_base_addr, 4);
+		if (pdata->mi2s_dsd_mode[PRIM_MI2S] == NULL) {
+			pr_err("%s ioremap failure for muxsel virt addr dsd prim\n",
+				__func__);
+		}
+	}
+	ret = of_property_read_u32(
+		pdev->dev.of_node, "tcsr_i2s_dsd_quat", &v_base_addr);
+	if (ret) {
+		dev_err(&pdev->dev, "MUX addr invalid for MI2S dsd quat\n");
+	} else {
+		pdata->mi2s_dsd_mode[QUAT_MI2S] =
+			devm_ioremap(&pdev->dev, v_base_addr, 4);
+		if (pdata->mi2s_dsd_mode[QUAT_MI2S] == NULL) {
+			pr_err("%s ioremap failure for muxsel virt addr dsd quat\n",
+				__func__);
+		}
+	}
+
 	/* test for ep92 HDMI bridge and update dai links accordingly */
 	ret = msm_detect_ep92_dev(pdev, card);
 	if (ret)
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 9a4a7f9..a2f644f 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -2986,7 +2986,7 @@
  */
 int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
 	     int perf_mode, uint16_t bit_width, int app_type, int acdb_id,
-	     int session_type)
+	     int session_type, uint32_t passthr_mode)
 {
 	struct adm_cmd_device_open_v5	open;
 	struct adm_cmd_device_open_v6	open_v6;
@@ -3199,7 +3199,9 @@
 			}
 
 			open_v8.topology_id = topology;
-			open_v8.reserved = 0;
+			open_v8.compressed_data_type = 0;
+			if (passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
+				open_v8.compressed_data_type = 1;
 
 			/* variable endpoint payload */
 			ep1_payload.dev_num_channel = channel_mode & 0x00FF;
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 08efe1a..6b0a377 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -3096,6 +3096,10 @@
 		open.mode_flags = 0x1;
 		open.frames_per_buf = 1;
 		pr_debug("%s: Flag 1 IEC61937 output\n", __func__);
+	} else if (format == FORMAT_DSD) {
+		open.mode_flags = ASM_DSD_FORMAT_FLAG;
+		open.frames_per_buf = 1;
+		pr_debug("%s: Flag 2 DSD output\n", __func__);
 	} else {
 		open.mode_flags = 0;
 		open.frames_per_buf = 1;
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index dccd5ed..46cf6d3 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -598,7 +598,7 @@
  * In all other use cases this should be set to 0xffff
  */
 
-	u16                  reserved;
+	u16 compressed_data_type;
 } __packed;
 
 /*
@@ -2554,6 +2554,7 @@
 #define AFE_GENERIC_COMPRESSED           0x8
 #define AFE_LINEAR_PCM_DATA_PACKED_16BIT 0X6
 #define AFE_DSD_DOP_W_MARKER_DATA        0x9
+#define AFE_DSD_DATA                     0xA
 
 /* This param id is used to configure I2S interface */
 #define AFE_PARAM_ID_I2S_CONFIG	0x0001020D
@@ -8878,6 +8879,13 @@
 /* Shift value for the IEC 61937 to 61937 pass-through capture. */
 #define ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG           0
 
+/* Bitmask for the DSD pass-through capture. */
+#define ASM_BIT_MASK_COMPRESSED_FORMAT_FLAG             (0x00000003UL)
+
+/* Shift value for the DSD pass-through capture. */
+#define ASM_SHIFT_DSD_COMPRESSED_FORMAT_FLAG            0
+
+#define ASM_DSD_FORMAT_FLAG                             2
 struct asm_stream_cmd_open_read_compressed {
 	struct apr_hdr hdr;
 	u32                    mode_flags;
@@ -8889,6 +8897,12 @@
  * - Use #ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG to set the bitmask
  *   and #ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG to set the shift value
  *   for this bit.
+ * Supported values for bit 1: (DSD native pass-through mode)
+ * 0 -- non DSD operation
+ * 1 -- Pass-through transfer of the DSD format stream
+ * To set this bit, use #ASM_BIT_MASK_DSD_PASS_THROUGH_FLAG and
+ * use #ASM_SHIFT_DSD_PASS_THROUGH_FLAG to set the shift value for
+ * this bit
  * Supported values for bit 4:
  * - 0 -- Return data buffer contains all encoded frames only; it does
  *      not contain frame metadata.
@@ -8905,6 +8919,9 @@
  * Supported values: should be greater than 0 for IEC to RAW compressed
  *                   unpack mode.
  *                   Value is don't care for IEC 61937 pass-through mode.
+ * @values
+ * - >0 -- For IEC 61937-to-RAW Compressed Unpack mode
+ * - 1  -- For IEC 61937 or DSD Pass-through mode
  */
 
 } __packed;
diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h
index 6180cc7..53514c3 100644
--- a/include/dsp/q6adm-v2.h
+++ b/include/dsp/q6adm-v2.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  */
 #ifndef __Q6_ADM_V2_H__
 #define __Q6_ADM_V2_H__
@@ -118,7 +118,8 @@
 
 int adm_open(int port, int path, int rate, int mode, int topology,
 			   int perf_mode, uint16_t bits_per_sample,
-			   int app_type, int acdbdev_id, int session_type);
+			   int app_type, int acdbdev_id, int session_type,
+			   uint32_t pass_thr);
 
 int adm_map_rtac_block(struct rtac_cal_block_data *cal_block);