diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c index 983654b067f0..b0567019cef9 100644 --- a/asoc/msm-dai-q6-v2.c +++ b/asoc/msm-dai-q6-v2.c @@ -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); diff --git a/asoc/sa6155.c b/asoc/sa6155.c index 2d77b801b37f..b7e9dc49d424 100644 --- a/asoc/sa6155.c +++ b/asoc/sa6155.c @@ -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) diff --git a/asoc/sa8155.c b/asoc/sa8155.c index e0292f83bd79..78254f73a0fa 100644 --- a/asoc/sa8155.c +++ b/asoc/sa8155.c @@ -892,6 +892,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); @@ -946,6 +967,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] = { { @@ -2392,6 +2414,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; @@ -3597,6 +3850,16 @@ static const struct snd_kcontrol_new msm_common_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 const struct snd_kcontrol_new sa8295_msm_snd_controls[] = {