aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Marek <jonathan@marek.ca>2020-06-11 23:31:44 -0400
committerJonathan Marek <jonathan@marek.ca>2020-06-11 23:36:30 -0400
commit17a10d8feb7c4f05e7584cfba852281e650ece37 (patch)
treec7e5ee0a68f523248f1ae33bde1a6a13a4c5035f
parenta8d615999266d30f31e97a3b67488dee794798f9 (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.h1
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c54
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c42
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.h11
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c9
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"),