From 282aeeb3759aff189299a6287ef812beb881ef8c Mon Sep 17 00:00:00 2001 From: Krishna Kishor Jha Date: Mon, 27 Jun 2022 21:27:36 +0530 Subject: [PATCH 1/6] audio-routing: Support Rx to Tx loopback Static loopback is created between QUIN_TDM_RX_0 to Tx session. Tx session is created with quin_tdm_tx_7 dummy port. Change-Id: Ic634b47d1d7f80a10c6d2bc341a6d3ca8eae34c1 --- asoc/msm-pcm-routing-auto.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/asoc/msm-pcm-routing-auto.c b/asoc/msm-pcm-routing-auto.c index f013d14271d0..cb220eeab6d8 100644 --- a/asoc/msm-pcm-routing-auto.c +++ b/asoc/msm-pcm-routing-auto.c @@ -56,6 +56,11 @@ #define STRING_LENGTH_OF_INT 12 #define MAX_USR_CTRL_CNT 128 +#ifdef RX_TO_TX_LOOPBACK +#define RX_TO_TX_LOOPBACK_DUMMY_TX_PORT AFE_PORT_ID_QUINARY_TDM_TX_7 +#define RX_TO_TX_LOOPBACK_RX_PORT AFE_PORT_ID_QUINARY_TDM_RX +#endif + static struct mutex routing_lock; static struct cal_type_data *cal_data[MAX_ROUTING_CAL_TYPES]; @@ -2527,7 +2532,19 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, &ec_ref_chmix_cfg[fedai_id]); /* reset ec_ref config */ ec_ref_chmix_cfg[fedai_id].output_channel = 0; - } else + } +#ifdef RX_TO_TX_LOOPBACK + else if(session_type == SESSION_TYPE_TX && + port_id == RX_TO_TX_LOOPBACK_DUMMY_TX_PORT) { + port_id = RX_TO_TX_LOOPBACK_RX_PORT; + copp_idx = adm_open(port_id, path_type, + sample_rate, channels, topology, + copp_perf_mode, bits_per_sample, + app_type, acdb_dev_id, + session_type, passthr_mode, copp_token); + } +#endif + else copp_idx = adm_open(port_id, path_type, sample_rate, channels, topology, copp_perf_mode, bits_per_sample, @@ -19500,6 +19517,12 @@ static const struct snd_kcontrol_new mmul1_mixer_controls[] = { MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), +#ifdef RX_TO_TX_LOOPBACK + SOC_DOUBLE_EXT("QUIN_TDM_TX_7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUIN_TDM_TX_7, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +#endif SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM, MSM_BACKEND_DAI_QUIN_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, @@ -28315,7 +28338,9 @@ static const struct snd_soc_dapm_route intercon_tdm[] = { {"MultiMedia1 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, {"MultiMedia1 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, {"MultiMedia1 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, - +#ifdef RX_TO_TX_LOOPBACK + {"MultiMedia1 Mixer", "QUIN_TDM_TX_7", "QUIN_TDM_TX_7"}, +#endif {"MultiMedia1 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"}, {"MultiMedia1 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"}, {"MultiMedia1 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"}, From 2283a81ea0118e48ed1f401a105b504abc2dac73 Mon Sep 17 00:00:00 2001 From: Kogara Naveen Kumar Date: Thu, 7 Apr 2022 14:30:38 +0530 Subject: [PATCH 2/6] audio-kernel: Reset client info on deregister. For elite and audioreach co-exit, we need keep source file same. This patch exit in audioreach but not included in elite, cp it to keep file same. Leveraged from audio-ar commit id ac15eb7016aff23a2be2a57289635d741cb95340 Change-Id: I187909403e9b54c8f6836477208de5e8311bf4ff Signed-off-by: Kogara Naveen Kumar --- soc/snd_event.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/soc/snd_event.c b/soc/snd_event.c index b20cdf422fe2..df8b6ff37227 100644 --- a/soc/snd_event.c +++ b/soc/snd_event.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -233,6 +234,9 @@ int snd_event_client_deregister(struct device *dev) return -EINVAL; } + dev_dbg(dev, "%s: removing client to SND event FW \n", + __func__); + mutex_lock(&snd_event_mutex); if (list_empty(&snd_event_client_list)) { dev_dbg(dev, "%s: No SND client registered\n", __func__); @@ -249,7 +253,7 @@ int snd_event_client_deregister(struct device *dev) c->state = false; - if (master && master->clients_found) { + if (master) { struct snd_event_client *d; bool dev_found = false; @@ -260,9 +264,12 @@ int snd_event_client_deregister(struct device *dev) break; } } - if (dev_found) { - ret = check_and_update_fwk_state(); - master->clients_found = false; + if (dev_found ) { + if(master->clients_found) { + ret = check_and_update_fwk_state(); + master->clients_found = false; + } + master->clients->cl_arr[i].dev = NULL; } } @@ -465,6 +472,9 @@ int snd_event_notify(struct device *dev, unsigned int state) return -EINVAL; } + dev_dbg(dev, "%s: snd_event_notify (state %u)\n", + __func__, state); + mutex_lock(&snd_event_mutex); if (list_empty(&snd_event_client_list) && !master) { dev_err(dev, "%s: No device registered\n", __func__); From b1d01899fa4c3fdf93ef0349281bb2cb7aa4027b Mon Sep 17 00:00:00 2001 From: Hugh Guan Date: Fri, 8 Jul 2022 08:47:49 -0700 Subject: [PATCH 3/6] asoc: change HS_IF dummy to playback HS_IF0_TDM_RX_0_DUMMY, HS_IF1_TDM_RX_0_DUMMY and HS_IF2_TDM_RX_0_DUMMY are for playback instead of capture. Change-Id: Icb4ccaacb3c6904b9591cada0905250a2b67cbef Signed-off-by: Hugh Guan --- asoc/gvm_auto_spf_dummy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/asoc/gvm_auto_spf_dummy.c b/asoc/gvm_auto_spf_dummy.c index e508c91078ba..b5e248ed5830 100644 --- a/asoc/gvm_auto_spf_dummy.c +++ b/asoc/gvm_auto_spf_dummy.c @@ -469,7 +469,7 @@ static struct snd_soc_dai_link msm_gvm8295_dai_links[] = { { .name = "HS_IF0_TDM_RX_0_DUMMY", .stream_name = "TDM-LPAIF_SDR-RX-PRIMARY", - .dpcm_capture = 1, + .dpcm_playback = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .ignore_suspend = 1, @@ -489,7 +489,7 @@ static struct snd_soc_dai_link msm_gvm8295_dai_links[] = { { .name = "HS_IF1_TDM_RX_0_DUMMY", .stream_name = "TDM-LPAIF_SDR-RX-SECONDARY", - .dpcm_capture = 1, + .dpcm_playback = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .ignore_suspend = 1, @@ -509,7 +509,7 @@ static struct snd_soc_dai_link msm_gvm8295_dai_links[] = { { .name = "HS_IF2_TDM_RX_0_DUMMY", .stream_name = "TDM-LPAIF_SDR-RX-TERTIARY", - .dpcm_capture = 1, + .dpcm_playback = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .ignore_suspend = 1, From b2a778807b8ccb96c4e4fe00ed6a4993526d3267 Mon Sep 17 00:00:00 2001 From: Kogara Naveen Kumar Date: Mon, 13 Jun 2022 19:05:08 +0530 Subject: [PATCH 4/6] dsp: functions for paired rx port enable/disable usecases Contains functions defined in the afe driver to store the paired rx information in the afe driver and to start/stop the paired rx port. Change-Id: I4ec863d9b04ec7f8f12abb5b66b417eeaa779ec8 --- dsp/q6afe.c | 120 ++++++++++++++++++++++++++++++++++++++++- include/dsp/q6afe-v2.h | 19 +++++++ 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 746aa31ca097..b2b7649f8db4 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -31,6 +31,16 @@ #define SP_V4_NUM_MAX_SPKRS SP_V2_NUM_MAX_SPKRS #define MAX_LSM_SESSIONS 8 +/* Paired Rx Structure Info */ +static struct afe_tdm_intf_paired_rx_cfg afe_tdm_paired_rx_cfg[AFE_TDM_INTERFACE_MAX] = { + {0}, /*Primary*/ + {0}, /*secondary*/ + {0}, /*Tertiary*/ + {0}, /*Quaternary*/ + {0}, /*QUINARY*/ +}; +static atomic_t afe_tdm_port_ref[AFE_MAX_PORTS] = {0}; + struct afe_avcs_payload_port_mapping { u16 port_id; struct avcs_load_unload_modules_payload *payload; @@ -4560,6 +4570,7 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port, uint16_t port_index = 0; enum afe_mad_type mad_type = MAD_HW_NONE; int ret = 0; + atomic_t *port_ref = NULL; if (!tdm_port) { pr_err("%s: Error, no configuration data\n", __func__); @@ -4575,6 +4586,7 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port, __func__, index); return -EINVAL; } + port_ref = &afe_tdm_port_ref[index]; ret = q6audio_validate_port(port_id); if (ret < 0) { pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret); @@ -4673,6 +4685,8 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port, } ret = afe_send_cmd_port_start(port_id); + if(!ret) + atomic_inc(port_ref); fail_cmd: return ret; @@ -9322,6 +9336,7 @@ int afe_close(int port_id) u16 i; int index = 0; uint16_t port_index; + atomic_t *port_ref = NULL; memset(&stop, 0, sizeof(stop)); @@ -9382,6 +9397,7 @@ int afe_close(int port_id) __func__, index); return -EINVAL; } + port_ref = &afe_tdm_port_ref[index]; ret = q6audio_validate_port(port_id); if (ret < 0) { pr_warn("%s: Not a valid port id 0x%x ret %d\n", @@ -9446,8 +9462,11 @@ int afe_close(int port_id) stop.reserved = 0; ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]); - if (ret) + if (ret) { pr_err("%s: AFE close failed %d\n", __func__, ret); + } else { + atomic_dec(port_ref); + } fail_cmd: if ((q6core_get_avcs_api_version_per_service( @@ -12154,3 +12173,102 @@ void afe_set_lsm_afe_port_id(int idx, int lsm_port) this_afe.lsm_afe_ports[idx] = lsm_port; } EXPORT_SYMBOL(afe_set_lsm_afe_port_id); + +//Paired Rx Functions +void afe_tdm_paired_rx_cfg_val(int intf_idx, int afe_port_id, + union afe_port_group_config tdm_group, + struct afe_tdm_port_config tdm_port, + struct afe_param_id_tdm_lane_cfg tdm_lane) +{ + afe_tdm_paired_rx_cfg[intf_idx].afe_port_id = afe_port_id; + afe_tdm_paired_rx_cfg[intf_idx].tdm_port = tdm_port; + afe_tdm_paired_rx_cfg[intf_idx].tdm_group = tdm_group; + afe_tdm_paired_rx_cfg[intf_idx].tdm_lane = tdm_lane; +} +EXPORT_SYMBOL(afe_tdm_paired_rx_cfg_val); + +int afe_paired_rx_tdm_port_ops(int intf_idx, bool enable, atomic_t *dai_group_ref) +{ + int rc = 0; + int group_id = afe_tdm_paired_rx_cfg[intf_idx].tdm_group.group_cfg.group_id; + int port_id = afe_tdm_paired_rx_cfg[intf_idx].afe_port_id; + int group_idx = AFE_TDM_RX_GET_GROUP_IDX(group_id); + atomic_t *group_ref = &dai_group_ref[group_idx]; + atomic_t *port_ref = NULL; + int index = 0; + + if (port_id == 0) { + pr_debug("%s:No Paired Rx alloted for TDM interface %d", __func__, intf_idx); + return 0; + } + + index = q6audio_get_port_index(port_id); + if (index < 0 || index >= AFE_MAX_PORTS) { + pr_err("%s: AFE port index[%d] invalid!\n", + __func__, index); + return -EINVAL; + } + port_ref = &afe_tdm_port_ref[index]; + if (enable) { + pr_debug("%s:Paired Rx Afe Port Id 0x%x Start, Group Id is 0x%x", __func__, port_id, group_id); + if (atomic_read(group_ref) == 0) { + rc = afe_port_group_enable(group_id, + &afe_tdm_paired_rx_cfg[intf_idx].tdm_group, + true, + &afe_tdm_paired_rx_cfg[intf_idx].tdm_lane); + if (rc < 0) { + pr_err("%s:Failed to enable paired rx afe group 0x%x\n" + , __func__, group_id); + return -EINVAL; + } + } + if (atomic_read(port_ref) == 0){ + rc = afe_tdm_port_start(port_id, + &afe_tdm_paired_rx_cfg[intf_idx].tdm_port, + afe_tdm_paired_rx_cfg[intf_idx].tdm_port.tdm.sample_rate, + afe_tdm_paired_rx_cfg[intf_idx].tdm_port.tdm.num_channels); + if (rc < 0) { + if (atomic_read(group_ref) == 0) { + afe_port_group_enable(group_id, + NULL, false, NULL); + } + pr_err("%s: fail to open paired rx AFE port 0x%x\n", __func__, port_id); + return -EINVAL; + } else { + pr_debug("%s:Paired Rx Port Started Sucessfully", __func__); + atomic_inc(group_ref); + } + } else { + pr_debug("%s:Paired Rx Usecase already started", __func__); + atomic_inc(port_ref); + atomic_inc(group_ref); + } + } else { + pr_debug("%s:Paired Rx Afe Port Id 0x%x Stop, Group Id is 0x%x", __func__, port_id, group_id); + if (atomic_read(port_ref) == 1) { + rc = afe_close(port_id); + if (rc < 0) { + pr_err("%s:Failed to close paired rx port 0x%x", __func__, port_id); + return -EINVAL; + } else { + pr_debug("%s:Paired Rx Usecase closed successfully", __func__); + } + atomic_dec(group_ref); + if (atomic_read(group_ref) == 0) { + rc = afe_port_group_enable(group_id, NULL, false, NULL); + if (rc < 0) { + pr_err("%s: fail to disable paired AFE group 0x%x\n", __func__, group_id); + return -EINVAL; + } + } + } else if (atomic_read(port_ref) > 1) { + atomic_dec(port_ref); + atomic_dec(group_ref); + } else { + pr_err("%s:No need to close port",__func__); + return -EINVAL; + } + } + return 0; +} +EXPORT_SYMBOL(afe_paired_rx_tdm_port_ops); diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index cd8e0132709d..900fe1699528 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -63,8 +63,16 @@ #define BAP_BROADCAST 2 #define BAP_BA_SIMULCAST 3 +#define AFE_TDM_INTERFACE_MAX 10 +#define AFE_ID_MASK 0xFF +#define AFE_ID_SHIFT 4 +#define PORT_ID_TO_INTF_IDX(b) ((b & AFE_ID_MASK) >> AFE_ID_SHIFT) +#define AFE_TDM_RX_GET_GROUP_IDX(b) ((PORT_ID_TO_INTF_IDX(b)) * 2) +#define AFE_TDM_TX_GET_GROUP_IDX(b) ((PORT_ID_TO_INTF_IDX(b)) * 2 + 1) +#define MAX_PORTS_PER_INTF 8 typedef int (*routing_cb)(int port); +u16 num_of_bits_set(u16 sd_line_mask); enum { /* IDX 0->4 */ @@ -678,4 +686,15 @@ int afe_get_spk_v_vali_flag(void); void afe_get_spk_v_vali_sts(int *spk_v_vali_sts); void afe_set_spk_initial_cal(int initial_cal); void afe_set_spk_v_vali_flag(int v_vali_flag); +struct afe_tdm_intf_paired_rx_cfg { + int afe_port_id; + union afe_port_group_config tdm_group; /* hold tdm group config */ + struct afe_tdm_port_config tdm_port; /* hold tdm config */ + struct afe_param_id_tdm_lane_cfg tdm_lane; /* hold tdm lane config */ +}; +void afe_tdm_paired_rx_cfg_val(int intf_idx, int afe_port_id, + union afe_port_group_config tdm_group, struct afe_tdm_port_config tdm_port, + struct afe_param_id_tdm_lane_cfg tdm_lane); +int afe_paired_rx_tdm_port_ops(int intf_idx, bool enable, atomic_t *dai_group_ref); + #endif /* __Q6AFE_V2_H__ */ From fab1b421ae1ce366ca841c50e5685c5349ddeb10 Mon Sep 17 00:00:00 2001 From: Kogara Naveen Kumar Date: Mon, 13 Jun 2022 18:54:56 +0530 Subject: [PATCH 5/6] asoc: enables paired rx port to address tdm slot shift issue Defines mixer control for the paired rx and how the dai driver is starting/stopping the paired rx port. Change-Id: Ie17f7de9d7a482ad30b219a9ba68066ee8d467df --- asoc/msm-dai-q6-v2.c | 36 +++++- asoc/sa6155.c | 263 +++++++++++++++++++++++++++++++++++++++++++ asoc/sa8155.c | 263 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 558 insertions(+), 4 deletions(-) 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[] = { From 05dab0221176c73e0b8ba81e5a11149392b513f4 Mon Sep 17 00:00:00 2001 From: ftong Date: Wed, 11 May 2022 11:03:58 +0800 Subject: [PATCH 6/6] asoc: ignore afe resp status to avoid 2s timeout When afe is inactive, it can cause afe_state to be negative and lead to timeout. Ignore afe response in such scenario to avoid timeout. Change-Id: I1191cbe40920bfdcb3ec7e8de76f9210923f40a2 Signed-off-by: ftong --- dsp/q6afe.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dsp/q6afe.c b/dsp/q6afe.c index b2b7649f8db4..137502f57536 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -684,13 +684,7 @@ static void av_dev_drift_afe_cb_handler(uint32_t opcode, uint32_t *payload, return; } - if (!this_afe.av_dev_drift_resp.status) { - atomic_set(&this_afe.state, 0); - } else { - pr_debug("%s: av_dev_drift_resp status: %d\n", __func__, - this_afe.av_dev_drift_resp.status); - atomic_set(&this_afe.state, -1); - } + atomic_set(&this_afe.state, 0); } static void doa_tracking_mon_afe_cb_handler(uint32_t opcode, uint32_t *payload,