diff options
author | Jonathan Marek <jonathan@marek.ca> | 2020-06-11 23:31:44 -0400 |
---|---|---|
committer | Jonathan Marek <jonathan@marek.ca> | 2020-06-11 23:36:30 -0400 |
commit | 17a10d8feb7c4f05e7584cfba852281e650ece37 (patch) | |
tree | c7e5ee0a68f523248f1ae33bde1a6a13a4c5035f | |
parent | a8d615999266d30f31e97a3b67488dee794798f9 (diff) |
ASoC: qcom: qdsp6: add support for WSA_CDC_DMA_RX_0 output
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
-rw-r--r-- | include/dt-bindings/sound/qcom,q6afe.h | 1 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6afe-dai.c | 54 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6afe.c | 42 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6afe.h | 11 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6routing.c | 9 |
5 files changed, 116 insertions, 1 deletions
diff --git a/include/dt-bindings/sound/qcom,q6afe.h b/include/dt-bindings/sound/qcom,q6afe.h index 1df06f8ad5c39..0940cbe8b8928 100644 --- a/include/dt-bindings/sound/qcom,q6afe.h +++ b/include/dt-bindings/sound/qcom,q6afe.h @@ -107,6 +107,7 @@ #define QUINARY_TDM_RX_7 102 #define QUINARY_TDM_TX_7 103 #define DISPLAY_PORT_RX 104 +#define WSA_CDC_DMA_RX_0 105 #endif /* __DT_BINDINGS_Q6_AFE_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 2a5302f1db98a..66dc2467d16a2 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -151,6 +151,20 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, return 0; } +static int q6dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_cdc_dma_cfg *cdc_dma = &dai_data->port_config[dai->id].cdc_dma; + + cdc_dma->sample_rate = params_rate(params); + cdc_dma->bit_width = params_width(params); + cdc_dma->num_channels = params_channels(params); + + return 0; +} + static int q6i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -362,6 +376,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, q6afe_tdm_port_prepare(dai_data->port[dai->id], &dai_data->port_config[dai->id].tdm); break; + case WSA_CDC_DMA_RX_0: + q6afe_cdc_dma_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].cdc_dma); + break; default: return -EINVAL; } @@ -562,6 +580,8 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"PRI_MI2S_TX", NULL, "Primary MI2S Capture"}, {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"}, {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, + + {"WSA CDC DMA0 Playback", NULL, "WSA_CDC_DMA_RX_0"}, }; static const struct snd_soc_dai_ops q6hdmi_ops = { @@ -594,6 +614,14 @@ static const struct snd_soc_dai_ops q6tdm_ops = { .hw_params = q6tdm_hw_params, }; +static const struct snd_soc_dai_ops msm_dai_q6_cdc_wsa_dma_ops = { + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + //.set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, + // .digital_mute = msm_dai_q6_spk_digital_mute, +}; + static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -1127,6 +1155,30 @@ static struct snd_soc_dai_driver q6afe_dais[] = { .name = "DISPLAY_PORT", .probe = msm_dai_q6_dai_probe, .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "WSA CDC DMA0 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 | + SNDRV_PCM_RATE_384000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 384000, + }, + .name = "WSA_CDC_DMA_RX_0", + .ops = &msm_dai_q6_cdc_wsa_dma_ops, + .id = WSA_CDC_DMA_RX_0, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, }, }; @@ -1350,6 +1402,8 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL, 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0), + + SND_SOC_DAPM_AIF_IN("WSA_CDC_DMA_RX_0", NULL, 0, 0, 0, 0), }; static const struct snd_soc_component_driver q6afe_dai_component = { diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index e0945f7a58c81..f6531ee753ab2 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -41,6 +41,7 @@ #define AFE_PARAM_ID_SLIMBUS_CONFIG 0x00010212 #define AFE_PARAM_ID_I2S_CONFIG 0x0001020D #define AFE_PARAM_ID_TDM_CONFIG 0x0001029D +#define AFE_PARAM_ID_CODEC_DMA_CONFIG 0x000102B8 #define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297 /* I2S config specific */ @@ -72,6 +73,7 @@ #define AFE_API_VERSION_HDMI_CONFIG 0x1 #define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E #define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020 +#define AFE_PORT_ID_WSA_CODEC_DMA_RX_0 0xB000 #define AFE_API_VERSION_SLIMBUS_CONFIG 0x1 /* Clock set API version */ @@ -448,11 +450,21 @@ struct afe_param_id_tdm_cfg { u32 slot_mask; } __packed; +struct afe_param_id_cdc_dma_cfg { + u32 cdc_dma_cfg_minor_version; + u32 sample_rate; + u16 bit_width; + u16 data_format; + u16 num_channels; + u16 active_channels_mask; +} __packed; + union afe_port_config { struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch; struct afe_param_id_slimbus_cfg slim_cfg; struct afe_param_id_i2s_cfg i2s_cfg; struct afe_param_id_tdm_cfg tdm_cfg; + struct afe_param_id_cdc_dma_cfg cdc_dma_cfg; } __packed; @@ -707,6 +719,8 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { QUINARY_TDM_TX_7, 0, 1}, [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX, DISPLAY_PORT_RX, 1, 1}, + [WSA_CDC_DMA_RX_0] = { AFE_PORT_ID_WSA_CODEC_DMA_RX_0, + WSA_CDC_DMA_RX_0, 1, 1}, }; static void q6afe_port_free(struct kref *ref) @@ -1146,6 +1160,30 @@ void q6afe_hdmi_port_prepare(struct q6afe_port *port, EXPORT_SYMBOL_GPL(q6afe_hdmi_port_prepare); /** + * q6afe_cdc_dma_port_prepare() - Prepare cdc_cma afe port. + * + * @port: Instance of afe port + * @cfg: HDMI configuration for the afe port + * + */ +void q6afe_cdc_dma_port_prepare(struct q6afe_port *port, + struct q6afe_cdc_dma_cfg *cfg) +{ + union afe_port_config *pcfg = &port->port_cfg; + +#define AFE_API_VERSION_CODEC_DMA_CONFIG 0x1 + + pcfg->cdc_dma_cfg.cdc_dma_cfg_minor_version = AFE_API_VERSION_CODEC_DMA_CONFIG; + pcfg->cdc_dma_cfg.sample_rate = cfg->sample_rate; + pcfg->cdc_dma_cfg.bit_width = cfg->bit_width; + pcfg->cdc_dma_cfg.data_format = 0x0; // AFE_LINEAR_PCM_DATA, or 0x6? + pcfg->cdc_dma_cfg.num_channels = cfg->num_channels; + // XXX this mask can be sparse - channel_map + pcfg->cdc_dma_cfg.active_channels_mask = (1 << cfg->num_channels) - 1; +} +EXPORT_SYMBOL_GPL(q6afe_hdmi_port_prepare); + +/** * q6afe_i2s_port_prepare() - Prepare i2s afe port. * * @port: Instance of afe port @@ -1421,6 +1459,10 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) cfg_type = AFE_PARAM_ID_TDM_CONFIG; break; + case AFE_PORT_ID_WSA_CODEC_DMA_RX_0: + cfg_type = AFE_PARAM_ID_CODEC_DMA_CONFIG; + break; + default: dev_err(dev, "Invalid port id 0x%x\n", port_id); return ERR_PTR(-EINVAL); diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index c7ed5422baffd..bec7ad9899b25 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -5,7 +5,7 @@ #include <dt-bindings/sound/qcom,q6afe.h> -#define AFE_PORT_MAX 105 +#define AFE_PORT_MAX 106 #define MSM_AFE_PORT_TYPE_RX 0 #define MSM_AFE_PORT_TYPE_TX 1 @@ -184,11 +184,18 @@ struct q6afe_tdm_cfg { u16 ch_mapping[AFE_MAX_CHAN_COUNT]; }; +struct q6afe_cdc_dma_cfg { + u32 sample_rate; + u16 bit_width; + u16 num_channels; +}; + struct q6afe_port_config { struct q6afe_hdmi_cfg hdmi; struct q6afe_slim_cfg slim; struct q6afe_i2s_cfg i2s_cfg; struct q6afe_tdm_cfg tdm; + struct q6afe_cdc_dma_cfg cdc_dma; }; struct q6afe_port; @@ -200,6 +207,8 @@ void q6afe_port_put(struct q6afe_port *port); int q6afe_get_port_id(int index); void q6afe_hdmi_port_prepare(struct q6afe_port *port, struct q6afe_hdmi_cfg *cfg); +void q6afe_cdc_dma_port_prepare(struct q6afe_port *port, + struct q6afe_cdc_dma_cfg *cfg); void q6afe_slim_port_prepare(struct q6afe_port *port, struct q6afe_slim_cfg *cfg); int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg); diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 46e50612b92c1..1572b4f511571 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -456,6 +456,9 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { static const struct snd_kcontrol_new display_port_mixer_controls[] = { Q6ROUTING_RX_MIXERS(DISPLAY_PORT_RX) }; +static const struct snd_kcontrol_new wsa_cdc_dma_rx_0_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(WSA_CDC_DMA_RX_0) }; + static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) }; @@ -662,6 +665,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { display_port_mixer_controls, ARRAY_SIZE(display_port_mixer_controls)), + SND_SOC_DAPM_MIXER("WSA_CDC_DMA_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0, + wsa_cdc_dma_rx_0_mixer_controls, + ARRAY_SIZE(wsa_cdc_dma_rx_0_mixer_controls)), + SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0, slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)), @@ -842,6 +849,8 @@ static const struct snd_soc_dapm_route intercon[] = { Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"), Q6ROUTING_RX_DAPM_ROUTE("DISPLAY_PORT_RX Audio Mixer", "DISPLAY_PORT_RX"), + Q6ROUTING_RX_DAPM_ROUTE("WSA_CDC_DMA_RX_0 Audio Mixer", + "WSA_CDC_DMA_RX_0"), Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"), Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"), Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"), |