SoC: msm: qdsp6v2: Add TDM changes in dai driver

Update dai driver with TDM dai related changes. Add
a property to help not configure the AFE EBIT on platforms
where it is not supported.

Change-Id: Ic10cbb58f31698ceb03a07d94c8834515e828a93
Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
Signed-off-by: Ashish Jain <ashishj@codeaurora.org>
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 27d8bf3..85d5f94 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -234,17 +234,22 @@
 	struct msm_dai_q6_dai_data bdai_data; /* incoporate base DAI data */
 };
 
+static union afe_port_group_config group_cfg_tx;
+
 struct msm_dai_q6_tdm_dai_data {
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
 	u32 rate;
 	u32 channels;
 	u32 bitwidth;
 	u32 num_group_ports;
+	bool afe_ebit_unsupported;
 	struct afe_clk_set clk_set; /* hold LPASS clock config. */
 	union afe_port_group_config group_cfg; /* hold tdm group config */
 	struct afe_tdm_port_config port_cfg; /* hold tdm config */
 };
 
+static bool afe_ebit_unsupported;
+
 /* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
  *  0: linear PCM
  *  1: non-linear PCM
@@ -5389,6 +5394,11 @@
 		goto rtn;
 	}
 
+	afe_ebit_unsupported = of_property_read_bool(pdev->dev.of_node,
+				"qcom,msm-cpudai-tdm-afe-ebit-unsupported");
+
+	dev_dbg(&pdev->dev, "afe_ebit_unsupported %d\n", afe_ebit_unsupported);
+
 	/* other initializations within device group */
 	group_idx = msm_dai_q6_get_group_idx(tdm_group_cfg.group_id);
 	if (group_idx < 0) {
@@ -6344,6 +6354,10 @@
 {
 	int rc = 0;
 
+	pr_debug("dai_data->group_cfg.tdm_cfg.group_id = %d : %d\n",
+			dai_data->group_cfg.tdm_cfg.group_id,
+			dai_data->clk_set.clk_freq_in_hz);
+
 	dai_data->clk_set.enable = enable;
 
 	rc = afe_set_lpass_clock_v2(port_id,
@@ -6570,6 +6584,11 @@
 		tdm_group->nslots_per_frame = slots;
 		tdm_group->slot_width = slot_width;
 		tdm_group->slot_mask = rx_mask & cap_mask;
+		dev_dbg(dai->dev, "%s:Rx:tdm_group->nslots_per_frame %d\n"
+				"tdm_group->slot_width %d\n"
+				"tdm_group->slot_mask %d\n", __func__,
+				tdm_group->nslots_per_frame,
+				tdm_group->slot_width, tdm_group->slot_mask);
 		break;
 	case AFE_PORT_ID_PRIMARY_TDM_TX:
 	case AFE_PORT_ID_PRIMARY_TDM_TX_1:
@@ -6614,6 +6633,10 @@
 		tdm_group->nslots_per_frame = slots;
 		tdm_group->slot_width = slot_width;
 		tdm_group->slot_mask = tx_mask & cap_mask;
+		dev_dbg(dai->dev, "%s:Tx:tdm_group->nslots_per_frame %d\n"
+			"tdm_group->slot_width %d,tdm_group->slot_mask %d\n"
+			"tx%d\n", __func__, tdm_group->nslots_per_frame,
+			tdm_group->slot_width, tdm_group->slot_mask, tx_mask);
 		break;
 	default:
 		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
@@ -6946,6 +6969,23 @@
 			custom_tdm_header->header[7]);
 	}
 
+	memcpy(&group_cfg_tx.group_cfg, &dai_data->group_cfg.group_cfg,
+			sizeof(dai_data->group_cfg.group_cfg));
+	memcpy(&group_cfg_tx.group_enable, &dai_data->group_cfg.group_enable,
+			sizeof(dai_data->group_cfg.group_enable));
+	memcpy(&group_cfg_tx.tdm_cfg, &dai_data->group_cfg.tdm_cfg,
+			sizeof(dai_data->group_cfg.tdm_cfg));
+	pr_debug("%s: TDM GROUP:\n"
+		"num_channels=%d sample_rate=%d bit_width=%d\n"
+		"nslots_per_frame=%d slot_width=%d slot_mask=0x%x\n",
+		__func__,
+		group_cfg_tx.tdm_cfg.num_channels,
+		group_cfg_tx.tdm_cfg.sample_rate,
+		group_cfg_tx.tdm_cfg.bit_width,
+		group_cfg_tx.tdm_cfg.nslots_per_frame,
+		group_cfg_tx.tdm_cfg.slot_width,
+		group_cfg_tx.tdm_cfg.slot_mask);
+
 	return 0;
 }
 
