Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dd2d4b63 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "asoc: enables paired rx port to address tdm slot shift issue"

parents b1d01899 fab1b421
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -2858,7 +2858,7 @@ static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
	return 0;
}

static u16 num_of_bits_set(u16 sd_line_mask)
u16 num_of_bits_set(u16 sd_line_mask)
{
	u8 num_bits_set = 0;

@@ -2868,6 +2868,7 @@ static u16 num_of_bits_set(u16 sd_line_mask)
	}
	return num_bits_set;
}
EXPORT_SYMBOL(num_of_bits_set);

static int msm_dai_q6_i2s_hw_params(struct snd_pcm_hw_params *params,
				    struct snd_soc_dai *dai, int stream)
@@ -11663,6 +11664,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
	u16 group_id = dai_data->group_cfg.tdm_cfg.group_id;
	int group_idx = 0;
	atomic_t *group_ref = NULL;
	int intf_idx =  PORT_ID_TO_INTF_IDX(dai->id);

	dev_dbg(dai->dev, "%s: dev_name: %s dev_id: 0x%x group_id: 0x%x\n",
		 __func__, dev_name(dai->dev), dai->dev->id, group_id);
@@ -11683,7 +11685,6 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
	group_ref = &tdm_group_ref[group_idx];

	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {

		if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) {
			/* TX and RX share the same clk. So enable the clk
			 * per TDM interface. */
@@ -11695,7 +11696,18 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
				goto rtn;
			}
		}

		/* Paired Rx Port Start */
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			rc = afe_paired_rx_tdm_port_ops(intf_idx, true, tdm_group_ref);
			if (rc < 0) {
				pr_debug("%s:Paired Rx Port failed to start\n",__func__);
				if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) {
					msm_dai_q6_tdm_set_clk(dai_data,
						dai->id, false);
				}
				goto rtn;
			}
		}
		/* PORT START should be set if prepare called
		 * in active state.
		 */
@@ -11720,6 +11732,9 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
		rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg,
			dai_data->rate, dai_data->num_group_ports);
		if (rc < 0) {
			rc = afe_paired_rx_tdm_port_ops(intf_idx, false, tdm_group_ref);
			if (rc < 0)
				pr_err("%s:Unable to close Paired Rx due to tx usecase start failure", __func__);
			if (atomic_read(group_ref) == 0) {
				afe_port_group_enable(group_id,
					NULL, false, NULL);
@@ -11734,6 +11749,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
			set_bit(STATUS_PORT_STARTED,
				dai_data->status_mask);
			atomic_inc(group_ref);
			pr_debug("%s: Group ref count: group_ref : %d", __func__, group_ref->counter);
		}

		/* TODO: need to monitor PCM/MI2S/TDM HW status */
@@ -11755,6 +11771,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream,
	u16 group_id = dai_data->group_cfg.tdm_cfg.group_id;
	int group_idx = 0;
	atomic_t *group_ref = NULL;
	int intf_idx =  PORT_ID_TO_INTF_IDX(dai->id);

	group_idx = msm_dai_q6_get_group_idx(dai->id);
	if (group_idx < 0) {
@@ -11774,6 +11791,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream,
				__func__, dai->id);
		}
		atomic_dec(group_ref);
		pr_debug("%s: group_ref : %d \n",__func__, group_ref->counter);
		clear_bit(STATUS_PORT_STARTED,
			dai_data->status_mask);

@@ -11785,7 +11803,17 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream,
					__func__, group_id);
			}
		}

		/* Paired Rx Stop */
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			rc = afe_paired_rx_tdm_port_ops(intf_idx, false, tdm_group_ref);
			if (rc < 0){
				if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) {
					msm_dai_q6_tdm_set_clk(dai_data,
						dai->id, false);
				}
				pr_err("%s:AFE Paired Rx Port Not disabled");
			}
		}
		if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) {
			rc = msm_dai_q6_tdm_set_clk(dai_data,
				dai->id, false);
+263 −0
Original line number Diff line number Diff line
@@ -660,6 +660,27 @@ static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
					   "Eight"};
