audio-driver: support tdm multi lane for sa8155

Support group tdm multi lane configuration for TDM interface.
With valid lane mask tdm interface support delivery audio channels
through different data lines.

Change-Id: I63e8ba1106b89c6bcaca0a8359a1def696c334ad
Signed-off-by: Cong Tang <congt@codeaurora.org>
This commit is contained in:
Cong Tang 2019-02-26 15:14:28 +08:00 • committed by Gerrit - the friendly Code Review server
commit b84eea3768
4 changed files with 136 additions and 9 deletions

View file

@ -272,6 +272,7 @@ struct msm_dai_q6_tdm_dai_data {
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 */
struct afe_param_id_tdm_lane_cfg lane_cfg; /* hold tdm lane config */
};
/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
@ -337,6 +338,11 @@ static DEFINE_MUTEX(tdm_mutex);
static atomic_t tdm_group_ref[IDX_GROUP_TDM_MAX];
static struct afe_param_id_tdm_lane_cfg tdm_lane_cfg = {
AFE_GROUP_DEVICE_ID_QUINARY_TDM_RX,
0x0,
};
/* cache of group cfg per parent node */
static struct afe_param_id_group_device_tdm_cfg tdm_group_cfg = {
AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG,
@ -6590,6 +6596,24 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
} else
dev_dbg(&pdev->dev, "%s: clk attribute not found\n", __func__);
/* extract tdm lane cfg to static */
tdm_lane_cfg.port_id = tdm_group_cfg.group_id;
tdm_lane_cfg.lane_mask = AFE_LANE_MASK_INVALID;
if (of_find_property(pdev->dev.of_node,
"qcom,msm-cpudai-tdm-lane-mask", NULL)) {
rc = of_property_read_u16(pdev->dev.of_node,
"qcom,msm-cpudai-tdm-lane-mask",
&tdm_lane_cfg.lane_mask);
if (rc) {
dev_err(&pdev->dev, "%s: value for tdm lane mask not found %s\n",
__func__, "qcom,msm-cpudai-tdm-lane-mask");
goto rtn;
}
dev_dbg(&pdev->dev, "%s: tdm lane mask from DT file %d\n",
__func__, tdm_lane_cfg.lane_mask);
} else
dev_dbg(&pdev->dev, "%s: tdm lane mask not found\n", __func__);
/* extract tdm clk src master/slave info into static */
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,msm-cpudai-tdm-clk-internal",
@ -7696,7 +7720,7 @@ static int msm_dai_q6_dai_tdm_remove(struct snd_soc_dai *dai)
if (atomic_read(group_ref) == 0) {
rc = afe_port_group_enable(group_id,
NULL, false);
NULL, false, NULL);
if (rc < 0) {
dev_err(dai->dev, "fail to disable AFE group 0x%x\n",
group_id);
@ -8066,7 +8090,17 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
* NOTE: group config is set to the same as slot config.
*/
tdm_group->bit_width = tdm_group->slot_width;
tdm_group->num_channels = tdm_group->nslots_per_frame;
/*
* for multi lane scenario
* Total number of active channels = number of active lanes * number of active slots.
*/
if (dai_data->lane_cfg.lane_mask != AFE_LANE_MASK_INVALID)
tdm_group->num_channels = tdm_group->nslots_per_frame
* num_of_bits_set(dai_data->lane_cfg.lane_mask);
else
tdm_group->num_channels = tdm_group->nslots_per_frame;
tdm_group->sample_rate = dai_data->rate;
pr_debug("%s: TDM GROUP:\n"
@ -8091,6 +8125,10 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
tdm_group->port_id[5],
tdm_group->port_id[6],
tdm_group->port_id[7]);
pr_debug("%s: TDM GROUP ID 0x%x lane mask 0x%x:\n",
__func__,
tdm_group->group_id,
dai_data->lane_cfg.lane_mask);
/*
* update tdm config param
@ -8246,7 +8284,8 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
*/
if (dai_data->num_group_ports > 1) {
rc = afe_port_group_enable(group_id,
&dai_data->group_cfg, true);
&dai_data->group_cfg, true,
&dai_data->lane_cfg);
if (rc < 0) {
dev_err(dai->dev,
"%s: fail to enable AFE group 0x%x\n",
@ -8261,7 +8300,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
if (rc < 0) {
if (atomic_read(group_ref) == 0) {
afe_port_group_enable(group_id,
NULL, false);
NULL, false, NULL);
}
if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) {
msm_dai_q6_tdm_set_clk(dai_data,
@ -8318,7 +8357,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream,
if (atomic_read(group_ref) == 0) {
rc = afe_port_group_enable(group_id,
NULL, false);
NULL, false, NULL);
if (rc < 0) {
dev_err(dai->dev, "%s: fail to disable AFE group 0x%x\n",
__func__, group_id);
@ -10223,7 +10262,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev)
dai_data->group_cfg.tdm_cfg = tdm_group_cfg;
/* copy static num group ports per parent node */
dai_data->num_group_ports = num_tdm_group_ports;
dai_data->lane_cfg = tdm_lane_cfg;
dev_set_drvdata(&pdev->dev, dai_data);

View file

@ -5422,6 +5422,53 @@ int afe_port_group_set_param(u16 group_id,
return ret;
}
/**
* afe_port_tdm_lane_config -
* to configure group TDM lane mask with specified configuration
*
* @group_id: AFE group id number
* @lane_cfg: TDM lane mask configutation
*
* Returns 0 on success or error value on failure.
*/
static int afe_port_tdm_lane_config(u16 group_id,
struct afe_param_id_tdm_lane_cfg *lane_cfg)
{
struct param_hdr_v3 param_hdr;
int ret = 0;
if (lane_cfg == NULL ||
lane_cfg->lane_mask == AFE_LANE_MASK_INVALID) {
pr_debug("%s: lane cfg not supported for group id: 0x%x\n",
__func__, group_id);
return ret;
}
pr_debug("%s: group id: 0x%x lane mask 0x%x\n", __func__,
group_id, lane_cfg->lane_mask);
memset(&param_hdr, 0, sizeof(param_hdr));
ret = afe_q6_interface_prepare();
if (ret != 0) {
pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
return ret;
}
param_hdr.module_id = AFE_MODULE_GROUP_DEVICE;
param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_id = AFE_PARAM_ID_TDM_LANE_CONFIG;
param_hdr.param_size = sizeof(struct afe_param_id_tdm_lane_cfg);
ret = q6afe_svc_pack_and_set_param_in_band(IDX_GLOBAL_CFG, param_hdr,
(u8 *)lane_cfg);
if (ret)
pr_err("%s: AFE_PARAM_ID_TDM_LANE_CONFIG failed %d\n",
__func__, ret);
return ret;
}
/**
* afe_port_group_enable -
* command to enable AFE port group
@ -5429,12 +5476,14 @@ int afe_port_group_set_param(u16 group_id,
* @group_id: group ID for AFE port group
* @afe_group_config: config for AFE group
* @enable: flag to indicate enable or disable
* @lane_cfg: TDM lane mask configutation
*
* Returns 0 on success or error on failure
*/
int afe_port_group_enable(u16 group_id,
union afe_port_group_config *afe_group_config,
u16 enable)
u16 enable,
struct afe_param_id_tdm_lane_cfg *lane_cfg)
{
struct afe_group_device_enable group_enable;
struct param_hdr_v3 param_hdr;
@ -5458,6 +5507,12 @@ int afe_port_group_enable(u16 group_id,
pr_err("%s: afe send failed %d\n", __func__, ret);
return ret;
}
ret = afe_port_tdm_lane_config(group_id, lane_cfg);
if (ret < 0) {
pr_err("%s: afe send lane config failed %d\n",
__func__, ret);
return ret;
}
}
param_hdr.module_id = AFE_MODULE_GROUP_DEVICE;
@ -8998,4 +9053,3 @@ done:
return ret;
}
EXPORT_SYMBOL(afe_unvote_lpass_core_hw);

View file

@ -1354,6 +1354,8 @@ struct adm_cmd_connect_afe_port_v5 {
#define AFE_LOOPBACK_TX 0x6001
#define DISPLAY_PORT_RX 0x6020
#define AFE_LANE_MASK_INVALID 0
#define AFE_PORT_INVALID 0xFFFF
#define SLIMBUS_INVALID AFE_PORT_INVALID
@ -12430,4 +12432,35 @@ struct afe_param_id_vad_cfg_t {
#define AFE_PARAM_ID_VAD_CORE_CFG 0x000102BB
/**
* This parameter is should be used to configure the AFE TDM
* interface lane configuration.
* Regular TDM interface ports:
* This parameter ID must be used with module ID
* AFE_MODULE_AUDIO_DEV_INTERFACE and set using the AFE_PORT_CMD_SET_PARAM_V3
* command for the AFE TDM interface port IDs.
* Group device TDM interface ports:
* This parameter ID must be used with module ID AFE_MODULE_GROUP_DEVICE
* and set using the AFE_SVC_CMD_SET_PARAM_V2 command for the AFE TDM group IDs.
*/
#define AFE_PARAM_ID_TDM_LANE_CONFIG 0x000102C1
/* Payload of the AFE_PARAM_ID_TDM_LANE_CONFIG parameter used by
* AFE_MODULE_AUDIO_DEV_INTERFACE.
*/
struct afe_param_id_tdm_lane_cfg {
uint16_t port_id;
/** ID of the TDM interface.
* For regular TDM interfaces value corresponds to valid port ID.
* For group devices TDM interface value corresponds to valid group device ID.
*/
uint16_t lane_mask;
/** Position of the active lanes. Bits 0 to N correspond to lanes 0 to N.
* 1 to 2^N-1 When a bit is set, the corresponding lane is active.
* The number of active lanes can be inferred from the number of bits
* set in the mask.
*/
};
#endif /*_APR_AUDIO_V2_H_ */

View file

@ -432,7 +432,8 @@ int afe_set_aanc_noise_level(int val);
int afe_port_group_set_param(u16 group_id,
union afe_port_group_config *afe_group_config);
int afe_port_group_enable(u16 group_id,
union afe_port_group_config *afe_group_config, u16 enable);
union afe_port_group_config *afe_group_config, u16 enable,
struct afe_param_id_tdm_lane_cfg *lane_cfg);
int afe_unmap_rtac_block(uint32_t *mem_map_handle);
int afe_map_rtac_block(struct rtac_cal_block_data *cal_block);
int afe_send_slot_mapping_cfg(