@@ -6957,6 +6997,8 @@
 		dev_get_drvdata(dai->dev);
 	u16 group_id = dai_data->group_cfg.tdm_cfg.group_id;
 	int group_idx = 0;
+	u16 prim_port_id = 0;
+	u16 sec_port_id = 0;
 	atomic_t *group_ref = NULL;
 
 	group_idx = msm_dai_q6_get_group_idx(dai->id);
@@ -6979,12 +7021,16 @@
 			 * AFE clk is enabled per group to simplify the logic.
 			 * DSP will monitor the clk count.
 			 */
-			rc = msm_dai_q6_tdm_set_clk(dai_data,
-				dai->id, true);
-			if (rc < 0) {
-				dev_err(dai->dev, "%s: fail to enable AFE clk 0x%x\n",
-					__func__, dai->id);
-				goto rtn;
+			if (!(dai_data->afe_ebit_unsupported &&
+				!dai_data->clk_set.clk_freq_in_hz)) {
+
+				rc = msm_dai_q6_tdm_set_clk(dai_data,
+					dai->id, true);
+				if (rc < 0) {
+					dev_err(dai->dev, "%s: fail to enable AFE clk 0x%x\n",
+						__func__, dai->id);
+					goto rtn;
+				}
 			}
 
 			/*
@@ -6992,32 +7038,95 @@
 			 * is no group need for only one port
 			 */
 			if (dai_data->num_group_ports > 1) {
+				dev_dbg(dai->dev, "%s:enable RX afe group\n",
+					__func__);
 				rc = afe_port_group_enable(group_id,
 					&dai_data->group_cfg, true);
 				if (rc < 0) {
 					dev_err(dai->dev,
-					"%s: fail to enable AFE group 0x%x\n",
+					"%s: fail to enable grp %x\n",
 					__func__, group_id);
 					goto rtn;
 				}
 			}
 		}
 
-		rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg,
+		/*
+		 * 8909 HW has a dependency where for Rx/Tx to work in TDM mode
+		 * We need to start a Tx or Rx port in the same group.
+		 * Hence for BG use TDM_TX when a RX session is requested and
+		 * use TDM_RX port when a TX session is requested as these ports
+		 * are unused as of now.
+		 */
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			prim_port_id = dai->id;
+			if (dai_data->afe_ebit_unsupported)
+				sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX;
+		} else {
+			prim_port_id = dai->id;
+			if (dai_data->afe_ebit_unsupported)
+				sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX;
+		}
+		dev_dbg(dai->dev, "\n%s:open prim port id %d TDM rate: %d\n"
+				"dai_data->port_cfg.tdm.slot_mask %x\n"
+				"dai_data->port_cfg.tdm.nslots_per_frame:%x\n",
+				__func__, prim_port_id,
+				dai_data->port_cfg.tdm.num_channels,
+				dai_data->port_cfg.tdm.slot_mask,
+				dai_data->port_cfg.tdm.nslots_per_frame);
+
+		rc = afe_tdm_port_start(prim_port_id, &dai_data->port_cfg,
 			dai_data->rate, dai_data->num_group_ports);
+
 		if (rc < 0) {
 			if (atomic_read(group_ref) == 0) {
 				afe_port_group_enable(group_id,
 					NULL, false);
-				msm_dai_q6_tdm_set_clk(dai_data,
-					dai->id, false);
+				if (!(dai_data->afe_ebit_unsupported &&
+					!dai_data->clk_set.clk_freq_in_hz))
+					msm_dai_q6_tdm_set_clk(dai_data,
+						dai->id, false);
 			}
-			dev_err(dai->dev, "%s: fail to open AFE port 0x%x\n",
-				__func__, dai->id);
+			dev_err(dai->dev, "%s: open AFE port 0x%x\n",
+				__func__, prim_port_id);
 		} else {
 			set_bit(STATUS_PORT_STARTED,
 				dai_data->status_mask);
 			atomic_inc(group_ref);
+
+		}
+
+		dai_data->port_cfg.tdm.num_channels = 1;
+		dai_data->port_cfg.tdm.slot_mask = 1;
+		dai_data->port_cfg.tdm.nslots_per_frame = 4;
+
+		dev_dbg(dai->dev, "\n%s:open sec port id %d TDM rate: %d\n"
+			"dai_data->port_cfg.tdm.slot_mask %x\n"
+			"dai_data->port_cfg.tdm.nslotsper_frame:%x\n", __func__,
+		sec_port_id, dai_data->port_cfg.tdm.num_channels,
+		dai_data->port_cfg.tdm.slot_mask,
+		dai_data->port_cfg.tdm.nslots_per_frame);
+
+		if (sec_port_id != 0) {
+			rc = afe_tdm_port_start(sec_port_id,
+						&dai_data->port_cfg,
+						dai_data->rate, 4);
+			if (IS_ERR_VALUE(rc)) {
+				if (atomic_read(group_ref) == 0) {
+					afe_port_group_enable(group_id,
+							NULL, false);
+					msm_dai_q6_tdm_set_clk(dai_data,
+					dai->id, false);
+				}
+				dev_err(dai->dev, "%s: fail AFE port 0x%x\n",
+					__func__, sec_port_id);
+			} else {
+				set_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+				atomic_inc(group_ref);
+			}
+
 		}
 
 		/* TODO: need to monitor PCM/MI2S/TDM HW status */