static const char *const qos_text[] = {"Disable", "Enable"};

static char const *tdm_pair_rx_format[] = {"PRI_TDM_RX_0", "PRI_TDM_RX_1",
					   "PRI_TDM_RX_2", "PRI_TDM_RX_3",
					   "PRI_TDM_RX_4", "PRI_TDM_RX_5",
					   "PRI_TDM_RX_6", "PRI_TDM_RX_7",
					   "SEC_TDM_RX_0", "SEC_TDM_RX_1",
					   "SEC_TDM_RX_2", "SEC_TDM_RX_3",
					   "SEC_TDM_RX_4", "SEC_TDM_RX_5",
					   "SEC_TDM_RX_6", "SEC_TDM_RX_7",
					   "TERT_TDM_RX_0", "TERT_TDM_RX_1",
					   "TERT_TDM_RX_2", "TERT_TDM_RX_3",
					   "TERT_TDM_RX_4", "TERT_TDM_RX_5",
					   "TERT_TDM_RX_6", "TERT_TDM_RX_7",
					   "QUAT_TDM_RX_0", "QUAT_TDM_RX_1",
					   "QUAT_TDM_RX_2", "QUAT_TDM_RX_3",
					   "QUAT_TDM_RX_4", "QUAT_TDM_RX_5",
					   "QUAT_TDM_RX_6", "QUAT_TDM_RX_7",
					   "QUIN_TDM_RX_0", "QUIN_TDM_RX_1",
					   "QUIN_TDM_RX_2", "QUIN_TDM_RX_3",
					   "QUIN_TDM_RX_4", "QUIN_TDM_RX_5",
					   "QUIN_TDM_RX_6", "QUIN_TDM_RX_7"};

