diff options
Diffstat (limited to 'sound/soc/mediatek/common')
-rw-r--r-- | sound/soc/mediatek/common/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-afe-platform-driver.c | 18 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-dai-adda-common.c | 70 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-dai-adda-common.h | 45 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-dsp-sof-common.c | 15 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-dsp-sof-common.h | 1 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-soc-card.h | 7 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-soundcard-driver.c | 199 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-soundcard-driver.h | 42 |
9 files changed, 390 insertions, 11 deletions
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile index 42e636c10c..c90d276cf4 100644 --- a/sound/soc/mediatek/common/Makefile +++ b/sound/soc/mediatek/common/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # platform driver -snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o mtk-soundcard-driver.o +snd-soc-mtk-common-y := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o mtk-soundcard-driver.o +snd-soc-mtk-common-y += mtk-dai-adda-common.o + obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 32edcb6d52..9b72b2a7ae 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -126,10 +126,28 @@ int mtk_afe_pcm_new(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); +static int mtk_afe_component_probe(struct snd_soc_component *component) +{ + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + int ret; + + snd_soc_component_init_regmap(component, afe->regmap); + + /* If the list was never initialized there are no sub-DAIs */ + if (afe->sub_dais.next && afe->sub_dais.prev) { + ret = mtk_afe_add_sub_dai_control(component); + if (ret) + return ret; + } + + return 0; +} + const struct snd_soc_component_driver mtk_afe_pcm_platform = { .name = AFE_PCM_NAME, .pointer = mtk_afe_pcm_pointer, .pcm_construct = mtk_afe_pcm_new, + .probe = mtk_afe_component_probe, }; EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); diff --git a/sound/soc/mediatek/common/mtk-dai-adda-common.c b/sound/soc/mediatek/common/mtk-dai-adda-common.c new file mode 100644 index 0000000000..4dc1412489 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-dai-adda-common.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI ADDA Common + * + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> + */ + +#include <linux/delay.h> +#include <linux/dev_printk.h> + +#include "mtk-base-afe.h" +#include "mtk-dai-adda-common.h" + +unsigned int mtk_adda_dl_rate_transform(struct mtk_base_afe *afe, u32 rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_DL_RATE_8K; + case 11025: + return MTK_AFE_ADDA_DL_RATE_11K; + case 12000: + return MTK_AFE_ADDA_DL_RATE_12K; + case 16000: + return MTK_AFE_ADDA_DL_RATE_16K; + case 22050: + return MTK_AFE_ADDA_DL_RATE_22K; + case 24000: + return MTK_AFE_ADDA_DL_RATE_24K; + case 32000: + return MTK_AFE_ADDA_DL_RATE_32K; + case 44100: + return MTK_AFE_ADDA_DL_RATE_44K; + case 48000: + return MTK_AFE_ADDA_DL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_DL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_DL_RATE_192K; + default: + dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_DL_RATE_48K; + } +} +EXPORT_SYMBOL_GPL(mtk_adda_dl_rate_transform); + +unsigned int mtk_adda_ul_rate_transform(struct mtk_base_afe *afe, u32 rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_UL_RATE_8K; + case 16000: + return MTK_AFE_ADDA_UL_RATE_16K; + case 32000: + return MTK_AFE_ADDA_UL_RATE_32K; + case 48000: + return MTK_AFE_ADDA_UL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_UL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_UL_RATE_192K; + default: + dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_UL_RATE_48K; + } +} +EXPORT_SYMBOL_GPL(mtk_adda_ul_rate_transform); diff --git a/sound/soc/mediatek/common/mtk-dai-adda-common.h b/sound/soc/mediatek/common/mtk-dai-adda-common.h new file mode 100644 index 0000000000..208b0dd89f --- /dev/null +++ b/sound/soc/mediatek/common/mtk-dai-adda-common.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> + */ + +#ifndef _MTK_DAI_ADDA_COMMON_H_ +#define _MTK_DAI_ADDA_COMMON_H_ + +struct mtk_base_afe; + +enum adda_input_mode_rate { + MTK_AFE_ADDA_DL_RATE_8K = 0, + MTK_AFE_ADDA_DL_RATE_11K = 1, + MTK_AFE_ADDA_DL_RATE_12K = 2, + MTK_AFE_ADDA_DL_RATE_16K = 3, + MTK_AFE_ADDA_DL_RATE_22K = 4, + MTK_AFE_ADDA_DL_RATE_24K = 5, + MTK_AFE_ADDA_DL_RATE_32K = 6, + MTK_AFE_ADDA_DL_RATE_44K = 7, + MTK_AFE_ADDA_DL_RATE_48K = 8, + MTK_AFE_ADDA_DL_RATE_96K = 9, + MTK_AFE_ADDA_DL_RATE_192K = 10, +}; + +enum adda_voice_mode_rate { + MTK_AFE_ADDA_UL_RATE_8K = 0, + MTK_AFE_ADDA_UL_RATE_16K = 1, + MTK_AFE_ADDA_UL_RATE_32K = 2, + MTK_AFE_ADDA_UL_RATE_48K = 3, + MTK_AFE_ADDA_UL_RATE_96K = 4, + MTK_AFE_ADDA_UL_RATE_192K = 5, + MTK_AFE_ADDA_UL_RATE_48K_HD = 6, +}; + +enum adda_rxif_delay_data { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO0 = 1, + DELAY_DATA_MISO2 = 1, +}; + +unsigned int mtk_adda_dl_rate_transform(struct mtk_base_afe *afe, u32 rate); +unsigned int mtk_adda_ul_rate_transform(struct mtk_base_afe *afe, u32 rate); +#endif diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c index 7ec8965a70..bca758dca2 100644 --- a/sound/soc/mediatek/common/mtk-dsp-sof-common.c +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c @@ -15,7 +15,7 @@ int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_card *card = rtd->card; struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; int i, j, ret = 0; for (i = 0; i < sof_priv->num_streams; i++) { @@ -55,7 +55,6 @@ int mtk_sof_card_probe(struct snd_soc_card *card) int i; struct snd_soc_dai_link *dai_link; struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; /* Set stream_name to help sof bind widgets */ for_each_card_prelinks(card, i, dai_link) { @@ -63,7 +62,7 @@ int mtk_sof_card_probe(struct snd_soc_card *card) dai_link->stream_name = dai_link->name; } - INIT_LIST_HEAD(&sof_priv->dai_link_list); + INIT_LIST_HEAD(&soc_card_data->sof_dai_link_list); return 0; } @@ -73,7 +72,7 @@ static struct snd_soc_pcm_runtime *mtk_sof_find_tplg_be(struct snd_soc_pcm_runti { struct snd_soc_card *card = rtd->card; struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; struct snd_soc_pcm_runtime *fe; struct snd_soc_pcm_runtime *be; struct snd_soc_dpcm *dpcm; @@ -113,7 +112,7 @@ static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_card *card = rtd->card; struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; struct snd_soc_pcm_runtime *sof_be; struct mtk_dai_link *dai_link; int ret = 0; @@ -125,7 +124,7 @@ static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, else if (sof_be->dai_link->be_hw_params_fixup) ret = sof_be->dai_link->be_hw_params_fixup(sof_be, params); } else { - list_for_each_entry(dai_link, &sof_priv->dai_link_list, list) { + list_for_each_entry(dai_link, &soc_card_data->sof_dai_link_list, list) { if (strcmp(dai_link->name, rtd->dai_link->name) == 0) { if (dai_link->be_hw_params_fixup) ret = dai_link->be_hw_params_fixup(rtd, params); @@ -144,7 +143,7 @@ int mtk_sof_card_late_probe(struct snd_soc_card *card) struct snd_soc_component *sof_comp = NULL; struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; struct snd_soc_dai_link *dai_link; struct mtk_dai_link *mtk_dai_link; int i; @@ -173,7 +172,7 @@ int mtk_sof_card_late_probe(struct snd_soc_card *card) mtk_dai_link->be_hw_params_fixup = dai_link->be_hw_params_fixup; mtk_dai_link->name = dai_link->name; - list_add(&mtk_dai_link->list, &sof_priv->dai_link_list); + list_add(&mtk_dai_link->list, &soc_card_data->sof_dai_link_list); } if (dai_link->no_pcm) diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.h b/sound/soc/mediatek/common/mtk-dsp-sof-common.h index 4bc5e1c0c8..8784ee4711 100644 --- a/sound/soc/mediatek/common/mtk-dsp-sof-common.h +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.h @@ -30,7 +30,6 @@ struct mtk_sof_priv { int num_streams; int (*sof_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); - struct list_head dai_link_list; }; int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h index eeda793700..3f6e24dd22 100644 --- a/sound/soc/mediatek/common/mtk-soc-card.h +++ b/sound/soc/mediatek/common/mtk-soc-card.h @@ -9,9 +9,14 @@ #ifndef _MTK_SOC_CARD_H_ #define _MTK_SOC_CARD_H_ +struct mtk_platform_card_data; +struct mtk_sof_priv; + struct mtk_soc_card_data { + const struct mtk_sof_priv *sof_priv; + struct list_head sof_dai_link_list; + struct mtk_platform_card_data *card_data; void *mach_priv; - void *sof_priv; }; #endif diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c index 000a086a8c..3bbf42c428 100644 --- a/sound/soc/mediatek/common/mtk-soundcard-driver.c +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c @@ -10,6 +10,8 @@ #include <linux/of.h> #include <sound/soc.h> +#include "mtk-dsp-sof-common.h" +#include "mtk-soc-card.h" #include "mtk-soundcard-driver.h" static int set_card_codec_info(struct snd_soc_card *card, @@ -136,3 +138,200 @@ void clean_card_reference(struct snd_soc_card *card) snd_soc_of_put_dai_link_codecs(dai_link); } EXPORT_SYMBOL_GPL(clean_card_reference); + +int mtk_soundcard_startup(struct snd_pcm_substream *substream, + enum mtk_pcm_constraint_type ctype) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_soc_card_data *soc_card = snd_soc_card_get_drvdata(rtd->card); + const struct mtk_pcm_constraints_data *mpc = &soc_card->card_data->pcm_constraints[ctype]; + int ret; + + if (unlikely(!mpc)) + return -EINVAL; + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + mpc->rates); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list rate failed\n"); + return ret; + } + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + mpc->channels); + if (ret < 0) { + dev_err(rtd->dev, "hw_constraint_list channel failed\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_soundcard_startup); + +static int mtk_soundcard_playback_startup(struct snd_pcm_substream *substream) +{ + return mtk_soundcard_startup(substream, MTK_CONSTRAINT_PLAYBACK); +} + +const struct snd_soc_ops mtk_soundcard_common_playback_ops = { + .startup = mtk_soundcard_playback_startup, +}; +EXPORT_SYMBOL_GPL(mtk_soundcard_common_playback_ops); + +static int mtk_soundcard_capture_startup(struct snd_pcm_substream *substream) +{ + return mtk_soundcard_startup(substream, MTK_CONSTRAINT_CAPTURE); +} + +const struct snd_soc_ops mtk_soundcard_common_capture_ops = { + .startup = mtk_soundcard_capture_startup, +}; +EXPORT_SYMBOL_GPL(mtk_soundcard_common_capture_ops); + +int mtk_soundcard_common_probe(struct platform_device *pdev) +{ + struct device_node *platform_node, *adsp_node; + const struct mtk_soundcard_pdata *pdata; + struct mtk_soc_card_data *soc_card_data; + struct snd_soc_dai_link *orig_dai_link, *dai_link; + struct snd_soc_jack *jacks; + struct snd_soc_card *card; + int i, orig_num_links, ret; + bool needs_legacy_probe; + + pdata = device_get_match_data(&pdev->dev); + if (!pdata) + return -EINVAL; + + card = pdata->card_data->card; + card->dev = &pdev->dev; + orig_dai_link = card->dai_link; + orig_num_links = card->num_links; + + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret) + return ret; + + if (!card->name) { + if (!pdata->card_name) + return -EINVAL; + + card->name = pdata->card_name; + } + + needs_legacy_probe = !of_property_read_bool(pdev->dev.of_node, "audio-routing"); + if (needs_legacy_probe) { + /* + * If we have no .soc_probe() callback there's no way of using + * any legacy probe mechanism, as that cannot not be generic. + */ + if (!pdata->soc_probe) + return -EINVAL; + + dev_info_once(&pdev->dev, "audio-routing not found: using legacy probe\n"); + } else { + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) + return ret; + } + + soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*soc_card_data), GFP_KERNEL); + if (!soc_card_data) + return -ENOMEM; + + soc_card_data->card_data = pdata->card_data; + + jacks = devm_kcalloc(card->dev, soc_card_data->card_data->num_jacks, + sizeof(*jacks), GFP_KERNEL); + if (!jacks) + return -ENOMEM; + + soc_card_data->card_data->jacks = jacks; + + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); + if (!platform_node) + return dev_err_probe(&pdev->dev, -EINVAL, + "Property mediatek,platform missing or invalid\n"); + + /* Check if this SoC has an Audio DSP */ + if (pdata->sof_priv) + adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0); + else + adsp_node = NULL; + + if (adsp_node) { + if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) { + ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node, + "mediatek,dai-link", + card->dai_link, card->num_links); + if (ret) { + of_node_put(adsp_node); + of_node_put(platform_node); + return dev_err_probe(&pdev->dev, ret, + "Cannot parse mediatek,dai-link\n"); + } + } + + soc_card_data->sof_priv = pdata->sof_priv; + card->probe = mtk_sof_card_probe; + card->late_probe = mtk_sof_card_late_probe; + if (!card->topology_shortname_created) { + snprintf(card->topology_shortname, 32, "sof-%s", card->name); + card->topology_shortname_created = true; + } + card->name = card->topology_shortname; + } + + /* + * Regardless of whether the ADSP is wanted and/or present in a machine + * specific device tree or not and regardless of whether any AFE_SOF + * link is present, we have to make sure that the platforms->of_node + * is not NULL, and set to either ADSP (adsp_node) or AFE (platform_node). + */ + for_each_card_prelinks(card, i, dai_link) { + if (adsp_node && !strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF"))) + dai_link->platforms->of_node = adsp_node; + else if (!dai_link->platforms->name && !dai_link->platforms->of_node) + dai_link->platforms->of_node = platform_node; + } + + if (!needs_legacy_probe) { + ret = parse_dai_link_info(card); + if (ret) + goto err_restore_dais; + } else { + if (adsp_node) + of_node_put(adsp_node); + of_node_put(platform_node); + } + + if (pdata->soc_probe) { + ret = pdata->soc_probe(soc_card_data, needs_legacy_probe); + if (ret) { + if (!needs_legacy_probe) + clean_card_reference(card); + goto err_restore_dais; + } + } + snd_soc_card_set_drvdata(card, soc_card_data); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + + if (!needs_legacy_probe) + clean_card_reference(card); + + if (ret) { + dev_err_probe(&pdev->dev, ret, "Cannot register card\n"); + goto err_restore_dais; + } + + return 0; + +err_restore_dais: + card->dai_link = orig_dai_link; + card->num_links = orig_num_links; + return ret; +} +EXPORT_SYMBOL_GPL(mtk_soundcard_common_probe); diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.h b/sound/soc/mediatek/common/mtk-soundcard-driver.h index d92cac1d7b..f6c275b540 100644 --- a/sound/soc/mediatek/common/mtk-soundcard-driver.h +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.h @@ -9,6 +9,48 @@ #ifndef _MTK_SOUNDCARD_DRIVER_H_ #define _MTK_SOUNDCARD_DRIVER_H_ +struct mtk_sof_priv; +struct mtk_soc_card_data; +struct snd_pcm_hw_constraint_list; + +enum mtk_pcm_constraint_type { + MTK_CONSTRAINT_PLAYBACK, + MTK_CONSTRAINT_CAPTURE, + MTK_CONSTRAINT_HDMIDP, + MTK_CONSTRAINT_MAX +}; + +struct mtk_pcm_constraints_data { + const struct snd_pcm_hw_constraint_list *channels; + const struct snd_pcm_hw_constraint_list *rates; +}; + +struct mtk_platform_card_data { + struct snd_soc_card *card; + struct snd_soc_jack *jacks; + const struct mtk_pcm_constraints_data *pcm_constraints; + u8 num_jacks; + u8 num_pcm_constraints; + u8 flags; +}; + +struct mtk_soundcard_pdata { + const char *card_name; + struct mtk_platform_card_data *card_data; + const struct mtk_sof_priv *sof_priv; + + int (*soc_probe)(struct mtk_soc_card_data *card_data, bool legacy); +}; + +/* Common playback/capture card startup ops */ +extern const struct snd_soc_ops mtk_soundcard_common_playback_ops; +extern const struct snd_soc_ops mtk_soundcard_common_capture_ops; + +/* Exported for custom/extended soundcard startup ops */ +int mtk_soundcard_startup(struct snd_pcm_substream *substream, + enum mtk_pcm_constraint_type ctype); + int parse_dai_link_info(struct snd_soc_card *card); void clean_card_reference(struct snd_soc_card *card); +int mtk_soundcard_common_probe(struct platform_device *pdev); #endif |