@@ -7038,6 +7147,8 @@
 		dev_get_drvdata(dai->dev);
 	u16 group_id = dai_data->group_cfg.tdm_cfg.group_id;
 	int group_idx = 0;
+	u16 prim_port_id = 0;
+	u16 sec_port_id = 0;
 	atomic_t *group_ref = NULL;
 
 	group_idx = msm_dai_q6_get_group_idx(dai->id);
@@ -7052,11 +7163,30 @@
 	group_ref = &tdm_group_ref[group_idx];
 
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		rc = afe_close(dai->id);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			prim_port_id = dai->id;
+			if (dai_data->afe_ebit_unsupported)
+				sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX;
+		} else {
+			prim_port_id = dai->id;
+			if (dai_data->afe_ebit_unsupported)
+				sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX;
+		}
+
+		rc = afe_close(prim_port_id);
 		if (rc < 0) {
 			dev_err(dai->dev, "%s: fail to close AFE port 0x%x\n",
-				__func__, dai->id);
+				__func__, prim_port_id);
 		}
+
+		if (sec_port_id != 0) {
+			rc = afe_close(sec_port_id);
+			if (IS_ERR_VALUE(rc)) {
+				dev_err(dai->dev, "%s: fail AFE port 0x%x\n",
+					__func__, sec_port_id);
+			}
+		}
+
 		atomic_dec(group_ref);
 		clear_bit(STATUS_PORT_STARTED,
 			dai_data->status_mask);
@@ -7065,13 +7195,15 @@
 			rc = afe_port_group_enable(group_id,
 				NULL, false);
 			if (rc < 0) {
-				dev_err(dai->dev, "%s: fail to disable AFE group 0x%x\n",
+				dev_err(dai->dev,
+					"%s: fail to disable grp 0x%x\n",
 					__func__, group_id);
 			}
 			rc = msm_dai_q6_tdm_set_clk(dai_data,
 				dai->id, false);
 			if (rc < 0) {
-				dev_err(dai->dev, "%s: fail to disable AFE clk 0x%x\n",
+				dev_err(dai->dev,
+					"%s: fail to disable AFE clk 0x%x\n",
 					__func__, dai->id);
 			}
 		}
@@ -8886,6 +9018,34 @@
 	dai_data->num_group_ports = num_tdm_group_ports;
 
 
+
+
+	dev_dbg(&pdev->dev, "TX group configuration tdm_dev_id 0x%x\n",
+				tdm_dev_id);
+
+	dai_data->afe_ebit_unsupported = afe_ebit_unsupported;
+
+	if (tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX ||
+		tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_1 ||
+		tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_2 ||
+		tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_3) {
+		dev_dbg(&pdev->dev, "Copy TX group config id %d\n", tdm_dev_id);
+		/*memcpy (&group_cfg_tx,&dai_data->group_cfg ,
+				sizeof(dai_data->group_cfg));*/
+		memcpy(&group_cfg_tx.group_cfg,
+			&dai_data->group_cfg.group_cfg,
+			sizeof(dai_data->group_cfg.group_cfg));
+		memcpy(&group_cfg_tx.group_enable,
+			&dai_data->group_cfg.group_enable,
+			sizeof(dai_data->group_cfg.group_enable));
+		memcpy(&group_cfg_tx.tdm_cfg,
+			&dai_data->group_cfg.tdm_cfg,
+			sizeof(dai_data->group_cfg.tdm_cfg));
+		dev_dbg(&pdev->dev,
+			"Copy TX group configuration Successfully tdm_id %d\n",
+			tdm_dev_id);
+	}
+
 	dev_set_drvdata(&pdev->dev, dai_data);
 
 	port_idx = msm_dai_q6_get_port_idx(tdm_dev_id);