static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text);
@@ -713,6 +734,7 @@ 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(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(tdm_paired_rx_format, tdm_pair_rx_format);

static struct afe_clk_set internal_mclk[MCLK_MAX] = {
	{
@@ -2123,6 +2145,237 @@ static int tdm_tx_slot_mapping_put(struct snd_kcontrol *kcontrol,
	return ret;
}

static int tdm_paired_rx_get(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_value *ucontrol)
{
	int ret = 0;
	int mode = tdm_get_mode(kcontrol);
	/*
	*mode gets the TDM interface value
	*0: Primary , 1: secondary, 2: Tertiary, 3: Quaternary, 4: QUINARY
	*/
	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n", __func__, kcontrol->id.name);
		return -EINVAL;
	}
	ucontrol->value.enumerated.item[0] = AFE_PORT_ID_INVALID;
	pr_debug("%s:Port Channel = %d", __func__, ucontrol->value.enumerated.item[0]);
	return ret;
}

static int tdm_paired_rx_put(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_value *ucontrol)
{
	int val = -1;
	int intf_idx = -1;
	int port_idx = -1;
	int index;
	int slot_array_index = 0;
	struct afe_tdm_port_config tdm_port;
	union afe_port_group_config tdm_group;
	struct afe_param_id_tdm_lane_cfg tdm_lane;
	int i = 0;
	int rc = 0;
	u16 num_bits_set = 0;
	int mode = tdm_get_mode(kcontrol);
	struct device_node *node = NULL;
	const uint32_t *port_id_array = NULL;
	uint32_t array_length = 0;
	static u32 num_tdm_group_ports;

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n", __func__, kcontrol->id.name);
		return -EINVAL;
	} else {
		memset(&tdm_port, 0, sizeof(tdm_port));
		memset(&tdm_group, 0, sizeof(tdm_group));
		memset(&tdm_lane, 0, sizeof(tdm_lane));

		val = ucontrol->value.enumerated.item[0];
		intf_idx = val / MAX_PORTS_PER_INTF;
		port_idx = val % MAX_PORTS_PER_INTF;
		if (mode != intf_idx) {
			pr_err("%s:Wrong value given for TDM Interface %d", __func__, intf_idx);
			return -EINVAL;
		}
		pr_debug("%s:Port Channel = %d Interface = %d", __func__, port_idx, intf_idx);
		while (tdm_rx_slot_offset[intf_idx][port_idx][slot_array_index] != AFE_SLOT_MAPPING_OFFSET_INVALID)
			slot_array_index++;
		switch (intf_idx) {
		case TDM_PRI:
			node = of_find_node_by_path("/soc/qcom,msm-dai-tdm-pri-rx");
			break;
		case TDM_SEC:
			node = of_find_node_by_path("/soc/qcom,msm-dai-tdm-sec-rx");
			break;
		case TDM_TERT:
			node = of_find_node_by_path("/soc/qcom,msm-dai-tdm-tert-rx");
			break;
		case TDM_QUAT:
			node = of_find_node_by_path("/soc/qcom,msm-dai-tdm-quat-rx");
			break;
		case TDM_QUIN:
			node = of_find_node_by_path("/soc/qcom,msm-dai-tdm-quin-rx");
			break;
		default:
			pr_err("%s:Wrong interface present", __func__);
			return -EINVAL;
		}

		/* Group Cfg */
		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-group-id",(u32 *)&tdm_group.tdm_cfg.group_id);
		if (rc) {
			pr_err("%s:Paired Rx Group Id not in DT File %s\n",__func__,"qcom,msm-cpudai-tdm-group-id");
			return -EINVAL;
		}

		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-group-num-ports",&num_tdm_group_ports);
		if (rc) {
			pr_err("%s:Paired Rx Group Num Ports from DT file %s\n",__func__, "qcom,msm-cpudai-tdm-group-num-ports");
			return -EINVAL;
		}
		if (num_tdm_group_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
			pr_err("%s:Paired Rx Group Num Ports %d greater than Max %d\n",__func__, num_tdm_group_ports,
				AFE_GROUP_DEVICE_NUM_PORTS);
			return -EINVAL;
		}
		/*
		*Will get the array of afe ports associated with the group id. and then are
		*converted from big endian to cpu's byte order values using be32_to_cpu function.
		*/
		port_id_array = of_get_property(node,"qcom,msm-cpudai-tdm-group-port-id",&array_length);
		if (port_id_array == NULL) {
			pr_err("%s:Paired rx port_id_array is not valid\n",__func__);
			return -EINVAL;
		}
		if (array_length != sizeof(uint32_t) * num_tdm_group_ports) {
			pr_err("%s:paired rx array_length is %d, expected is %zd\n",
				__func__, array_length,
				sizeof(uint32_t) * num_tdm_group_ports);
			return -EINVAL;
		}

		for (i = 0; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
			tdm_group.tdm_cfg.port_id[i] = AFE_PORT_INVALID;

		for (i = 0; i < num_tdm_group_ports; i++) {
			index = (((u16)be32_to_cpu(port_id_array[i]))/2)% MAX_PORTS_PER_INTF;
			tdm_group.tdm_cfg.port_id[index] =
				(u16)be32_to_cpu(port_id_array[i]);
			pr_debug("%s:Paired rx group port id is 0x%x",__func__,tdm_group.tdm_cfg.port_id[index]);
		}

		tdm_group.tdm_cfg.group_device_cfg_minor_version = AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG;
		tdm_group.tdm_cfg.reserved = 0;
		tdm_group.tdm_cfg.nslots_per_frame = tdm_slot[intf_idx].num;
		tdm_group.tdm_cfg.sample_rate = tdm_rx_cfg[intf_idx][port_idx].sample_rate;
		tdm_group.tdm_cfg.slot_width = tdm_slot[intf_idx].width;
		tdm_group.tdm_cfg.bit_width = tdm_group.tdm_cfg.slot_width;

		/* Lane Cfg */
		tdm_lane.port_id = tdm_group.group_cfg.group_id;
		tdm_lane.lane_mask = AFE_LANE_MASK_INVALID;
		if (of_find_property(node,"qcom,msm-cpudai-tdm-lane-mask", NULL)) {
			rc = of_property_read_u16(node,"qcom,msm-cpudai-tdm-lane-mask",&tdm_lane.lane_mask);
			if (rc) {
				pr_err("%s: value for tdm lane mask not found %s\n",__func__, "qcom,msm-cpudai-tdm-lane-mask");
				return -EINVAL;
			}
			pr_debug("%s: tdm lane mask from DT file %d\n",__func__, tdm_lane.lane_mask);
		} else
			pr_debug("%s: tdm lane mask not found\n", __func__);
		if (tdm_lane.lane_mask != AFE_LANE_MASK_INVALID) {
			num_bits_set = num_of_bits_set(tdm_lane.lane_mask);
			tdm_group.tdm_cfg.num_channels = tdm_group.tdm_cfg.nslots_per_frame * num_bits_set;
		} else {
			tdm_group.tdm_cfg.num_channels = tdm_group.tdm_cfg.nslots_per_frame;
		}

		/* TDM Cfg */
		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-sync-mode",(u32 *)&tdm_port.tdm.sync_mode);
		if (rc) {
			pr_err("%s:Paired rx Sync Mode from DT file %s\n",__func__, "qcom,msm-cpudai-tdm-sync-mode");
			return -EINVAL;
		}

		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-sync-src",(u32 *)&tdm_port.tdm.sync_src);
		if (rc) {
			pr_err("%s:Paired rx Sync Src from DT file %s\n",__func__, "qcom,msm-cpudai-tdm-sync-src");
			return -EINVAL;
		}

		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-data-out",(u32 *)&tdm_port.tdm.ctrl_data_out_enable);
		if (rc) {
			pr_err("%s:Paired rx Data Out from DT file %s\n",__func__, "qcom,msm-cpudai-tdm-data-out");
			return -EINVAL;
		}

		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-invert-sync",(u32 *)&tdm_port.tdm.ctrl_invert_sync_pulse);
		if (rc) {
			pr_err("%s:Paired rx Invert Sync from DT file %s\n",
				__func__, "qcom,msm-cpudai-tdm-invert-sync");
			return -EINVAL;
		}

		rc = of_property_read_u32(node,"qcom,msm-cpudai-tdm-data-delay",(u32 *)&tdm_port.tdm.ctrl_sync_data_delay);
		if (rc) {
			pr_err("%s:Paired rx Data Delay from DT file %s\n",__func__, "qcom,msm-cpudai-tdm-data-delay");
			return -EINVAL;
		}

		/* TDM Cfg  */
		tdm_port.tdm.data_format = AFE_LINEAR_PCM_DATA;
		tdm_port.tdm.tdm_cfg_minor_version = AFE_API_VERSION_TDM_CONFIG;
		tdm_port.tdm.num_channels = tdm_rx_cfg[intf_idx][port_idx].channels;
		tdm_port.tdm.sample_rate = tdm_rx_cfg[intf_idx][port_idx].sample_rate;
		tdm_port.tdm.bit_width = tdm_slot[intf_idx].width;
		tdm_port.tdm.nslots_per_frame = tdm_slot[intf_idx].num;
		tdm_port.tdm.slot_width = tdm_slot[intf_idx].width;

		/* Slot Mapping Cfg */
		tdm_port.slot_mapping.num_channel = tdm_rx_cfg[intf_idx][port_idx].channels;
		tdm_port.slot_mapping.bitwidth = tdm_slot[intf_idx].width;
		tdm_port.slot_mapping.data_align_type = AFE_SLOT_MAPPING_DATA_ALIGN_MSB;
		tdm_port.slot_mapping.minor_version = AFE_API_VERSION_SLOT_MAPPING_CONFIG;

		/* Slot Mapping v2 Cfg */
		tdm_port.slot_mapping_v2.num_channel = tdm_rx_cfg[intf_idx][port_idx].channels;
		tdm_port.slot_mapping_v2.bitwidth = tdm_slot[intf_idx].width;
		tdm_port.slot_mapping_v2.data_align_type = AFE_SLOT_MAPPING_DATA_ALIGN_MSB;
		tdm_port.slot_mapping_v2.minor_version = AFE_API_VERSION_SLOT_MAPPING_CONFIG_V2;

		for (i = 0; (i < slot_array_index) && (i < AFE_PORT_MAX_AUDIO_CHAN_CNT); i++)
			tdm_port.slot_mapping.offset[i] = tdm_rx_slot_offset[intf_idx][port_idx][i];

		for (i = slot_array_index; i < AFE_PORT_MAX_AUDIO_CHAN_CNT ; i++)
			tdm_port.slot_mapping.offset[i] = AFE_SLOT_MAPPING_OFFSET_INVALID;

		for (i = 0; (i < slot_array_index) && (i < AFE_PORT_MAX_AUDIO_CHAN_CNT_V2) ; i++)
			tdm_port.slot_mapping_v2.offset[i] = tdm_rx_slot_offset[intf_idx][port_idx][i];

		for (i = slot_array_index; i < AFE_PORT_MAX_AUDIO_CHAN_CNT_V2 ; i++)
			tdm_port.slot_mapping_v2.offset[i] = AFE_SLOT_MAPPING_OFFSET_INVALID;

		for (i = 0; i < tdm_slot[intf_idx].num ; i++)
			tdm_port.tdm.slot_mask |= 1 << i;

		tdm_port.custom_tdm_header.minor_version = AFE_API_VERSION_CUSTOM_TDM_HEADER_CONFIG;
		tdm_port.custom_tdm_header.header_type = AFE_CUSTOM_TDM_HEADER_TYPE_INVALID;

		tdm_group.tdm_cfg.slot_mask = tdm_port.tdm.slot_mask;

		pr_debug("%s:Paired Rx Info\n"
		 "Group Id: 0x%x, Group Num Ports: 0x%x, Sync Mode: 0x%x\n"
		 "Sync Src: 0x%x, Data Out: 0x%x, Invert Sync: 0x%x, Data Delay: 0x%x\n",
		 __func__, tdm_group.tdm_cfg.group_id, num_tdm_group_ports,
		 tdm_port.tdm.sync_mode, tdm_port.tdm.sync_src,
		 tdm_port.tdm.ctrl_data_out_enable, tdm_port.tdm.ctrl_invert_sync_pulse,
		 tdm_port.tdm.ctrl_sync_data_delay);
		afe_tdm_paired_rx_cfg_val(intf_idx, tdm_group.tdm_cfg.port_id[port_idx], tdm_group, tdm_port, tdm_lane);
	}
	return 0;
}

static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
{
	int idx;
@@ -3326,6 +3579,16 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
			msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
	SOC_ENUM_EXT("QUIN_AUX_PCM_TX Format", aux_pcm_tx_format,
			msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
	SOC_ENUM_EXT("PRI_TDM Paired_Rx", tdm_paired_rx_format,
			tdm_paired_rx_get, tdm_paired_rx_put),
	SOC_ENUM_EXT("SEC_TDM Paired_Rx", tdm_paired_rx_format,
			tdm_paired_rx_get, tdm_paired_rx_put),
	SOC_ENUM_EXT("TERT_TDM Paired_Rx", tdm_paired_rx_format,
			tdm_paired_rx_get, tdm_paired_rx_put),
	SOC_ENUM_EXT("QUAT_TDM Paired_Rx", tdm_paired_rx_format,
			tdm_paired_rx_get, tdm_paired_rx_put),
	SOC_ENUM_EXT("QUIN_TDM Paired_Rx", tdm_paired_rx_format,
			tdm_paired_rx_get, tdm_paired_rx_put),
};

static inline int param_is_mask(int p)
+263 −0

File changed.

Preview size limit exceeded, changes collapsed.