diff options
Diffstat (limited to 'sound')
298 files changed, 20765 insertions, 1163 deletions
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 5cbc82eca4c9..0932473b6394 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -130,4 +130,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = { + { + .id = "AMDI1019", + .drv_name = "rmb-dsp", + .pdata = &acp_quirk_data, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-acp-rmb.tplg", + }, + { + .id = "10508825", + .drv_name = "nau8825-max", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-rmb-nau8825-max98360.tplg", + }, + { + .id = "RTL5682", + .drv_name = "rt5682s-hs-rt1019", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-rmb-rt5682s-rt1019.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_rmb_sof_machines); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 9dae2719084c..7e56d2644105 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -49,6 +49,7 @@ config SND_SOC_AMD_MACH_COMMON select SND_SOC_RT1019 select SND_SOC_MAX98357A select SND_SOC_RT5682S + select SND_SOC_NAU8825 help This option enables common Machine driver module for ACP. diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 6ae454bf60af..7530cab24bc8 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -24,6 +24,7 @@ #include "../../codecs/rt5682.h" #include "../../codecs/rt1019.h" #include "../../codecs/rt5682s.h" +#include "../../codecs/nau8825.h" #include "acp-mach.h" #define PCO_PLAT_CLK 48000000 @@ -148,9 +149,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) struct acp_card_drvdata *drvdata = card->drvdata; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); int ret; + unsigned int fmt; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBP_CFP); + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); return ret; @@ -161,10 +167,13 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) &constraints_channels); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - ret = acp_clk_enable(drvdata); - if (ret < 0) - dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); + if (!drvdata->soc_mclk) { + ret = acp_clk_enable(drvdata); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); + return ret; + } + } return ret; } @@ -175,7 +184,8 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; - clk_disable_unprepare(drvdata->wclk); + if (!drvdata->soc_mclk) + clk_disable_unprepare(drvdata->wclk); } static const struct snd_soc_ops acp_card_rt5682_ops = { @@ -199,6 +209,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) struct acp_card_drvdata *drvdata = card->drvdata; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; + unsigned int fmt; int ret; dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); @@ -206,8 +217,12 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != RT5682S) return -EINVAL; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBP_CFP); + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); return ret; @@ -234,8 +249,10 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) return ret; } - drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); - drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); + if (!drvdata->soc_mclk) { + drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); + drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); + } ret = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | @@ -296,6 +313,9 @@ static const struct snd_soc_ops acp_card_dmic_ops = { SND_SOC_DAILINK_DEF(rt1019, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"), COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"))); +SND_SOC_DAILINK_DEF(rt1019_1, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:02", "rt1019-aif"), + COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"))); static const struct snd_soc_dapm_route rt1019_map_lr[] = { { "Left Spk", NULL, "Left SPO" }, @@ -313,6 +333,17 @@ static struct snd_soc_codec_conf rt1019_conf[] = { }, }; +static struct snd_soc_codec_conf rt1019_1_conf[] = { + { + .dlc = COMP_CODEC_CONF("i2c-10EC1019:02"), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"), + .name_prefix = "Right", + }, +}; + static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -363,7 +394,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; - int ret; + int ret = 0; runtime->hw.channels_max = DUAL_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -371,10 +402,13 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - ret = acp_clk_enable(drvdata); - if (ret < 0) - dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); - + if (!drvdata->soc_mclk) { + ret = acp_clk_enable(drvdata); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); + return ret; + } + } return ret; } @@ -409,6 +443,104 @@ static const struct snd_soc_ops acp_card_maxim_ops = { .shutdown = acp_card_shutdown, }; +/* Declare nau8825 codec components */ +SND_SOC_DAILINK_DEF(nau8825, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); + +static const struct snd_soc_dapm_route nau8825_map[] = { + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, +}; + +static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + unsigned int fmt; + int ret; + + dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); + + if (drvdata->hs_codec_id != NAU8825) + return -EINVAL; + + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); + return ret; + } + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pco_jack); + if (ret) { + dev_err(card->dev, "HP jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map)); +} + +static int acp_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, + (48000 * 256), SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params), + params_rate(params) * 256); + if (ret < 0) { + dev_err(rtd->dev, "can't set FLL: %d\n", ret); + return ret; + } + + return ret; +} + +static int acp_nau8825_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + return 0; +} + +static const struct snd_soc_ops acp_card_nau8825_ops = { + .startup = acp_nau8825_startup, + .hw_params = acp_nau8825_hw_params, +}; + /* Declare DMIC codec components */ SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); @@ -437,6 +569,8 @@ SND_SOC_DAILINK_DEF(i2s_sp, DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp"))); SND_SOC_DAILINK_DEF(sof_sp, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp"))); +SND_SOC_DAILINK_DEF(sof_hs, + DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs"))); SND_SOC_DAILINK_DEF(sof_dmic, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic"))); SND_SOC_DAILINK_DEF(pdm_dmic, @@ -491,6 +625,37 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->hs_cpu_id == I2S_HS) { + links[i].name = "acp-headset-codec"; + links[i].id = HEADSET_BE_ID; + links[i].cpus = sof_hs; + links[i].num_cpus = ARRAY_SIZE(sof_hs); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->hs_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->hs_codec_id == NAU8825) { + links[i].codecs = nau8825; + links[i].num_codecs = ARRAY_SIZE(nau8825); + links[i].init = acp_card_nau8825_init; + links[i].ops = &acp_card_nau8825_ops; + } + if (drv_data->hs_codec_id == RT5682S) { + links[i].codecs = rt5682s; + links[i].num_codecs = ARRAY_SIZE(rt5682s); + links[i].init = acp_card_rt5682s_init; + links[i].ops = &acp_card_rt5682s_ops; + } + i++; + } + if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; @@ -523,6 +688,42 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->amp_cpu_id == I2S_HS) { + links[i].name = "acp-amp-codec"; + links[i].id = AMP_BE_ID; + links[i].cpus = sof_hs; + links[i].num_cpus = ARRAY_SIZE(sof_hs); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->amp_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->amp_codec_id == MAX98360A) { + links[i].codecs = max98360a; + links[i].num_codecs = ARRAY_SIZE(max98360a); + links[i].ops = &acp_card_maxim_ops; + links[i].init = acp_card_maxim_init; + } + if (drv_data->amp_codec_id == RT1019) { + links[i].codecs = rt1019; + links[i].num_codecs = ARRAY_SIZE(rt1019); + links[i].ops = &acp_card_rt1019_ops; + links[i].init = acp_card_rt1019_init; + card->codec_conf = rt1019_conf; + card->num_configs = ARRAY_SIZE(rt1019_conf); + links[i].codecs = rt1019_1; + links[i].num_codecs = ARRAY_SIZE(rt1019_1); + card->codec_conf = rt1019_1_conf; + card->num_configs = ARRAY_SIZE(rt1019_1_conf); + } + i++; + } + if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; links[i].id = DMIC_BE_ID; diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 5dc47cfbff10..c95ee1c52eb1 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -26,6 +26,7 @@ enum be_id { enum cpu_endpoints { NONE = 0, + I2S_HS, I2S_SP, I2S_BT, DMIC, @@ -37,6 +38,7 @@ enum codec_endpoints { RT1019, MAX98360A, RT5682S, + NAU8825, }; struct acp_card_drvdata { @@ -49,6 +51,7 @@ struct acp_card_drvdata { unsigned int dai_fmt; struct clk *wclk; struct clk *bclk; + bool soc_mclk; }; int acp_sofdsp_dai_links_create(struct snd_soc_card *card); diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index 424c6e0bb9d6..7a0b26a30051 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -174,7 +174,7 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream, struct acp_dev_data *adata = dev_get_drvdata(dev); u32 ext_int_ctrl; - /* Disable DMIC interrrupts */ + /* Disable DMIC interrupts */ ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); ext_int_ctrl |= ~PDM_DMA_INTR_MASK; writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index d1531cdab110..f19f064a7527 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -56,6 +56,26 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { .dmic_codec_id = DMIC, }; +static struct acp_card_drvdata sof_nau8825_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = NAU8825, + .amp_codec_id = MAX98360A, + .dmic_codec_id = DMIC, + .soc_mclk = true, +}; + +static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = RT5682S, + .amp_codec_id = RT1019, + .dmic_codec_id = DMIC, + .soc_mclk = true, +}; + static const struct snd_kcontrol_new acp_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -124,6 +144,14 @@ static const struct platform_device_id board_ids[] = { .name = "rt5682s-rt1019", .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data }, + { + .name = "nau8825-max", + .driver_data = (kernel_ulong_t)&sof_nau8825_data + }, + { + .name = "rt5682s-hs-rt1019", + .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data + }, { } }; static struct platform_driver acp_asoc_audio = { @@ -143,4 +171,6 @@ MODULE_ALIAS("platform:rt5682-rt1019"); MODULE_ALIAS("platform:rt5682-max"); MODULE_ALIAS("platform:rt5682s-max"); MODULE_ALIAS("platform:rt5682s-rt1019"); +MODULE_ALIAS("platform:nau8825-max"); +MODULE_ALIAS("platform:rt5682s-hs-rt1019"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 0a54567a2841..7b4c625da40d 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -19,6 +19,7 @@ #define ACP_PCI_DEV_ID 0x15E2 extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c index 59a98f89a669..72c8c68e5933 100644 --- a/sound/soc/amd/vangogh/acp5x-i2s.c +++ b/sound/soc/amd/vangogh/acp5x-i2s.c @@ -37,10 +37,10 @@ static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; switch (mode) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: adata->master_mode = I2S_MASTER_MODE_ENABLE; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: adata->master_mode = I2S_MASTER_MODE_DISABLE; break; } diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 1934767690b5..ba56d6ac7e57 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -343,7 +343,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, } switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* codec is slave, so cpu is master */ mr |= ATMEL_I2SC_MR_MODE_MASTER; ret = atmel_i2s_get_gck_param(dev, params_rate(params)); @@ -351,7 +351,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, return ret; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* codec is master, so cpu is slave */ mr |= ATMEL_I2SC_MR_MODE_SLAVE; dev->gck_param = NULL; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index c1dea8d62416..c92905e343e7 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -210,7 +210,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, return frame_size; switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) && ssc->clk_from_rk_pin) /* Receiver Frame Synchro (i.e. capture) @@ -220,7 +220,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, mck_div = 3; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) && !ssc->clk_from_rk_pin) /* Transmit Frame Synchro (i.e. playback) @@ -233,7 +233,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, } switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: r.num = ssc_p->mck_rate / mck_div / frame_size; ret = snd_interval_ratnum(i, 1, &r, &num, &den); @@ -243,8 +243,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, } break; - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BC_FC: t.min = 8000; t.max = ssc_p->mck_rate / mck_div / frame_size; t.openmin = t.openmax = 0; @@ -433,8 +433,8 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) { switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BP_FP: return 1; } return 0; @@ -444,8 +444,8 @@ static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) { switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFP: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FC: + case SND_SOC_DAIFMT_BP_FP: return 1; } return 0; diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 6d1227a1d67b..269eab56b6dd 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -350,7 +350,7 @@ static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; /* We can't generate only FSYNC */ - if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFC) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_BC_FP) return -EINVAL; /* We can only reconfigure the IP when it's stopped */ @@ -547,19 +547,19 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, } switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* cpu is BCLK and LRC master */ mra |= MCHP_I2SMCC_MRA_MODE_MASTER; if (dev->sysclk) mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN; set_divs = 1; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: /* cpu is BCLK master */ mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT; set_divs = 1; fallthrough; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* cpu is slave */ mra |= MCHP_I2SMCC_MRA_MODE_SLAVE; if (dev->sysclk) diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index a3856c73e221..b9f637059448 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -492,8 +492,8 @@ static int mchp_pdmc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int fmt_format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; /* IP needs to be bitclock master */ - if (fmt_master != SND_SOC_DAIFMT_CBS_CFS && - fmt_master != SND_SOC_DAIFMT_CBS_CFM) + if (fmt_master != SND_SOC_DAIFMT_BP_FP && + fmt_master != SND_SOC_DAIFMT_BP_FC) return -EINVAL; /* IP supports only PDM interface */ diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 740d4e052e4d..45bb7851e75d 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -121,7 +121,7 @@ static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) /* I2S controller only supports provider */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */ + case SND_SOC_DAIFMT_BP_FP: /* CODEC consumer */ break; default: goto out; diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index b2b8896bb593..530a072d7427 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -91,10 +91,10 @@ static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: /* CODEC provider */ + case SND_SOC_DAIFMT_BC_FC: /* CODEC provider */ ct |= PSC_I2SCFG_MS; /* PSC I2S consumer mode */ break; - case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */ + case SND_SOC_DAIFMT_BP_FP: /* CODEC consumer */ ct &= ~PSC_I2SCFG_MS; /* PSC I2S provider mode */ break; default: diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index e3fc4bee8cfd..e39c8d9f4099 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -133,8 +133,8 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) return; switch (provider) { - case SND_SOC_DAIFMT_CBC_CFC: - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BP_FC: clk_prepare_enable(dev->clk); dev->clk_prepared = true; break; @@ -385,12 +385,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, /* Check if CPU is bit clock provider */ switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BP_FC: bit_clock_provider = true; break; - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BC_FC: bit_clock_provider = false; break; default: @@ -399,12 +399,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, /* Check if CPU is frame sync provider */ switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BC_FP: frame_sync_provider = true; break; - case SND_SOC_DAIFMT_CBC_CFP: - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BP_FC: + case SND_SOC_DAIFMT_BC_FC: frame_sync_provider = false; break; default: diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 9698f4531c90..4bfa2d715ff4 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -849,11 +849,11 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) ssp_newcfg = 0; switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE); aio->is_slave = 1; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE); aio->is_slave = 0; break; diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 2c8cd843d049..47959794353a 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -246,12 +246,12 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* CPU is provider */ clk_cfg |= EP93XX_I2S_CLKCFG_MASTER; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* Codec is provider */ clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER; break; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6165db92a629..5a60633a196c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -937,6 +937,16 @@ config SND_SOC_HDAC_HDA tristate select SND_HDA +config SND_SOC_HDA + tristate "HD-Audio codec driver" + select SND_HDA_EXT_CORE + select SND_HDA + help + This enables HD-Audio codec support in ASoC subsystem. Compared + to SND_SOC_HDAC_HDA, driver's behavior is identical to HD-Audio + legacy solution - including the dynamic resource allocation + based on actual codec capabilities. + config SND_SOC_ICS43432 tristate "ICS43423 and compatible i2s microphones" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 28dc4edfd01f..d32026ae326f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-hdac-hda-objs := hdac_hda.o +snd-soc-hda-codec-objs := hda.o hda-dai.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -458,6 +459,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o +obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index aefafb0b7b97..cbd4a92cb06c 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -12,8 +12,6 @@ * Mikko Sarmanne <mikko.sarmanne@symbio.com>, * Jarmo K. Kuronen <jarmo.kuronen@symbio.com>, * for ST-Ericsson. - * - * License terms: */ #include <linux/kernel.h> diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h index 0ac87d0446c2..2a6f6409f1f8 100644 --- a/sound/soc/codecs/ab8500-codec.h +++ b/sound/soc/codecs/ab8500-codec.h @@ -11,8 +11,6 @@ * Mikko J. Lehto <mikko.lehto@symbio.com>, * Mikko Sarmanne <mikko.sarmanne@symbio.com>, * for ST-Ericsson. - * - * License terms: */ #ifndef AB8500_CODEC_REGISTERS_H diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 93606e5afd8f..d29d5e0db168 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -921,18 +921,12 @@ static int ak4613_i2c_probe(struct i2c_client *i2c) &ak4613_dai, 1); } -static int ak4613_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static struct i2c_driver ak4613_i2c_driver = { .driver = { .name = "ak4613-codec", .of_match_table = ak4613_of_match, }, .probe_new = ak4613_i2c_probe, - .remove = ak4613_i2c_remove, .id_table = ak4613_i2c_id, }; diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 8b0a9c788a26..11e7b3f6d410 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -995,6 +995,7 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev) dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", priv->ap_shm_phys_addr, priv->ap_shm_len); } + of_node_put(node); } #endif diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 6d3070ea9e06..0c7d1c791279 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -1302,7 +1302,8 @@ int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, return 0; } - dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts); + if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) + dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts); return -ENOMSG; } @@ -1321,6 +1322,85 @@ int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap) } EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata); +int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap, + enum cs35l41_boost_type b_type) +{ + if (!cs35l41_safe_reset(regmap, b_type)) { + dev_dbg(dev, "System does not support Suspend\n"); + return -EINVAL; + } + + dev_dbg(dev, "Enter hibernate\n"); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + // Don't wait for ACK since bus activity would wake the device + regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE); + + return 0; +} +EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate); + +static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap) +{ + const int pwrmgt_retries = 10; + unsigned int sts; + int i, ret; + + for (i = 0; i < pwrmgt_retries; i++) { + ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts); + if (ret) + dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret); + else if (!(sts & CS35L41_WR_PEND_STS_MASK)) + return; + + udelay(20); + } + + dev_err(dev, "Timed out reading PWRMGT_STS\n"); +} + +int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap) +{ + const int wake_retries = 20; + const int sleep_retries = 5; + int ret, i, j; + + for (i = 0; i < sleep_retries; i++) { + dev_dbg(dev, "Exit hibernate\n"); + + for (j = 0; j < wake_retries; j++) { + ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, + CSPL_MBOX_CMD_OUT_OF_HIBERNATE); + if (!ret) + break; + + usleep_range(100, 200); + } + + if (j < wake_retries) { + dev_dbg(dev, "Wake success at cycle: %d\n", j); + return 0; + } + + dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3); + } + + dev_err(dev, "Timed out waking device\n"); + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate); + MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>"); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 71ab2a5d1c55..8766e19d85f1 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1335,15 +1335,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running) return 0; - dev_dbg(cs35l41->dev, "Enter hibernate\n"); - - cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188); - - // Don't wait for ACK since bus activity would wake the device - regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, - CSPL_MBOX_CMD_HIBERNATE); + cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type); regcache_cache_only(cs35l41->regmap, true); regcache_mark_dirty(cs35l41->regmap); @@ -1351,65 +1343,6 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) return 0; } -static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41) -{ - const int pwrmgt_retries = 10; - unsigned int sts; - int i, ret; - - for (i = 0; i < pwrmgt_retries; i++) { - ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts); - if (ret) - dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret); - else if (!(sts & CS35L41_WR_PEND_STS_MASK)) - return; - - udelay(20); - } - - dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n"); -} - -static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41) -{ - const int wake_retries = 20; - const int sleep_retries = 5; - int ret, i, j; - - for (i = 0; i < sleep_retries; i++) { - dev_dbg(cs35l41->dev, "Exit hibernate\n"); - - for (j = 0; j < wake_retries; j++) { - ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, - CSPL_MBOX_CMD_OUT_OF_HIBERNATE); - if (!ret) - break; - - usleep_range(100, 200); - } - - if (j < wake_retries) { - dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j); - return 0; - } - - dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3); - } - - dev_err(cs35l41->dev, "Timed out waking device\n"); - - return -ETIMEDOUT; -} - static int __maybe_unused cs35l41_runtime_resume(struct device *dev) { struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); @@ -1422,7 +1355,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev) regcache_cache_only(cs35l41->regmap, false); - ret = cs35l41_exit_hibernate(cs35l41); + ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); if (ret) return ret; diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c index 38a4dbc9e9fe..06c2ddffb9c5 100644 --- a/sound/soc/codecs/cs35l45-i2c.c +++ b/sound/soc/codecs/cs35l45-i2c.c @@ -40,7 +40,9 @@ static int cs35l45_i2c_remove(struct i2c_client *client) { struct cs35l45_private *cs35l45 = i2c_get_clientdata(client); - return cs35l45_remove(cs35l45); + cs35l45_remove(cs35l45); + + return 0; } static const struct of_device_id cs35l45_of_match[] = { diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c index 2367c1a4c10e..d15b3b77c7eb 100644 --- a/sound/soc/codecs/cs35l45.c +++ b/sound/soc/codecs/cs35l45.c @@ -500,6 +500,8 @@ static const struct snd_soc_component_driver cs35l45_component = { .num_controls = ARRAY_SIZE(cs35l45_controls), .name = "cs35l45", + + .endianness = 1, }; static int __maybe_unused cs35l45_runtime_suspend(struct device *dev) @@ -665,7 +667,7 @@ err: } EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45); -int cs35l45_remove(struct cs35l45_private *cs35l45) +void cs35l45_remove(struct cs35l45_private *cs35l45) { pm_runtime_disable(cs35l45->dev); @@ -673,8 +675,6 @@ int cs35l45_remove(struct cs35l45_private *cs35l45) regulator_disable(cs35l45->vdd_a); /* VDD_BATT must be the last to power-off */ regulator_disable(cs35l45->vdd_batt); - - return 0; } EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45); diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h index 4e266d19cd1c..53fe9d2b7b15 100644 --- a/sound/soc/codecs/cs35l45.h +++ b/sound/soc/codecs/cs35l45.h @@ -209,9 +209,9 @@ struct cs35l45_private { extern const struct dev_pm_ops cs35l45_pm_ops; extern const struct regmap_config cs35l45_i2c_regmap; extern const struct regmap_config cs35l45_spi_regmap; -int cs35l45_apply_patch(struct cs35l45_private *cs43l45); +int cs35l45_apply_patch(struct cs35l45_private *cs35l45); unsigned int cs35l45_get_clk_freq_id(unsigned int freq); int cs35l45_probe(struct cs35l45_private *cs35l45); -int cs35l45_remove(struct cs35l45_private *cs35l45); +void cs35l45_remove(struct cs35l45_private *cs35l45); #endif /* CS35L45_H */ diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 531f63b01554..97d26b9e8f7f 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -663,7 +663,6 @@ static int cs4270_i2c_remove(struct i2c_client *i2c_client) /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object - * @id: the I2C device ID (ignored) * * This function is called whenever the I2C subsystem finds a device that * matches the device ID given via a prior call to i2c_add_driver(). diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 4fade2388797..6ca74c0d46ea 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1701,8 +1701,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) break; default: - if (cs42l42->plug_state != CS42L42_TS_TRANS) - cs42l42->plug_state = CS42L42_TS_TRANS; + cs42l42->plug_state = CS42L42_TS_TRANS; } } diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index b35debb5818d..b6667e8a6099 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -710,22 +710,19 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x) regdbt2.ulval = 0xac; - /* set master/slave */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: reg2.r.tx_master = 1; reg3.r.rx_master = 1; - dev_dbg(dev, "Sets Master mode\n"); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg2.r.tx_master = 0; reg3.r.rx_master = 0; - dev_dbg(dev, "Sets Slave mode\n"); break; default: - dev_err(dev, "Unsupported DAI master mode\n"); + dev_err(dev, "Unsupported DAI clocking mode\n"); return -EINVAL; } @@ -1009,9 +1006,9 @@ static int cx2072x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(dev, "set_dai_fmt- %08x\n", fmt); /* set master/slave */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: break; default: diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 3fa3042e4424..76a21976ccdd 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1335,6 +1335,8 @@ static int __init da7210_modinit(void) int ret = 0; #if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&da7210_i2c_driver); + if (ret) + return ret; #endif #if defined(CONFIG_SPI_MASTER) ret = spi_register_driver(&da7210_spi_driver); diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 7fdef38ed8cd..c18f76f370fc 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2693,11 +2693,6 @@ static int da7219_i2c_probe(struct i2c_client *i2c) return ret; } -static int da7219_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id da7219_i2c_id[] = { { "da7219", }, { } @@ -2711,7 +2706,6 @@ static struct i2c_driver da7219_i2c_driver = { .acpi_match_table = ACPI_PTR(da7219_acpi_match), }, .probe_new = da7219_i2c_probe, - .remove = da7219_i2c_remove, .id_table = da7219_i2c_id, }; diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index f14cddf23f42..3f1cfee10df3 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1546,11 +1546,6 @@ err: return ret; } -static int da732x_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id da732x_i2c_id[] = { { "da7320", 0}, { } @@ -1562,7 +1557,6 @@ static struct i2c_driver da732x_i2c_driver = { .name = "da7320", }, .probe_new = da732x_i2c_probe, - .remove = da732x_i2c_remove, .id_table = da732x_i2c_id, }; diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c new file mode 100644 index 000000000000..5371ff086261 --- /dev/null +++ b/sound/soc/codecs/hda-dai.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <sound/soc.h> +#include <sound/hda_codec.h> +#include "hda.h" + +static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct hda_pcm_stream *stream_info; + struct hda_codec *codec; + struct hda_pcm *pcm; + int ret; + + codec = dev_to_hda_codec(dai->dev); + stream_info = snd_soc_dai_get_dma_data(dai, substream); + pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]); + + dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n", + codec->core.vendor_id, stream_info, pcm, pcm->name, substream); + + snd_hda_codec_pcm_get(pcm); + + ret = stream_info->ops.open(stream_info, codec, substream); + if (ret < 0) { + dev_err(dai->dev, "codec open failed: %d\n", ret); + snd_hda_codec_pcm_put(pcm); + return ret; + } + + return 0; +} + +static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct hda_pcm_stream *stream_info; + struct hda_codec *codec; + struct hda_pcm *pcm; + int ret; + + codec = dev_to_hda_codec(dai->dev); + stream_info = snd_soc_dai_get_dma_data(dai, substream); + pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]); + + dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n", + codec->core.vendor_id, stream_info, pcm, pcm->name, substream); + + ret = stream_info->ops.close(stream_info, codec, substream); + if (ret < 0) + dev_err(dai->dev, "codec close failed: %d\n", ret); + + snd_hda_codec_pcm_put(pcm); +} + +static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct hda_pcm_stream *stream_info; + struct hda_codec *codec; + + codec = dev_to_hda_codec(dai->dev); + stream_info = snd_soc_dai_get_dma_data(dai, substream); + + snd_hda_codec_cleanup(codec, stream_info, substream); + + return 0; +} + +static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct hda_pcm_stream *stream_info; + struct hdac_stream *stream; + struct hda_codec *codec; + unsigned int format; + int ret; + + codec = dev_to_hda_codec(dai->dev); + stream = substream->runtime->private_data; + stream_info = snd_soc_dai_get_dma_data(dai, substream); + format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, + runtime->sample_bits, 0); + + ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream); + if (ret < 0) { + dev_err(dai->dev, "codec prepare failed: %d\n", ret); + return ret; + } + + return 0; +} + +const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = { + .startup = hda_codec_dai_startup, + .shutdown = hda_codec_dai_shutdown, + .hw_free = hda_codec_dai_hw_free, + .prepare = hda_codec_dai_prepare, +}; +EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops); diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c new file mode 100644 index 000000000000..edcb8bc6806b --- /dev/null +++ b/sound/soc/codecs/hda.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> +#include <sound/hdaudio_ext.h> +#include <sound/hda_i915.h> +#include <sound/hda_codec.h> +#include "hda.h" + +static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count, + struct snd_soc_dai_driver **drivers) +{ + struct device *dev = &codec->core.dev; + struct snd_soc_dai_driver *drvs; + struct hda_pcm *pcm; + int i; + + drvs = devm_kcalloc(dev, pcm_count, sizeof(*drvs), GFP_KERNEL); + if (!drvs) + return -ENOMEM; + + pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); + + for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { + struct snd_soc_pcm_stream *stream; + int dir; + + dev_info(dev, "creating for %s %d\n", pcm->name, i); + drvs[i].id = i; + drvs[i].name = pcm->name; + drvs[i].ops = &snd_soc_hda_codec_dai_ops; + + dir = SNDRV_PCM_STREAM_PLAYBACK; + stream = &drvs[i].playback; + if (!pcm->stream[dir].substreams) { + dev_info(dev, "skipping playback dai for %s\n", pcm->name); + goto capture_dais; + } + + stream->stream_name = + devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name, + snd_pcm_direction_name(dir)); + if (!stream->stream_name) + return -ENOMEM; + stream->channels_min = pcm->stream[dir].channels_min; + stream->channels_max = pcm->stream[dir].channels_max; + stream->rates = pcm->stream[dir].rates; + stream->formats = pcm->stream[dir].formats; + stream->sig_bits = pcm->stream[dir].maxbps; + +capture_dais: + dir = SNDRV_PCM_STREAM_CAPTURE; + stream = &drvs[i].capture; + if (!pcm->stream[dir].substreams) { + dev_info(dev, "skipping capture dai for %s\n", pcm->name); + continue; + } + + stream->stream_name = + devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name, + snd_pcm_direction_name(dir)); + if (!stream->stream_name) + return -ENOMEM; + stream->channels_min = pcm->stream[dir].channels_min; + stream->channels_max = pcm->stream[dir].channels_max; + stream->rates = pcm->stream[dir].rates; + stream->formats = pcm->stream[dir].formats; + stream->sig_bits = pcm->stream[dir].maxbps; + } + + *drivers = drvs; + return 0; +} + +static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_component *component) +{ + struct snd_soc_dai_driver *drvs = NULL; + struct snd_soc_dapm_context *dapm; + struct hda_pcm *pcm; + int ret, pcm_count = 0; + + if (list_empty(&codec->pcm_list_head)) + return -EINVAL; + list_for_each_entry(pcm, &codec->pcm_list_head, list) + pcm_count++; + + ret = hda_codec_create_dais(codec, pcm_count, &drvs); + if (ret < 0) + return ret; + + dapm = snd_soc_component_get_dapm(component); + + list_for_each_entry(pcm, &codec->pcm_list_head, list) { + struct snd_soc_dai *dai; + + dai = snd_soc_register_dai(component, drvs, false); + if (!dai) { + dev_err(component->dev, "register dai for %s failed\n", pcm->name); + return -EINVAL; + } + + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret < 0) { + dev_err(component->dev, "create widgets failed: %d\n", ret); + snd_soc_unregister_dai(dai); + return ret; + } + + snd_soc_dai_init_dma_data(dai, &pcm->stream[0], &pcm->stream[1]); + drvs++; + } + + return 0; +} + +static void hda_codec_unregister_dais(struct hda_codec *codec, + struct snd_soc_component *component) +{ + struct snd_soc_dai *dai, *save; + struct hda_pcm *pcm; + + for_each_component_dais_safe(component, dai, save) { + list_for_each_entry(pcm, &codec->pcm_list_head, list) { + if (strcmp(dai->driver->name, pcm->name)) + continue; + + if (dai->playback_widget) + snd_soc_dapm_free_widget(dai->playback_widget); + if (dai->capture_widget) + snd_soc_dapm_free_widget(dai->capture_widget); + snd_soc_unregister_dai(dai); + break; + } + } +} + +int hda_codec_probe_complete(struct hda_codec *codec) +{ + struct hdac_device *hdev = &codec->core; + struct hdac_bus *bus = hdev->bus; + int ret; + + ret = snd_hda_codec_build_controls(codec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to create controls %d\n", ret); + goto out; + } + + /* Bus suspended codecs as it does not manage their pm */ + pm_runtime_set_active(&hdev->dev); + /* rpm was forbidden in snd_hda_codec_device_new() */ + snd_hda_codec_set_power_save(codec, 2000); + snd_hda_codec_register(codec); +out: + /* Complement pm_runtime_get_sync(bus) in probe */ + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(hda_codec_probe_complete); + +/* Expects codec with usage_count=1 and status=suspended */ +static int hda_codec_probe(struct snd_soc_component *component) +{ + struct hda_codec *codec = dev_to_hda_codec(component->dev); + struct hdac_device *hdev = &codec->core; + struct hdac_bus *bus = hdev->bus; + struct hdac_ext_link *hlink; + hda_codec_patch_t patch; + int ret; + +#ifdef CONFIG_PM + WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 || + !pm_runtime_status_suspended(&hdev->dev)); +#endif + + hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + + pm_runtime_get_sync(bus->dev); + if (hda_codec_is_display(codec)) + snd_hdac_display_power(bus, hdev->addr, true); + snd_hdac_ext_bus_link_get(bus, hlink); + + ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec, + false); + if (ret < 0) { + dev_err(&hdev->dev, "create hda codec failed: %d\n", ret); + goto device_new_err; + } + + ret = snd_hda_codec_set_name(codec, codec->preset->name); + if (ret < 0) { + dev_err(&hdev->dev, "name failed %s\n", codec->preset->name); + goto err; + } + + ret = snd_hdac_regmap_init(&codec->core); + if (ret < 0) { + dev_err(&hdev->dev, "regmap init failed\n"); + goto err; + } + + patch = (hda_codec_patch_t)codec->preset->driver_data; + if (!patch) { + dev_err(&hdev->dev, "no patch specified?\n"); + ret = -EINVAL; + goto err; + } + + ret = patch(codec); + if (ret < 0) { + dev_err(&hdev->dev, "patch failed %d\n", ret); + goto err; + } + + /* configure codec for 1:1 PCM:DAI mapping */ + codec->mst_no_extra_pcms = 1; + + ret = snd_hda_codec_parse_pcms(codec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); + goto parse_pcms_err; + } + + ret = hda_codec_register_dais(codec, component); + if (ret < 0) { + dev_err(&hdev->dev, "update dais failed: %d\n", ret); + goto parse_pcms_err; + } + + if (!hda_codec_is_display(codec)) { + ret = hda_codec_probe_complete(codec); + if (ret < 0) + goto complete_err; + } + + codec->core.lazy_cache = true; + + return 0; + +complete_err: + hda_codec_unregister_dais(codec, component); +parse_pcms_err: + if (codec->patch_ops.free) + codec->patch_ops.free(codec); +err: + snd_hda_codec_cleanup_for_unbind(codec); +device_new_err: + if (hda_codec_is_display(codec)) + snd_hdac_display_power(bus, hdev->addr, false); + + snd_hdac_ext_bus_link_put(bus, hlink); + + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + return ret; +} + +/* Leaves codec with usage_count=1 and status=suspended */ +static void hda_codec_remove(struct snd_soc_component *component) +{ + struct hda_codec *codec = dev_to_hda_codec(component->dev); + struct hdac_device *hdev = &codec->core; + struct hdac_bus *bus = hdev->bus; + struct hdac_ext_link *hlink; + bool was_registered = codec->registered; + + /* Don't allow any more runtime suspends */ + pm_runtime_forbid(&hdev->dev); + + hda_codec_unregister_dais(codec, component); + + if (codec->patch_ops.free) + codec->patch_ops.free(codec); + + snd_hda_codec_cleanup_for_unbind(codec); + pm_runtime_put_noidle(&hdev->dev); + /* snd_hdac_device_exit() is only called on bus remove */ + pm_runtime_set_suspended(&hdev->dev); + + if (hda_codec_is_display(codec)) + snd_hdac_display_power(bus, hdev->addr, false); + + hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr); + if (hlink) + snd_hdac_ext_bus_link_put(bus, hlink); + /* + * HDMI card's hda_codec_probe_complete() (see late_probe()) may + * not be called due to early error, leaving bus uc unbalanced + */ + if (!was_registered) { + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + } + +#ifdef CONFIG_PM + WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 || + !pm_runtime_status_suspended(&hdev->dev)); +#endif +} + +static const struct snd_soc_dapm_route hda_dapm_routes[] = { + {"AIF1TX", NULL, "Codec Input Pin1"}, + {"AIF2TX", NULL, "Codec Input Pin2"}, + {"AIF3TX", NULL, "Codec Input Pin3"}, + + {"Codec Output Pin1", NULL, "AIF1RX"}, + {"Codec Output Pin2", NULL, "AIF2RX"}, + {"Codec Output Pin3", NULL, "AIF3RX"}, +}; + +static const struct snd_soc_dapm_widget hda_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Input Pins */ + SND_SOC_DAPM_INPUT("Codec Input Pin1"), + SND_SOC_DAPM_INPUT("Codec Input Pin2"), + SND_SOC_DAPM_INPUT("Codec Input Pin3"), + + /* Output Pins */ + SND_SOC_DAPM_OUTPUT("Codec Output Pin1"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin2"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin3"), +}; + +static struct snd_soc_dai_driver card_binder_dai = { + .id = -1, + .name = "codec-probing-DAI", +}; + +static int hda_hdev_attach(struct hdac_device *hdev) +{ + struct hda_codec *codec = dev_to_hda_codec(&hdev->dev); + struct snd_soc_component_driver *comp_drv; + + comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL); + if (!comp_drv) + return -ENOMEM; + + /* + * It's save to rely on dev_name() rather than a copy as component + * driver's lifetime is directly tied to hda codec one + */ + comp_drv->name = dev_name(&hdev->dev); + comp_drv->probe = hda_codec_probe; + comp_drv->remove = hda_codec_remove; + comp_drv->idle_bias_on = false; + if (!hda_codec_is_display(codec)) { + comp_drv->dapm_widgets = hda_dapm_widgets; + comp_drv->num_dapm_widgets = ARRAY_SIZE(hda_dapm_widgets); + comp_drv->dapm_routes = hda_dapm_routes; + comp_drv->num_dapm_routes = ARRAY_SIZE(hda_dapm_routes); + } + + return snd_soc_register_component(&hdev->dev, comp_drv, &card_binder_dai, 1); +} + +static int hda_hdev_detach(struct hdac_device *hdev) +{ + struct hda_codec *codec = dev_to_hda_codec(&hdev->dev); + + if (codec->registered) + cancel_delayed_work_sync(&codec->jackpoll_work); + + snd_soc_unregister_component(&hdev->dev); + + return 0; +} + +const struct hdac_ext_bus_ops soc_hda_ext_bus_ops = { + .hdev_attach = hda_hdev_attach, + .hdev_detach = hda_hdev_detach, +}; +EXPORT_SYMBOL_GPL(soc_hda_ext_bus_ops); + +MODULE_DESCRIPTION("HD-Audio codec driver"); +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h new file mode 100644 index 000000000000..78a2be4945b1 --- /dev/null +++ b/sound/soc/codecs/hda.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * + * Author: Cezary Rojewski <cezary.rojewski@intel.com> + */ + +#ifndef SND_SOC_CODECS_HDA_H +#define SND_SOC_CODECS_HDA_H + +#define hda_codec_is_display(codec) \ + ((((codec)->core.vendor_id >> 16) & 0xFFFF) == 0x8086) + +extern const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops; + +extern const struct hdac_ext_bus_ops soc_hda_ext_bus_ops; +int hda_codec_probe_complete(struct hda_codec *codec); + +#endif diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index b773466619b2..7d1e351f863a 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -606,18 +606,18 @@ static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, /* Reset daifmt */ memset(cf, 0, sizeof(*cf)); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - cf->bit_clk_master = 1; - cf->frame_clk_master = 1; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + cf->bit_clk_provider = 1; + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: - cf->frame_clk_master = 1; + case SND_SOC_DAIFMT_CBC_CFP: + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: - cf->bit_clk_master = 1; + case SND_SOC_DAIFMT_CBP_CFC: + cf->bit_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index bd0078e4499b..c4900ada8618 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1442,11 +1442,6 @@ static int lm49453_i2c_probe(struct i2c_client *i2c) return ret; } -static int lm49453_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id lm49453_i2c_id[] = { { "lm49453", 0 }, { } @@ -1458,7 +1453,6 @@ static struct i2c_driver lm49453_i2c_driver = { .name = "lm49453", }, .probe_new = lm49453_i2c_probe, - .remove = lm49453_i2c_remove, .id_table = lm49453_i2c_id, }; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 576277a82d41..72471cdb2229 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1591,9 +1591,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, cdata->fmt = fmt; regval = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Set to slave mode PLL - MAS mode off */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Set to consumer mode PLL - MAS mode off */ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB, 0x00); snd_soc_component_write(component, @@ -1602,8 +1602,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, M98090_USE_M1_MASK, 0); max98090->master = false; break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ if (max98090->tdm_slots == 4) { /* TDM */ regval |= M98090_MAS_MASK | @@ -1619,8 +1619,6 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, } max98090->master = true; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "DAI clock mode unsupported"); return -EINVAL; diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index e14fe98349a5..1517c47afbf1 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -5,6 +5,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/cdev.h> @@ -440,8 +441,19 @@ const struct snd_soc_component_driver soc_codec_dev_max98373 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_max98373); +static int max98373_sdw_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = { - .probe = NULL, + .probe = max98373_sdw_probe, .controls = max98373_snd_controls, .num_controls = ARRAY_SIZE(max98373_snd_controls), .dapm_widgets = max98373_dapm_widgets, diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 2a6b1648c884..d83f81d9ff4e 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -10,7 +10,7 @@ #include <linux/cdev.h> #include <linux/dmi.h> #include <linux/firmware.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of_gpio.h> diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 82f20a8e27ad..a1d0179e12c7 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -448,9 +448,9 @@ static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: max9860->fmt = fmt; return 0; diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 20a07c92b2fc..098a58990f07 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -328,8 +328,8 @@ static const struct snd_kcontrol_new rx1_mix2_inp1_mux = SOC_DAPM_ENUM( static const struct snd_kcontrol_new rx2_mix2_inp1_mux = SOC_DAPM_ENUM( "RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum); -/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ -static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); +/* Digital Gain control -84 dB to +40 dB in 1 dB steps */ +static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); /* Cutoff Freq for High Pass Filter at -3dB */ static const char * const hpf_cutoff_text[] = { @@ -510,15 +510,15 @@ static int wcd_iir_filter_info(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), @@ -553,22 +553,22 @@ static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { WCD_IIR_FILTER_CTL("IIR2 Band3", IIR2, BAND3), WCD_IIR_FILTER_CTL("IIR2 Band4", IIR2, BAND4), WCD_IIR_FILTER_CTL("IIR2 Band5", IIR2, BAND5), - SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL, + -84, 40, digital_gain), }; diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 60b209efe52d..93f35e8d26fc 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -2479,6 +2479,7 @@ static int mt6358_platform_driver_probe(struct platform_device *pdev) static const struct of_device_id mt6358_of_match[] = { {.compatible = "mediatek,mt6358-sound",}, + {.compatible = "mediatek,mt6366-sound",}, {} }; MODULE_DEVICE_TABLE(of, mt6358_of_match); diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 08f6c56dc387..3907d1dd8cee 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -726,6 +726,17 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, struct nau8822_pll *pll_param = &nau8822->pll; int ret, fs; + if (freq_in == pll_param->freq_in && + freq_out == pll_param->freq_out) + return 0; + + if (freq_out == 0) { + dev_dbg(component->dev, "PLL disabled\n"); + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); + return 0; + } + fs = freq_out / 256; ret = nau8822_calc_pll(freq_in, fs, pll_param); @@ -762,6 +773,9 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_update_bits(component, NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_ON); + pll_param->freq_in = freq_in; + pll_param->freq_out = freq_out; + return 0; } diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index b45d42c15de6..547ec057f853 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -198,6 +198,8 @@ struct nau8822_pll { int mclk_scaler; int pll_frac; int pll_int; + int freq_in; + int freq_out; }; /* Codec Private Data */ diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 86b679cf7aef..1d523bfd9d84 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -69,11 +69,11 @@ static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) snd_soc_component_get_drvdata(dai->component); unsigned int val; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER; break; default: diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 72f673f278ee..0be6e72ff5a9 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -608,7 +608,19 @@ static const struct sdw_slave_ops rt1308_slave_ops = { .bus_config = rt1308_bus_config, }; +static int rt1308_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_component_sdw_rt1308 = { + .probe = rt1308_sdw_component_probe, .controls = rt1308_snd_controls, .num_controls = ARRAY_SIZE(rt1308_snd_controls), .dapm_widgets = rt1308_dapm_widgets, diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 2d6b5f9d4d77..e53396606a1c 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -590,7 +590,19 @@ static struct sdw_slave_ops rt1316_slave_ops = { .update_status = rt1316_update_status, }; +static int rt1316_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_component_sdw_rt1316 = { + .probe = rt1316_sdw_component_probe, .controls = rt1316_snd_controls, .num_controls = ARRAY_SIZE(rt1316_snd_controls), .dapm_widgets = rt1316_dapm_widgets, diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index ab093bdb5552..a5615e94ec7d 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -980,14 +980,11 @@ static int rt274_probe(struct snd_soc_component *component) struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); rt274->component = component; + INIT_DELAYED_WORK(&rt274->jack_detect_work, rt274_jack_detect_work); - if (rt274->i2c->irq) { - INIT_DELAYED_WORK(&rt274->jack_detect_work, - rt274_jack_detect_work); + if (rt274->i2c->irq) schedule_delayed_work(&rt274->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(1250)); return 0; } diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index ad8ea1fa7c23..0534a073ee69 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -311,7 +311,8 @@ static void rt286_jack_detect_work(struct work_struct *work) SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); } -int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) +static int rt286_mic_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); @@ -335,7 +336,6 @@ int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j return 0; } -EXPORT_SYMBOL_GPL(rt286_mic_detect); static int is_mclk_mode(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) @@ -947,17 +947,11 @@ static int rt286_probe(struct snd_soc_component *component) struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); rt286->component = component; + INIT_DELAYED_WORK(&rt286->jack_detect_work, rt286_jack_detect_work); - if (rt286->i2c->irq) { - regmap_update_bits(rt286->regmap, - RT286_IRQ_CTRL, 0x2, 0x2); - - INIT_DELAYED_WORK(&rt286->jack_detect_work, - rt286_jack_detect_work); + if (rt286->i2c->irq) schedule_delayed_work(&rt286->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(50)); return 0; } @@ -1055,6 +1049,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = { .suspend = rt286_suspend, .resume = rt286_resume, .set_bias_level = rt286_set_bias_level, + .set_jack = rt286_mic_detect, .controls = rt286_snd_controls, .num_controls = ARRAY_SIZE(rt286_snd_controls), .dapm_widgets = rt286_dapm_widgets, diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h index f27a4e71d5b6..4b7a3bd6043d 100644 --- a/sound/soc/codecs/rt286.h +++ b/sound/soc/codecs/rt286.h @@ -196,7 +196,5 @@ enum { RT286_AIFS, }; -int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); - #endif /* __RT286_H__ */ diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index c291786dc82d..1a27e5e63289 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -326,7 +326,8 @@ static void rt298_jack_detect_work(struct work_struct *work) SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); } -int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) +static int rt298_mic_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) { struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm; @@ -358,7 +359,6 @@ int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j return 0; } -EXPORT_SYMBOL_GPL(rt298_mic_detect); static int is_mclk_mode(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) @@ -1011,17 +1011,11 @@ static int rt298_probe(struct snd_soc_component *component) struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); rt298->component = component; + INIT_DELAYED_WORK(&rt298->jack_detect_work, rt298_jack_detect_work); - if (rt298->i2c->irq) { - regmap_update_bits(rt298->regmap, - RT298_IRQ_CTRL, 0x2, 0x2); - - INIT_DELAYED_WORK(&rt298->jack_detect_work, - rt298_jack_detect_work); + if (rt298->i2c->irq) schedule_delayed_work(&rt298->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(1250)); return 0; } @@ -1120,6 +1114,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = { .suspend = rt298_suspend, .resume = rt298_resume, .set_bias_level = rt298_set_bias_level, + .set_jack = rt298_mic_detect, .controls = rt298_snd_controls, .num_controls = ARRAY_SIZE(rt298_snd_controls), .dapm_widgets = rt298_dapm_widgets, diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h index ed2b8fd87f4c..f1be9c135401 100644 --- a/sound/soc/codecs/rt298.h +++ b/sound/soc/codecs/rt298.h @@ -207,7 +207,5 @@ enum { RT298_AIFS, }; -int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); - #endif /* __RT298_H__ */ diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 9bceeeb830b1..055c3ae974d8 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -818,9 +818,14 @@ static const struct snd_soc_dapm_route rt700_audio_map[] = { static int rt700_probe(struct snd_soc_component *component) { struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + int ret; rt700->component = component; + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; } diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 5ad53bbc8528..925268121901 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -1194,10 +1194,15 @@ static int rt711_sdca_parse_dt(struct rt711_sdca_priv *rt711, struct device *dev static int rt711_sdca_probe(struct snd_soc_component *component) { struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711_sdca_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; } diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 9df800abfc2d..1bf618089194 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -935,10 +935,15 @@ static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) static int rt711_probe(struct snd_soc_component *component) { struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; } diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 5857d0866307..ce8bbc76199a 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -758,7 +758,19 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { {"ADC 25 Mux", "DMIC4", "DMIC4"}, }; +static int rt715_sdca_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = { + .probe = rt715_sdca_probe, .controls = rt715_sdca_snd_controls, .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls), .dapm_widgets = rt715_sdca_dapm_widgets, diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 418e006b19ef..e93240521c74 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -737,7 +737,19 @@ static int rt715_set_bias_level(struct snd_soc_component *component, return 0; } +static int rt715_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rt715 = { + .probe = rt715_probe, .set_bias_level = rt715_set_bias_level, .controls = rt715_snd_controls, .num_controls = ARRAY_SIZE(rt715_snd_controls), diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 83acbdbb8e0d..012f209e76e9 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -409,8 +409,8 @@ static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) bool invert_fclk; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 7964e922b07f..1821854ca0f3 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -411,11 +411,11 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int iface = 0; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 08ced09ef001..b47321c597d0 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -278,8 +278,8 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int ctrl1 = 0; bool invert_fclk; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 8585cbef4c9b..17e5077f26b0 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -601,8 +601,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); u8 confb = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 9189fb3648f7..b2d15d20fe63 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -630,8 +630,8 @@ static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component); unsigned int confb = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 3be4940e3c77..10a6a112f4b4 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -199,10 +199,10 @@ static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(dai->component->dev, - "%s: ERROR: Unsupporter master mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + "%s: ERROR: Unsupported clocking mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index b5c9c61ff5a8..c98a9332dcc0 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -347,17 +347,17 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct tas2552_data *tas2552 = dev_get_drvdata(component->dev); u8 serial_format; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: serial_format = 0x00; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: serial_format = TAS2552_WCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: serial_format = TAS2552_BCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR); break; default: diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index c1dbd978d550..f6037a148cb6 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -340,11 +340,11 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(tas2770->dev, "ASI format master is not found\n"); + dev_err(tas2770->dev, "ASI invalid DAI clocking\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 5c0df3cd4832..05b57bb1aea0 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -318,7 +318,7 @@ static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai, struct tas5086_private *priv = snd_soc_component_get_drvdata(component); /* The TAS5086 can only be slave to all clocks */ - if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(component->dev, "Invalid clocking mode\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 17034abef568..2ee06a95f3e4 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -89,8 +89,8 @@ static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) u8 serial_format; int ret; - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - dev_vdbg(component->dev, "DAI Format master is not found\n"); + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { + dev_vdbg(component->dev, "DAI clocking invalid\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 22b53856e691..9c9a6ec4d977 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -160,11 +160,11 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt); /* clock masters */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clocking\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index 3d8e8c2276f0..41a9b1b76e62 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -111,8 +111,8 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) int i2s_set; int sck_pol; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c index dc86852752c5..8ab2656de750 100644 --- a/sound/soc/codecs/tfa989x.c +++ b/sound/soc/codecs/tfa989x.c @@ -40,12 +40,14 @@ #define TFA989X_I2S_SEL_REG 0x0a #define TFA989X_I2S_SEL_REG_SPKR_MSK GENMASK(10, 9) /* speaker impedance */ #define TFA989X_I2S_SEL_REG_DCFG_MSK GENMASK(14, 11) /* DCDC compensation */ +#define TFA989X_HIDE_UNHIDE_KEY 0x40 #define TFA989X_PWM_CONTROL 0x41 #define TFA989X_CURRENTSENSE1 0x46 #define TFA989X_CURRENTSENSE2 0x47 #define TFA989X_CURRENTSENSE3 0x48 #define TFA989X_CURRENTSENSE4 0x49 +#define TFA9890_REVISION 0x80 #define TFA9895_REVISION 0x12 #define TFA9897_REVISION 0x97 @@ -188,6 +190,33 @@ static struct snd_soc_dai_driver tfa989x_dai = { .ops = &tfa989x_dai_ops, }; +static int tfa9890_init(struct regmap *regmap) +{ + int ret; + + /* unhide keys to allow updating them */ + ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b); + if (ret) + return ret; + + /* update PLL registers */ + ret = regmap_set_bits(regmap, 0x59, 0x3); + if (ret) + return ret; + + /* hide keys again */ + ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000); + if (ret) + return ret; + + return regmap_write(regmap, TFA989X_CURRENTSENSE2, 0x7BE1); +} + +static const struct tfa989x_rev tfa9890_rev = { + .rev = TFA9890_REVISION, + .init = tfa9890_init, +}; + static const struct reg_sequence tfa9895_reg_init[] = { /* some other registers must be set for optimal amplifier behaviour */ { TFA989X_BAT_PROT, 0x13ab }, @@ -376,6 +405,7 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c) } static const struct of_device_id tfa989x_of_match[] = { + { .compatible = "nxp,tfa9890", .data = &tfa9890_rev }, { .compatible = "nxp,tfa9895", .data = &tfa9895_rev }, { .compatible = "nxp,tfa9897", .data = &tfa9897_rev }, { } diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index 82532ad00c3c..748998e48af9 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -1252,8 +1252,7 @@ static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) int master = 0; int ret; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBP_CFP: master = 1; clkdir = ADC3XXX_BCLK_MASTER | ADC3XXX_WCLK_MASTER; diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index b55f0b836932..de5b184a701e 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -713,16 +713,14 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, bool inverted_bclk = false; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clock provider\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 2400093e2c99..c86ca793a2b6 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -429,12 +429,11 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & (~0x03); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg |= TLV320AIC23_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface_reg &= ~TLV320AIC23_MS_MASTER; break; default: diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 077415a57225..f85f8061639f 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -32,7 +32,7 @@ struct aic26 { struct spi_device *spi; struct regmap *regmap; struct snd_soc_component *component; - int master; + int clock_provider; int datfm; int mclk; @@ -117,8 +117,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, reg = dval << 2; snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg); - /* Audio Control 3 (master mode, fsref rate) */ - if (aic26->master) + /* Audio Control 3 (clock provider mode, fsref rate) */ + if (aic26->clock_provider) reg = 0x0800; if (fsref == 48000) reg = 0x2000; @@ -178,10 +178,9 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n", codec_dai, fmt); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aic26->clock_provider = 1; break; + case SND_SOC_DAIFMT_CBC_CFC: aic26->clock_provider = 0; break; default: dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL; } @@ -363,7 +362,7 @@ static int aic26_spi_probe(struct spi_device *spi) /* Initialize the driver data */ aic26->spi = spi; dev_set_drvdata(&spi->dev, aic26); - aic26->master = 1; + aic26->clock_provider = 1; ret = devm_snd_soc_register_component(&spi->dev, &aic26_soc_component_dev, &aic26_dai, 1); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index b2e59581c17a..aacee2367992 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1033,8 +1033,8 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component, struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); int ret; - fmt &= SND_SOC_DAIFMT_MASTER_MASK; - if (fmt == SND_SOC_DAIFMT_CBS_CFS && + fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + if (fmt == SND_SOC_DAIFMT_CBC_CFC && aic31xx->master_dapm_route_applied) { /* * Remove the DAPM route(s) for codec clock master modes, @@ -1051,7 +1051,7 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component, return ret; aic31xx->master_dapm_route_applied = false; - } else if (fmt != SND_SOC_DAIFMT_CBS_CFS && + } else if (fmt != SND_SOC_DAIFMT_CBC_CFC && !aic31xx->master_dapm_route_applied) { /* * Add the needed DAPM route(s) for codec clock master modes, @@ -1083,21 +1083,20 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: iface_reg1 |= AIC31XX_WCLK_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: iface_reg1 |= AIC31XX_BCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clock provider\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 8f42fd7bc053..a8e6adf62ac8 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -615,15 +615,14 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u8 iface_reg_2 = 0; u8 iface_reg_3 = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: - printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n"); + printk(KERN_ERR "aic32x4: invalid clock provider\n"); return -EINVAL; } diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index d53037b1509d..610e41bbf388 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1253,22 +1253,21 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_areg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & 0x3f; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aic3x->master = 1; iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: aic3x->master = 0; iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER); break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aic3x->master = 1; iface_areg |= BIT_CLK_MASTER; iface_areg &= ~WORD_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aic3x->master = 1; iface_areg |= WORD_CLK_MASTER; iface_areg &= ~BIT_CLK_MASTER; diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 66f1d1cd6cf0..371026eb8f41 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1317,16 +1317,14 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A); aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - /* Codec Master */ + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK); break; - case SND_SOC_DAIFMT_CBS_CFS: - /* Codec Slave */ + case SND_SOC_DAIFMT_CBC_CFC: if (dac33->fifo_mode) { - dev_err(component->dev, "FIFO mode requires master mode\n"); + dev_err(component->dev, "FIFO mode requires provider mode\n"); return -EINVAL; } else aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 0ba3546ef870..87b58017094b 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -34,6 +34,14 @@ #define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) +struct twl4030_board_params { + unsigned int digimic_delay; /* in ms */ + unsigned int ramp_delay_value; + unsigned int offset_cncl_path; + unsigned int hs_extmute:1; + int hs_extmute_gpio; +}; + /* codec private data */ struct twl4030_priv { unsigned int codec_powered; @@ -58,7 +66,7 @@ struct twl4030_priv { u8 carkitl_enabled, carkitr_enabled; u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1]; - struct twl4030_codec_data *pdata; + struct twl4030_board_params *board_params; }; static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) @@ -193,73 +201,71 @@ static void twl4030_codec_enable(struct snd_soc_component *component, int enable udelay(10); } -static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata, - struct device_node *node) +static void +twl4030_get_board_param_values(struct twl4030_board_params *board_params, + struct device_node *node) { int value; - of_property_read_u32(node, "ti,digimic_delay", - &pdata->digimic_delay); - of_property_read_u32(node, "ti,ramp_delay_value", - &pdata->ramp_delay_value); - of_property_read_u32(node, "ti,offset_cncl_path", - &pdata->offset_cncl_path); + of_property_read_u32(node, "ti,digimic_delay", &board_params->digimic_delay); + of_property_read_u32(node, "ti,ramp_delay_value", &board_params->ramp_delay_value); + of_property_read_u32(node, "ti,offset_cncl_path", &board_params->offset_cncl_path); if (!of_property_read_u32(node, "ti,hs_extmute", &value)) - pdata->hs_extmute = value; + board_params->hs_extmute = value; - pdata->hs_extmute_gpio = of_get_named_gpio(node, - "ti,hs_extmute_gpio", 0); - if (gpio_is_valid(pdata->hs_extmute_gpio)) - pdata->hs_extmute = 1; + board_params->hs_extmute_gpio = of_get_named_gpio(node, "ti,hs_extmute_gpio", 0); + if (gpio_is_valid(board_params->hs_extmute_gpio)) + board_params->hs_extmute = 1; } -static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component) +static struct twl4030_board_params* +twl4030_get_board_params(struct snd_soc_component *component) { - struct twl4030_codec_data *pdata = dev_get_platdata(component->dev); + struct twl4030_board_params *board_params = NULL; struct device_node *twl4030_codec_node = NULL; twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node, "codec"); - if (!pdata && twl4030_codec_node) { - pdata = devm_kzalloc(component->dev, - sizeof(struct twl4030_codec_data), - GFP_KERNEL); - if (!pdata) { + if (twl4030_codec_node) { + board_params = devm_kzalloc(component->dev, + sizeof(struct twl4030_board_params), + GFP_KERNEL); + if (!board_params) { of_node_put(twl4030_codec_node); return NULL; } - twl4030_setup_pdata_of(pdata, twl4030_codec_node); + twl4030_get_board_param_values(board_params, twl4030_codec_node); of_node_put(twl4030_codec_node); } - return pdata; + return board_params; } static void twl4030_init_chip(struct snd_soc_component *component) { - struct twl4030_codec_data *pdata; + struct twl4030_board_params *board_params; struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); u8 reg, byte; int i = 0; - pdata = twl4030_get_pdata(component); + board_params = twl4030_get_board_params(component); - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { int ret; - if (!pdata->hs_extmute_gpio) + if (!board_params->hs_extmute_gpio) dev_warn(component->dev, "Extmute GPIO is 0 is this correct?\n"); - ret = gpio_request_one(pdata->hs_extmute_gpio, + ret = gpio_request_one(board_params->hs_extmute_gpio, GPIOF_OUT_INIT_LOW, "hs_extmute"); if (ret) { dev_err(component->dev, "Failed to get hs_extmute GPIO\n"); - pdata->hs_extmute_gpio = -1; + board_params->hs_extmute_gpio = -1; } } else { u8 pin_mux; @@ -290,14 +296,14 @@ static void twl4030_init_chip(struct snd_soc_component *component) twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32); /* Machine dependent setup */ - if (!pdata) + if (!board_params) return; - twl4030->pdata = pdata; + twl4030->board_params = board_params; reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET); reg &= ~TWL4030_RAMP_DELAY; - reg |= (pdata->ramp_delay_value << 2); + reg |= (board_params->ramp_delay_value << 2); twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg); /* initiate offset cancellation */ @@ -305,7 +311,7 @@ static void twl4030_init_chip(struct snd_soc_component *component) reg = twl4030_read(component, TWL4030_REG_ANAMICL); reg &= ~TWL4030_OFFSET_CNCL_SEL; - reg |= pdata->offset_cncl_path; + reg |= board_params->offset_cncl_path; twl4030_write(component, TWL4030_REG_ANAMICL, reg | TWL4030_CNCL_OFFSET_START); @@ -692,7 +698,7 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) { unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; /* Base values for ramp delay calculation: 2^19 - 2^26 */ unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864}; @@ -705,9 +711,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) /* Enable external mute control, this dramatically reduces * the pop-noise */ - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - gpio_set_value(pdata->hs_extmute_gpio, 1); + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { + gpio_set_value(board_params->hs_extmute_gpio, 1); } else { hs_pop |= TWL4030_EXTMUTE; twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -741,9 +747,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) } /* Disable external mute */ - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - gpio_set_value(pdata->hs_extmute_gpio, 0); + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { + gpio_set_value(board_params->hs_extmute_gpio, 0); } else { hs_pop &= ~TWL4030_EXTMUTE; twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -806,10 +812,10 @@ static int digimic_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; - if (pdata && pdata->digimic_delay) - twl4030_wait_ms(pdata->digimic_delay); + if (board_params && board_params->digimic_delay) + twl4030_wait_ms(board_params->digimic_delay); return 0; } @@ -2168,10 +2174,11 @@ static int twl4030_soc_probe(struct snd_soc_component *component) static void twl4030_soc_remove(struct snd_soc_component *component) { struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; - if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) - gpio_free(pdata->hs_extmute_gpio); + if (board_params && board_params->hs_extmute && + gpio_is_valid(board_params->hs_extmute_gpio)) + gpio_free(board_params->hs_extmute_gpio); } static const struct snd_soc_component_driver soc_component_dev_twl4030 = { diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c index 8670a2a05a56..9d5ed34e5420 100644 --- a/sound/soc/codecs/uda1334.c +++ b/sound/soc/codecs/uda1334.c @@ -169,7 +169,7 @@ static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK | - SND_SOC_DAIFMT_MASTER_MASK); + SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC)) { diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index c53c2ef33e1a..31009283e7d4 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1306,7 +1306,7 @@ exit: static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) { struct wcd_mbhc *mbhc = data; - u8 clamp_state = 0; + u8 clamp_state; u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY; /* diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index d9f135200688..7d40a61b03b0 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1813,11 +1813,11 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; shift = (tx_port << 1); shift_val = 0x03; - } else if ((tx_port >= 4) && (tx_port < 8)) { + } else if (tx_port < 8) { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; shift = ((tx_port - 4) << 1); shift_val = 0x03; - } else if ((tx_port >= 8) && (tx_port < 11)) { + } else if (tx_port < 11) { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; shift = ((tx_port - 8) << 1); shift_val = 0x03; @@ -2259,51 +2259,42 @@ static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc, static const struct snd_kcontrol_new wcd9335_snd_controls[] = { /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", - WCD9335_CDC_RX0_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", - WCD9335_CDC_RX1_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", - WCD9335_CDC_RX2_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", - WCD9335_CDC_RX3_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", - WCD9335_CDC_RX4_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", - WCD9335_CDC_RX5_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", - WCD9335_CDC_RX6_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", - WCD9335_CDC_RX7_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", - WCD9335_CDC_RX8_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + -84, 40, digital_gain), SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 1edac3e10f34..e794e020052e 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -357,20 +357,20 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) int ret = 0; switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: if (dev->capability & DW_I2S_SLAVE) ret = 0; else ret = -EINVAL; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: if (dev->capability & DW_I2S_MASTER) ret = 0; else ret = -EINVAL; break; - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BP_FC: ret = -EINVAL; break; default: diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 5038faf035cb..33eabb96340e 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -114,8 +114,8 @@ static int fsl_asrc_dma_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dmaengine_terminate_all(pair->dma_chan[OUT]); - dmaengine_terminate_all(pair->dma_chan[IN]); + dmaengine_terminate_async(pair->dma_chan[OUT]); + dmaengine_terminate_async(pair->dma_chan[IN]); break; default: return -EINVAL; @@ -129,6 +129,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params) { enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; @@ -139,6 +140,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_soc_component *component_be = NULL; struct fsl_asrc *asrc = pair->asrc; struct dma_slave_config config_fe, config_be; + struct sdma_peripheral_config audio_config; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; struct device_node *of_dma_node; @@ -221,6 +223,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, /* Get DMA request of Back-End */ tmp_data = tmp_chan->private; pair->dma_data.dma_request = tmp_data->dma_request; + be_peripheral_type = tmp_data->peripheral_type; if (!be_chan) dma_release_channel(tmp_chan); @@ -268,6 +271,17 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, config_be.dst_addr_width = buswidth; config_be.dst_maxburst = dma_params_be->maxburst; + memset(&audio_config, 0, sizeof(audio_config)); + config_be.peripheral_config = &audio_config; + config_be.peripheral_size = sizeof(audio_config); + + if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL || + be_peripheral_type == IMX_DMATYPE_SPDIF)) + audio_config.n_fifos_dst = 2; + if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL || + be_peripheral_type == IMX_DMATYPE_SPDIF)) + audio_config.n_fifos_src = 2; + if (tx) { config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index); config_be.dst_addr = dma_params_be->addr; diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 6dbb8c99f626..43857b7a81c9 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -259,8 +259,8 @@ static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* For playback the AUDMIX is consumer, and for record is provider */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -317,7 +317,7 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, } static const struct snd_soc_dai_ops fsl_audmix_dai_ops = { - .set_fmt = fsl_audmix_dai_set_fmt, + .set_fmt = fsl_audmix_dai_set_fmt, .trigger = fsl_audmix_dai_trigger, }; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 1a2bdf8e76f0..75f7807df29a 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -480,16 +480,16 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: esai_priv->consumer_mode = true; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: xccr |= ESAI_xCCR_xCKD; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: xccr |= ESAI_xCCR_xFSD; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD; break; default: diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index ceaecbe3a25e..bb25c58e335f 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -10,6 +10,7 @@ #include <linux/moduleparam.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/pm.h> @@ -29,15 +30,41 @@ #define MQS_CLK_DIV_MASK (0xFF << 0) #define MQS_CLK_DIV_SHIFT (0) +/** + * struct fsl_mqs_soc_data - soc specific data + * + * @use_gpr: control register is in General Purpose Register group + * @ctrl_off: control register offset + * @en_mask: enable bit mask + * @en_shift: enable bit shift + * @rst_mask: reset bit mask + * @rst_shift: reset bit shift + * @osr_mask: oversample bit mask + * @osr_shift: oversample bit shift + * @div_mask: clock divider mask + * @div_shift: clock divider bit shift + */ +struct fsl_mqs_soc_data { + bool use_gpr; + int ctrl_off; + int en_mask; + int en_shift; + int rst_mask; + int rst_shift; + int osr_mask; + int osr_shift; + int div_mask; + int div_shift; +}; + /* codec private data */ struct fsl_mqs { struct regmap *regmap; struct clk *mclk; struct clk *ipg; + const struct fsl_mqs_soc_data *soc; - unsigned int reg_iomuxc_gpr2; unsigned int reg_mqs_ctrl; - bool use_gpr; }; #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) @@ -65,19 +92,11 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, res = mclk_rate % (32 * lrclk * 2 * 8); if (res == 0 && div > 0 && div <= 256) { - if (mqs_priv->use_gpr) { - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_CLK_DIV_MASK, - (div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT); - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0); - } else { - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_CLK_DIV_MASK, - (div - 1) << MQS_CLK_DIV_SHIFT); - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_OVERSAMPLE_MASK, 0); - } + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->div_mask, + (div - 1) << mqs_priv->soc->div_shift); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->osr_mask, 0); } else { dev_err(component->dev, "can't get proper divider\n"); } @@ -103,7 +122,7 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -118,14 +137,9 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - if (mqs_priv->use_gpr) - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_EN_MASK, - 1 << IMX6SX_GPR2_MQS_EN_SHIFT); - else - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_EN_MASK, - 1 << MQS_EN_SHIFT); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->en_mask, + 1 << mqs_priv->soc->en_shift); return 0; } @@ -135,12 +149,8 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - if (mqs_priv->use_gpr) - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_EN_MASK, 0); - else - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_EN_MASK, 0); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->en_mask, 0); } static const struct snd_soc_component_driver soc_codec_fsl_mqs = { @@ -191,12 +201,9 @@ static int fsl_mqs_probe(struct platform_device *pdev) * But in i.MX8QM/i.MX8QXP the control register is moved * to its own domain. */ - if (of_device_is_compatible(np, "fsl,imx8qm-mqs")) - mqs_priv->use_gpr = false; - else - mqs_priv->use_gpr = true; + mqs_priv->soc = of_device_get_match_data(&pdev->dev); - if (mqs_priv->use_gpr) { + if (mqs_priv->soc->use_gpr) { gpr_np = of_parse_phandle(np, "gpr", 0); if (!gpr_np) { dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); @@ -280,12 +287,7 @@ static int fsl_mqs_runtime_resume(struct device *dev) return ret; } - if (mqs_priv->use_gpr) - regmap_write(mqs_priv->regmap, IOMUXC_GPR2, - mqs_priv->reg_iomuxc_gpr2); - else - regmap_write(mqs_priv->regmap, REG_MQS_CTRL, - mqs_priv->reg_mqs_ctrl); + regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl); return 0; } @@ -293,12 +295,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev) { struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); - if (mqs_priv->use_gpr) - regmap_read(mqs_priv->regmap, IOMUXC_GPR2, - &mqs_priv->reg_iomuxc_gpr2); - else - regmap_read(mqs_priv->regmap, REG_MQS_CTRL, - &mqs_priv->reg_mqs_ctrl); + regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl); clk_disable_unprepare(mqs_priv->mclk); clk_disable_unprepare(mqs_priv->ipg); @@ -315,9 +312,49 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = { pm_runtime_force_resume) }; +static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { + .use_gpr = false, + .ctrl_off = REG_MQS_CTRL, + .en_mask = MQS_EN_MASK, + .en_shift = MQS_EN_SHIFT, + .rst_mask = MQS_SW_RST_MASK, + .rst_shift = MQS_SW_RST_SHIFT, + .osr_mask = MQS_OVERSAMPLE_MASK, + .osr_shift = MQS_OVERSAMPLE_SHIFT, + .div_mask = MQS_CLK_DIV_MASK, + .div_shift = MQS_CLK_DIV_SHIFT, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { + .use_gpr = true, + .ctrl_off = IOMUXC_GPR2, + .en_mask = IMX6SX_GPR2_MQS_EN_MASK, + .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT, + .rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK, + .rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT, + .osr_mask = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, + .osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT, + .div_mask = IMX6SX_GPR2_MQS_CLK_DIV_MASK, + .div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { + .use_gpr = true, + .ctrl_off = 0x20, + .en_mask = BIT(1), + .en_shift = 1, + .rst_mask = BIT(2), + .rst_shift = 2, + .osr_mask = BIT(3), + .osr_shift = 3, + .div_mask = GENMASK(15, 8), + .div_shift = 8, +}; + static const struct of_device_id fsl_mqs_dt_ids[] = { - { .compatible = "fsl,imx8qm-mqs", }, - { .compatible = "fsl,imx6sx-mqs", }, + { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data }, + { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data }, + { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data }, {} }; MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index e765da9a19e7..4f5bd9597c74 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -292,19 +292,19 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: sai->is_consumer_mode = true; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; sai->is_consumer_mode = true; break; @@ -437,6 +437,12 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, savediv / 2 - 1); + if (sai->soc_data->max_register >= FSL_SAI_MCTL) { + /* SAI is in master mode at this point, so enable MCLK */ + regmap_update_bits(sai->regmap, FSL_SAI_MCTL, + FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); + } + return 0; } @@ -1004,6 +1010,7 @@ static int fsl_sai_runtime_resume(struct device *dev); static int fsl_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct fsl_sai *sai; struct regmap *gpr; struct resource *res; @@ -1012,12 +1019,12 @@ static int fsl_sai_probe(struct platform_device *pdev) int irq, ret, i; int index; - sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); + sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); if (!sai) return -ENOMEM; sai->pdev = pdev; - sai->soc_data = of_device_get_match_data(&pdev->dev); + sai->soc_data = of_device_get_match_data(dev); sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); @@ -1032,18 +1039,18 @@ static int fsl_sai_probe(struct platform_device *pdev) ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); } - sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config); + sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); + dev_err(dev, "regmap init failed\n"); return PTR_ERR(sai->regmap); } - sai->bus_clk = devm_clk_get(&pdev->dev, "bus"); + sai->bus_clk = devm_clk_get(dev, "bus"); /* Compatible with old DTB cases */ if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER) - sai->bus_clk = devm_clk_get(&pdev->dev, "sai"); + sai->bus_clk = devm_clk_get(dev, "sai"); if (IS_ERR(sai->bus_clk)) { - dev_err(&pdev->dev, "failed to get bus clock: %ld\n", + dev_err(dev, "failed to get bus clock: %ld\n", PTR_ERR(sai->bus_clk)); /* -EPROBE_DEFER */ return PTR_ERR(sai->bus_clk); @@ -1051,9 +1058,9 @@ static int fsl_sai_probe(struct platform_device *pdev) for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { sprintf(tmp, "mclk%d", i); - sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); + sai->mclk_clk[i] = devm_clk_get(dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { - dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", + dev_err(dev, "failed to get mclk%d clock: %ld\n", i + 1, PTR_ERR(sai->mclk_clk[i])); sai->mclk_clk[i] = NULL; } @@ -1068,10 +1075,10 @@ static int fsl_sai_probe(struct platform_device *pdev) if (irq < 0) return irq; - ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED, + ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED, np->name, sai); if (ret) { - dev_err(&pdev->dev, "failed to claim irq %u\n", irq); + dev_err(dev, "failed to claim irq %u\n", irq); return ret; } @@ -1088,7 +1095,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && of_find_property(np, "fsl,sai-asynchronous", NULL)) { /* error out if both synchronous and asynchronous are present */ - dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); + dev_err(dev, "invalid binding for synchronous mode\n"); return -EINVAL; } @@ -1109,7 +1116,7 @@ static int fsl_sai_probe(struct platform_device *pdev) of_device_is_compatible(np, "fsl,imx6ul-sai")) { gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); if (IS_ERR(gpr)) { - dev_err(&pdev->dev, "cannot find iomuxc registers\n"); + dev_err(dev, "cannot find iomuxc registers\n"); return PTR_ERR(gpr); } @@ -1127,23 +1134,23 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; platform_set_drvdata(pdev, sai); - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = fsl_sai_runtime_resume(&pdev->dev); + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = fsl_sai_runtime_resume(dev); if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_get_sync(dev); if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_put_noidle(dev); goto err_pm_get_sync; } /* Get sai version */ - ret = fsl_sai_check_version(&pdev->dev); + ret = fsl_sai_check_version(dev); if (ret < 0) - dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret); + dev_warn(dev, "Error reading SAI version: %d\n", ret); /* Select MCLK direction */ if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && @@ -1152,7 +1159,7 @@ static int fsl_sai_probe(struct platform_device *pdev) FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); } - ret = pm_runtime_put_sync(&pdev->dev); + ret = pm_runtime_put_sync(dev); if (ret < 0) goto err_pm_get_sync; @@ -1162,15 +1169,18 @@ static int fsl_sai_probe(struct platform_device *pdev) */ if (sai->soc_data->use_imx_pcm) { ret = imx_pcm_dma_init(pdev); - if (ret) + if (ret) { + if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)) + dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n"); goto err_pm_get_sync; + } } else { - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) goto err_pm_get_sync; } - ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, + ret = devm_snd_soc_register_component(dev, &fsl_component, &sai->cpu_dai_drv, 1); if (ret) goto err_pm_get_sync; @@ -1178,10 +1188,10 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; err_pm_get_sync: - if (!pm_runtime_status_suspended(&pdev->dev)) - fsl_sai_runtime_suspend(&pdev->dev); + if (!pm_runtime_status_suspended(dev)) + fsl_sai_runtime_suspend(dev); err_pm_disable: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); return ret; } diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 84cb36d9dfea..7dd0c48cd9ae 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -93,7 +93,7 @@ */ #define FSLSSI_AC97_DAIFMT \ (SND_SOC_DAIFMT_AC97 | \ - SND_SOC_DAIFMT_CBM_CFS | \ + SND_SOC_DAIFMT_BC_FP | \ SND_SOC_DAIFMT_NB_NF) #define FSLSSI_SIER_DBG_RX_FLAGS \ @@ -358,13 +358,13 @@ static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) static bool fsl_ssi_is_i2s_clock_provider(struct fsl_ssi *ssi) { return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == - SND_SOC_DAIFMT_CBC_CFC; + SND_SOC_DAIFMT_BP_FP; } -static bool fsl_ssi_is_i2s_cbp_cfc(struct fsl_ssi *ssi) +static bool fsl_ssi_is_i2s_bc_fp(struct fsl_ssi *ssi) { return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == - SND_SOC_DAIFMT_CBP_CFC; + SND_SOC_DAIFMT_BC_FP; } /** @@ -847,7 +847,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u8 i2s_net = ssi->i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ - if (fsl_ssi_is_i2s_cbp_cfc(ssi) && sample_size == 16) + if (fsl_ssi_is_i2s_bc_fp(ssi) && sample_size == 16) i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; /* Use Normal mode to send mono data at 1st slot of 2 slots */ @@ -920,17 +920,17 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: if (IS_ERR(ssi->baudclk)) { dev_err(ssi->dev, "missing baudclk for master mode\n"); return -EINVAL; } fallthrough; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: @@ -992,15 +992,15 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* Output bit and frame sync clocks */ strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; scr |= SSI_SCR_SYS_CLK_EN; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* Input bit or frame sync clocks */ break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: /* Input bit clock but output frame sync clock */ strcr |= SSI_STCR_TFDIR; break; diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index d0556c79fdb1..55e640cba87d 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1228,6 +1228,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) */ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) { + pm_runtime_disable(dev); dev_err(dev, "failed to pcm register\n"); return ret; } @@ -1235,6 +1236,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp, &fsl_xcvr_dai, 1); if (ret) { + pm_runtime_disable(dev); dev_err(dev, "failed to register component %s\n", fsl_xcvr_comp.name); } @@ -1242,6 +1244,12 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return ret; } +static int fsl_xcvr_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} + static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); @@ -1370,6 +1378,7 @@ static struct platform_driver fsl_xcvr_driver = { .pm = &fsl_xcvr_pm_ops, .of_match_table = fsl_xcvr_dt_ids, }, + .remove = fsl_xcvr_remove, }; module_platform_driver(fsl_xcvr_driver); diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 502fe1b522ab..1292a845c424 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -81,7 +81,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream, int ret, dir; /* For playback the AUDMIX is consumer, and for record is provider */ - fmt |= tx ? SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBP_CFP; + fmt |= tx ? SND_SOC_DAIFMT_BP_FP : SND_SOC_DAIFMT_BC_FC; dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN; /* set DAI configuration */ @@ -122,7 +122,7 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream, return 0; /* For playback the AUDMIX is consumer */ - fmt |= SND_SOC_DAIFMT_CBP_CFP; + fmt |= SND_SOC_DAIFMT_BC_FC; /* set AUDMIX DAI configuration */ ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index dfa05d40b276..50b71e5d4589 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -62,17 +62,14 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, uintptr_t port = (uintptr_t)file->private_data; u32 pdcr, ptcr; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) @@ -209,17 +206,14 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, if (!audmux_base) return -ENOSYS; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); return 0; } @@ -298,7 +292,7 @@ static int imx_audmux_probe(struct platform_device *pdev) audmux_clk = NULL; } - audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev); + audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev); switch (audmux_type) { case IMX31_AUDMUX: diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 6f8efd838fcc..1797d777b1b8 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -317,7 +317,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, } } - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + ret = snd_soc_dai_set_fmt(cpu_dai, snd_soc_daifmt_clock_provider_flipped(fmt)); if (ret && ret != -ENOTSUPP) { dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); return ret; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 539d7f081bd7..7be84c7840cb 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -513,7 +513,12 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai, return 0; } -static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, +static inline int asoc_simple_component_is_codec(struct snd_soc_component *component) +{ + return component->driver->endianness; +} + +static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, struct simple_dai_props *dai_props) { struct snd_soc_dai_link *dai_link = rtd->dai_link; @@ -524,7 +529,7 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, /* Only Codecs */ for_each_rtd_components(rtd, i, component) { - if (!snd_soc_component_is_codec(component)) + if (!asoc_simple_component_is_codec(component)) return 0; } @@ -575,7 +580,7 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = asoc_simple_init_dai_link_params(rtd, props); + ret = asoc_simple_init_for_codec2codec(rtd, props); if (ret < 0) return ret; @@ -609,7 +614,7 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); -int asoc_simple_clean_reference(struct snd_soc_card *card) +void asoc_simple_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link_component *cpu; @@ -622,7 +627,6 @@ int asoc_simple_clean_reference(struct snd_soc_card *card) for_each_link_codecs(dai_link, j, codec) of_node_put(codec->of_node); } - return 0; } EXPORT_SYMBOL_GPL(asoc_simple_clean_reference); @@ -877,7 +881,9 @@ int asoc_simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - return asoc_simple_clean_reference(card); + asoc_simple_clean_reference(card); + + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_remove); diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 5da4725d9e16..d28712fabe3f 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -66,7 +66,7 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; unsigned int clock = fmt & SND_SOC_DAIFMT_CLOCK_MASK; unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK; - unsigned int master = fmt & SND_SOC_DAIFMT_MASTER_MASK; + unsigned int master = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; char *str; dev_info(dai->dev, "name : %s", dai->name); @@ -105,16 +105,16 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) str = "unknown"; switch (master) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BP_FP: str = "clk provider, frame provider"; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BC_FP: str = "clk consumer, frame provider"; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BP_FC: str = "clk provider, frame consumer"; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FC: str = "clk consumer, frame consumer"; break; } @@ -192,10 +192,10 @@ static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream, static u64 test_dai_formats = /* * Select below from Sound Card, not auto - * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP - * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP - * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC - * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC + * SND_SOC_POSSIBLE_DAIFMT_BP_FP + * SND_SOC_POSSIBLE_DAIFMT_BC_FP + * SND_SOC_POSSIBLE_DAIFMT_BP_FC + * SND_SOC_POSSIBLE_DAIFMT_BC_FC */ SND_SOC_POSSIBLE_DAIFMT_I2S | SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index a297d4af5099..689ae13f34f5 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -227,9 +227,9 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) * We don't actually set the hardware until the hw_params * call, but we need to validate the user input here. */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -245,8 +245,8 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } i2s->format = fmt; - i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBS_CFS; + i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_BP_FP; return 0; } @@ -375,21 +375,21 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream, hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val); - switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: i2s->master = false; val = hi6210_read_reg(i2s, HII2S_I2S_CFG); val |= HII2S_I2S_CFG__S2_MST_SLV; hi6210_write_reg(i2s, HII2S_I2S_CFG, val); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: i2s->master = true; val = hi6210_read_reg(i2s, HII2S_I2S_CFG); val &= ~HII2S_I2S_CFG__S2_MST_SLV; hi6210_write_reg(i2s, HII2S_I2S_CFG, val); break; default: - WARN_ONCE(1, "Invalid i2s->fmt MASTER_MASK. This shouldn't happen\n"); + WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n"); return -EINVAL; } diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index 09d23b11621c..97cab6d95b16 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -333,8 +333,8 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index 28f48ca1508a..9ec6fc528e2b 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -302,10 +302,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (force_clk_active) control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: control_set |= IMG_I2S_OUT_CTL_MASTER_MASK; break; default: diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 7c85d1bb9c12..e5107a3ce16a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -226,5 +226,8 @@ config SND_SOC_INTEL_AVS capabilities. This includes Skylake, Kabylake, Amberlake and Apollolake. +# Machine board drivers +source "sound/soc/intel/avs/boards/Kconfig" + # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 335c32732994..fd59b35a62ba 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -831,9 +831,9 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); switch (format) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: return SSP_MODE_PROVIDER; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: return SSP_MODE_CONSUMER; default: dev_err(dai->dev, "Invalid ssp protocol: %d\n", format); @@ -1328,7 +1328,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) { struct sst_data *drv = snd_soc_dai_get_drvdata(dai); struct snd_soc_dapm_widget *w; - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream); @@ -1392,7 +1392,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) static int sst_fill_module_list(struct snd_kcontrol *kctl, struct snd_soc_dapm_widget *w, int type) { - struct sst_module *module = NULL; + struct sst_module *module; struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); struct sst_ids *ids = w->priv; int ret = 0; diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 3a42d68c0247..160b50f479fb 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -114,7 +114,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context) { struct intel_sst_drv *drv = (struct intel_sst_drv *) context; - struct ipc_post *__msg, *msg = NULL; + struct ipc_post *__msg, *msg; unsigned long irq_flags; spin_lock_irqsave(&drv->rx_msg_lock, irq_flags); diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 4e8382097e61..4e039c7173d8 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -28,7 +28,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx, u32 msg_id, u32 drv_id) { - struct sst_block *msg = NULL; + struct sst_block *msg; dev_dbg(ctx->dev, "Enter\n"); msg = kzalloc(sizeof(*msg), GFP_KERNEL); @@ -63,7 +63,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx, int sst_wake_up_block(struct intel_sst_drv *ctx, int result, u32 drv_id, u32 ipc, void *data, u32 size) { - struct sst_block *block = NULL; + struct sst_block *block; dev_dbg(ctx->dev, "Enter\n"); @@ -91,7 +91,7 @@ int sst_wake_up_block(struct intel_sst_drv *ctx, int result, int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed) { - struct sst_block *block = NULL, *__block; + struct sst_block *block, *__block; dev_dbg(ctx->dev, "Enter\n"); spin_lock_bh(&ctx->block_lock); @@ -341,7 +341,7 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, } /* FW sent short error response for an IPC */ - if (msg_high.part.result && drv_id && !msg_high.part.large) { + if (msg_high.part.result && !msg_high.part.large) { /* 32-bit FW error code in msg_low */ dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low); sst_wake_up_block(sst_drv_ctx, msg_high.part.result, diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index b6b93ae80304..919212825f21 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -10,3 +10,6 @@ snd-soc-avs-objs += trace.o CFLAGS_trace.o := -I$(src) obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o + +# Machine support +obj-$(CONFIG_SND_SOC) += boards/ diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig new file mode 100644 index 000000000000..4d68e3ef992b --- /dev/null +++ b/sound/soc/intel/avs/boards/Kconfig @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "Intel AVS Machine drivers" + depends on SND_SOC_INTEL_AVS + +comment "Available DSP configurations" + +config SND_SOC_INTEL_AVS_MACH_DA7219 + tristate "da7219 I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_DA7219 + help + This adds support for AVS with DA7219 I2S codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_DMIC + tristate "DMIC generic board" + select SND_SOC_DMIC + help + This adds support for AVS with Digital Mic array configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_HDAUDIO + tristate "HD-Audio generic board" + select SND_SOC_HDA + help + This adds support for AVS with HDAudio codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_I2S_TEST + tristate "I2S test board" + help + This adds support for I2S test-board which can be used to verify + transfer over I2S interface with SSP loopback scenarios. + +config SND_SOC_INTEL_AVS_MACH_MAX98357A + tristate "max98357A I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_MAX98357A + help + This adds support for AVS with MAX98357A I2S codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_MAX98373 + tristate "max98373 I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_MAX98373 + help + This adds support for AVS with MAX98373 I2S codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_NAU8825 + tristate "nau8825 I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_NAU8825 + help + This adds support for ASoC machine driver with NAU8825 I2S audio codec. + It is meant to be used with AVS driver. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_RT274 + tristate "rt274 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT274 + help + This adds support for ASoC machine driver with RT274 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_RT286 + tristate "rt286 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT286 + help + This adds support for ASoC machine driver with RT286 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_RT298 + tristate "rt298 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT298 + help + This adds support for ASoC machine driver with RT298 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_RT5682 + tristate "rt5682 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT5682_I2C + help + This adds support for ASoC machine driver with RT5682 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +config SND_SOC_INTEL_AVS_MACH_SSM4567 + tristate "ssm4567 I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_SSM4567 + help + This adds support for ASoC machine driver with SSM4567 I2S audio codec. + It is meant to be used with AVS driver. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +endmenu diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile new file mode 100644 index 000000000000..25e8c4bb07db --- /dev/null +++ b/sound/soc/intel/avs/boards/Makefile @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-only + +snd-soc-avs-da7219-objs := da7219.o +snd-soc-avs-dmic-objs := dmic.o +snd-soc-avs-hdaudio-objs := hdaudio.o +snd-soc-avs-i2s-test-objs := i2s_test.o +snd-soc-avs-max98357a-objs := max98357a.o +snd-soc-avs-max98373-objs := max98373.o +snd-soc-avs-nau8825-objs := nau8825.o +snd-soc-avs-rt274-objs := rt274.o +snd-soc-avs-rt286-objs := rt286.o +snd-soc-avs-rt298-objs := rt298.o +snd-soc-avs-rt5682-objs := rt5682.o +snd-soc-avs-ssm4567-objs := ssm4567.o + +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_i2s_TEST) += snd-soc-avs-i2s-test.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c new file mode 100644 index 000000000000..02ae542ad779 --- /dev/null +++ b/sound/soc/intel/avs/boards/da7219.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> +#include <uapi/linux/input-event-codes.h> +#include "../../../codecs/da7219.h" +#include "../../../codecs/da7219-aad.h" + +#define DA7219_DAI_NAME "da7219-hifi" + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found. Unable to set/unset codec pll\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); + if (ret) + dev_err(card->dev, "failed to stop PLL: %d\n", ret); + } else if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, + 0, DA7219_PLL_FREQ_OUT_98304); + if (ret) + dev_err(card->dev, "failed to start PLL: %d\n", ret); + } + + return ret; +} + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + /* HP jack connectors - unknown if we have jack detection */ + {"Headphone Jack", NULL, "HPL"}, + {"Headphone Jack", NULL, "HPR"}, + + {"MIC", NULL, "Headset Mic"}, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_card *card = runtime->card; + struct snd_soc_jack *jack; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + int clk_freq; + int ret; + + jack = snd_soc_card_get_drvdata(card); + clk_freq = 19200000; + + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "can't set codec sysclk configuration\n"); + return ret; + } + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack); + if (ret) { + dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + da7219_aad_jack_det(component, jack); + + return 0; +} + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-DLGS7219:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, DA7219_DAI_NAME); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->init = avs_da7219_codec_init; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) + snd_soc_component_set_jack(component, jack, NULL); + return 0; +} + +static int avs_card_remove(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return avs_card_set_jack(card, jack); +} + +static int avs_da7219_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + card->name = "avs_da7219"; + card->dev = dev; + card->owner = THIS_MODULE; + card->remove = avs_card_remove; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_da7219_driver = { + .probe = avs_da7219_probe, + .driver = { + .name = "avs_da7219", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_da7219_driver); + +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_da7219"); diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c new file mode 100644 index 000000000000..90a921638572 --- /dev/null +++ b/sound/soc/intel/avs/boards/dmic.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/device.h> +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> + +SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); +SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin"))); +SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); +/* Name overridden on probe */ +SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM(""))); + +static struct snd_soc_dai_link card_dai_links[] = { + /* Back ends */ + { + .name = "DMIC", + .id = 0, + .dpcm_capture = 1, + .nonatomic = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "DMIC WoV", + .id = 1, + .dpcm_capture = 1, + .nonatomic = 1, + .no_pcm = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform), + }, +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + {"DMic", NULL, "SoC DMIC"}, + {"DMIC Rx", NULL, "Capture"}, + {"DMIC WoV Rx", NULL, "Capture"}, +}; + +static int avs_dmic_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + int ret; + + mach = dev_get_platdata(dev); + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "avs_dmic"; + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = card_dai_links; + card->num_links = ARRAY_SIZE(card_dai_links); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_dmic_driver = { + .probe = avs_dmic_probe, + .driver = { + .name = "avs_dmic", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_dmic_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_dmic"); diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c new file mode 100644 index 000000000000..d2fc41d39448 --- /dev/null +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/platform_device.h> +#include <sound/hda_codec.h> +#include <sound/hda_i915.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/hda.h" + +static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count, + const char *platform_name, struct snd_soc_dai_link **links) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + struct hda_pcm *pcm; + const char *cname = dev_name(&codec->core.dev); + int i; + + dl = devm_kcalloc(dev, pcm_count, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); + + for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { + dl[i].name = devm_kasprintf(dev, GFP_KERNEL, "%s link%d", cname, i); + if (!dl[i].name) + return -ENOMEM; + + dl[i].id = i; + dl[i].nonatomic = 1; + dl[i].no_pcm = 1; + dl[i].dpcm_playback = 1; + dl[i].dpcm_capture = 1; + dl[i].platforms = platform; + dl[i].num_platforms = 1; + + dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + if (!dl[i].codecs || !dl[i].cpus) + return -ENOMEM; + + dl[i].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d", cname, i); + if (!dl[i].cpus->dai_name) + return -ENOMEM; + + dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL); + dl[i].codecs->dai_name = pcm->name; + dl[i].num_codecs = 1; + dl[i].num_cpus = 1; + } + + *links = dl; + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, struct hda_codec *codec, int pcm_count, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + struct hda_pcm *pcm; + const char *cname = dev_name(&codec->core.dev); + int i, n = 0; + + /* at max twice the number of pcms */ + dr = devm_kcalloc(dev, pcm_count * 2, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); + + for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { + struct hda_pcm_stream *stream; + int dir; + + dir = SNDRV_PCM_STREAM_PLAYBACK; + stream = &pcm->stream[dir]; + if (!stream->substreams) + goto capture_routes; + + dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name, + snd_pcm_direction_name(dir)); + dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Tx", cname, i); + if (!dr[n].sink || !dr[n].source) + return -ENOMEM; + n++; + +capture_routes: + dir = SNDRV_PCM_STREAM_CAPTURE; + stream = &pcm->stream[dir]; + if (!stream->substreams) + continue; + + dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Rx", cname, i); + dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name, + snd_pcm_direction_name(dir)); + if (!dr[n].sink || !dr[n].source) + return -ENOMEM; + n++; + } + + *routes = dr; + *num_routes = n; + return 0; +} + +/* Should be aligned with SectionPCM's name from topology */ +#define FEDAI_NAME_PREFIX "HDMI" + +static struct snd_pcm * +avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx) +{ + struct snd_soc_pcm_runtime *rtd; + int dir = SNDRV_PCM_STREAM_PLAYBACK; + + for_each_card_rtds(card, rtd) { + struct snd_pcm *spcm; + int ret, n; + + spcm = rtd->pcm ? rtd->pcm->streams[dir].pcm : NULL; + if (!spcm || !strstr(spcm->id, FEDAI_NAME_PREFIX)) + continue; + + ret = sscanf(spcm->id, FEDAI_NAME_PREFIX "%d", &n); + if (ret != 1) + continue; + if (n == hdmi_idx) + return rtd->pcm; + } + + return NULL; +} + +static int avs_card_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + struct hda_codec *codec = mach->pdata; + struct hda_pcm *hpcm; + /* Topology pcm indexing is 1-based */ + int i = 1; + + list_for_each_entry(hpcm, &codec->pcm_list_head, list) { + struct snd_pcm *spcm; + + spcm = avs_card_hdmi_pcm_at(card, i); + if (spcm) { + hpcm->pcm = spcm; + hpcm->device = spcm->device; + dev_info(card->dev, "%s: mapping HDMI converter %d to PCM %d (%p)\n", + __func__, i, hpcm->device, spcm); + } else { + hpcm->pcm = NULL; + hpcm->device = SNDRV_PCM_INVALID_DEVICE; + dev_warn(card->dev, "%s: no PCM in topology for HDMI converter %d\n", + __func__, i); + } + i++; + } + + return hda_codec_probe_complete(codec); +} + +static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_acpi_mach *mach; + struct snd_soc_dai_link *links = NULL; + struct snd_soc_card *card = rtm->card; + struct hda_codec *codec; + struct hda_pcm *pcm; + int ret, n, pcm_count = 0; + + mach = dev_get_platdata(card->dev); + codec = mach->pdata; + + if (list_empty(&codec->pcm_list_head)) + return -EINVAL; + list_for_each_entry(pcm, &codec->pcm_list_head, list) + pcm_count++; + + ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links); + if (ret < 0) { + dev_err(card->dev, "create links failed: %d\n", ret); + return ret; + } + + for (n = 0; n < pcm_count; n++) { + ret = snd_soc_add_pcm_runtime(card, &links[n]); + if (ret < 0) { + dev_err(card->dev, "add links failed: %d\n", ret); + return ret; + } + } + + ret = avs_create_dapm_routes(card->dev, codec, pcm_count, &routes, &n); + if (ret < 0) { + dev_err(card->dev, "create routes failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, routes, n); + if (ret < 0) { + dev_err(card->dev, "add routes failed: %d\n", ret); + return ret; + } + + return 0; +} + +SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); + +static struct snd_soc_dai_link probing_link = { + .name = "probing-LINK", + .id = -1, + .nonatomic = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .cpus = dummy, + .num_cpus = ARRAY_SIZE(dummy), + .init = avs_probing_link_init, +}; + +static int avs_hdaudio_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *binder; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + struct hda_codec *codec; + + mach = dev_get_platdata(dev); + codec = mach->pdata; + + /* codec may be unloaded before card's probe() fires */ + if (!device_is_registered(&codec->core.dev)) + return -ENODEV; + + binder = devm_kmemdup(dev, &probing_link, sizeof(probing_link), GFP_KERNEL); + if (!binder) + return -ENOMEM; + + binder->platforms = devm_kzalloc(dev, sizeof(*binder->platforms), GFP_KERNEL); + binder->codecs = devm_kzalloc(dev, sizeof(*binder->codecs), GFP_KERNEL); + if (!binder->platforms || !binder->codecs) + return -ENOMEM; + + binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL); + if (!binder->codecs->name) + return -ENOMEM; + + binder->platforms->name = mach->mach_params.platform; + binder->num_platforms = 1; + binder->codecs->dai_name = "codec-probing-DAI"; + binder->num_codecs = 1; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = binder->codecs->name; + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = binder; + card->num_links = 1; + card->fully_routed = true; + if (hda_codec_is_display(codec)) + card->late_probe = avs_card_late_probe; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_hdaudio_driver = { + .probe = avs_hdaudio_probe, + .driver = { + .name = "avs_hdaudio", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_hdaudio_driver) + +MODULE_DESCRIPTION("Intel HD-Audio machine driver"); +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_hdaudio"); diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c new file mode 100644 index 000000000000..461b651cd331 --- /dev/null +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy-dai"); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_dr = 2; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port); + dr[0].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[0].sink || !dr[0].source) + return -ENOMEM; + + dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[1].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port); + if (!dr[1].sink || !dr[1].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_create_dapm_widgets(struct device *dev, int ssp_port, + struct snd_soc_dapm_widget **widgets, int *num_widgets) +{ + struct snd_soc_dapm_widget *dw; + const int num_dw = 2; + + dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL); + if (!dw) + return -ENOMEM; + + dw[0].id = snd_soc_dapm_hp; + dw[0].reg = SND_SOC_NOPM; + dw[0].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port); + if (!dw[0].name) + return -ENOMEM; + + dw[1].id = snd_soc_dapm_mic; + dw[1].reg = SND_SOC_NOPM; + dw[1].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port); + if (!dw[1].name) + return -ENOMEM; + + *widgets = dw; + *num_widgets = num_dw; + + return 0; +} + +static int avs_i2s_test_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_widget *widgets; + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, num_widgets; + int ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = devm_kasprintf(dev, GFP_KERNEL, "ssp%ld-loopback", ssp_port); + if (!card->name) + return -ENOMEM; + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d\n", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d\n", ret); + return ret; + } + + ret = avs_create_dapm_widgets(dev, ssp_port, &widgets, &num_widgets); + if (ret) { + dev_err(dev, "Failed to create dapm widgets: %d\n", ret); + return ret; + } + + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = dai_link; + card->num_links = 1; + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->dapm_widgets = widgets; + card->num_dapm_widgets = num_widgets; + card->fully_routed = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_i2s_test_driver = { + .probe = avs_i2s_test_probe, + .driver = { + .name = "avs_i2s_test", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_i2s_test_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_i2s_test"); diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c new file mode 100644 index 000000000000..921f42caf7e0 --- /dev/null +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + { "Spk", NULL, "Speaker" }, +}; + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "MX98357A:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "HiFi"); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 1; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "HiFi Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_max98357a_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "avs_max98357a"; + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_max98357a_driver = { + .probe = avs_max98357a_probe, + .driver = { + .name = "avs_max98357a", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_max98357a_driver) + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_max98357a"); diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c new file mode 100644 index 000000000000..0fa8f5606385 --- /dev/null +++ b/sound/soc/intel/avs/boards/max98373.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> + +#define MAX98373_DEV0_NAME "i2c-MX98373:00" +#define MAX98373_DEV1_NAME "i2c-MX98373:01" +#define MAX98373_CODEC_NAME "max98373-aif1" + +static struct snd_soc_codec_conf card_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME), + .name_prefix = "Right", + }, + { + .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME), + .name_prefix = "Left", + }, +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, +}; + +static int +avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 16 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + return 0; +} + +static int avs_max98373_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int ret, i; + + for_each_rtd_codec_dais(runtime, i, codec_dai) { + if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); + return ret; + } + } + } + + return 0; +} + +static const struct snd_soc_ops avs_max98373_ops = { + .hw_params = avs_max98373_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV0_NAME); + dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME); + dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV1_NAME); + dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME); + if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name || + !dl->codecs[1].name || !dl->codecs[1].dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 2; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + dl->be_hw_params_fixup = avs_max98373_be_fixup; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + dl->ignore_pmdown_time = 1; + dl->ops = &avs_max98373_ops; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_max98373_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "avs_max98373"; + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = dai_link; + card->num_links = 1; + card->codec_conf = card_codec_conf; + card->num_configs = ARRAY_SIZE(card_codec_conf); + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_max98373_driver = { + .probe = avs_max98373_probe, + .driver = { + .name = "avs_max98373", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_max98373_driver) + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_max98373"); diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c new file mode 100644 index 000000000000..f76909e9f990 --- /dev/null +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/nau8825.h" + +#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" + +static int +avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EINVAL; + } + + if (!SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return ret; + } + } + + return 0; +} + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_nau8825_clock_control, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + { "MIC", NULL, "Headset Mic" }, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + struct snd_soc_card *card = runtime->card; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + /* + * 4 buttons here map to the google Reference headset. + * The use of these buttons can be decided by the user space. + */ + ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, + jack, pins, num_pins); + if (ret) + return ret; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + //snd_soc_component_set_jack(component, jack, NULL); + // TODO: Fix nau8825 codec to use .set_jack, like everyone else + nau8825_enable_jack_detect(component, jack); + + return 0; +} + +static int +avs_nau8825_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_nau8825_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set FS clock %d\n", ret); + break; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256); + if (ret < 0) + dev_err(codec_dai->dev, "can't set FLL: %d\n", ret); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256); + if (ret < 0) + dev_err(codec_dai->dev, "can't set FLL: %d\n", ret); + break; + } + + return ret; +} + + +static const struct snd_soc_ops avs_nau8825_ops = { + .trigger = avs_nau8825_trigger, +}; + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10508825:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, SKL_NUVOTON_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->init = avs_nau8825_codec_init; + dl->be_hw_params_fixup = avs_nau8825_be_fixup; + dl->ops = &avs_nau8825_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) + snd_soc_component_set_jack(component, jack, NULL); + return 0; +} + +static int avs_card_remove(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EINVAL; + } + + if (codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK] && + codec_dai->playback_widget->active) + snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN); + + return avs_card_set_jack(card, jack); +} + +static int avs_nau8825_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + card->name = "avs_nau8825"; + card->dev = dev; + card->owner = THIS_MODULE; + card->remove = avs_card_remove; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_nau8825_driver = { + .probe = avs_nau8825_probe, + .driver = { + .name = "avs_nau8825", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_nau8825_driver) + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_nau8825"); diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c new file mode 100644 index 000000000000..afef5a3ca60b --- /dev/null +++ b/sound/soc/intel/avs/boards/rt274.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/rt274.h" + +#define AVS_RT274_FREQ_OUT 24000000 +#define AVS_RT274_BE_FIXUP_RATE 48000 +#define RT274_CODEC_DAI "rt274-aif1" + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; + +static int +avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI); + if (!codec_dai) + return -EINVAL; + + /* Codec needs clock for Jack detection and button press */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, AVS_RT274_FREQ_OUT, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret); + return ret; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + int ratio = 100; + + snd_soc_dai_set_bclk_ratio(codec_dai, ratio); + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK, + AVS_RT274_BE_FIXUP_RATE * ratio, AVS_RT274_FREQ_OUT); + if (ret) { + dev_err(codec_dai->dev, "failed to enable PLL2: %d\n", ret); + return ret; + } + } + + return 0; +} + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_rt274_clock_control, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + {"Headphone Jack", NULL, "HPO Pin"}, + {"MIC", NULL, "Mic Jack"}, + + {"Headphone Jack", NULL, "Platform Clock"}, + {"MIC", NULL, "Platform Clock"}, +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + struct snd_soc_card *card = runtime->card; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins); + if (ret) + return ret; + + snd_soc_component_set_jack(component, jack, NULL); + + /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); + if (ret < 0) { + dev_err(card->dev, "can't set codec pcm format %d\n", ret); + return ret; + } + + card->dapm.idle_bias_off = true; + + return 0; +} + +static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = AVS_RT274_BE_FIXUP_RATE; + channels->min = channels->max = 2; + + /* set SSPN to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt274-aif1"); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->init = avs_rt274_codec_init; + dl->be_hw_params_fixup = avs_rt274_be_fixup; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) + snd_soc_component_set_jack(component, jack, NULL); + return 0; +} + +static int avs_card_remove(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return avs_card_set_jack(card, jack); +} + +static int avs_rt274_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + card->name = "avs_rt274"; + card->dev = dev; + card->owner = THIS_MODULE; + card->remove = avs_card_remove; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_rt274_driver = { + .probe = avs_rt274_probe, + .driver = { + .name = "avs_rt274", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_rt274_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_rt274"); diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c new file mode 100644 index 000000000000..e51d4e181274 --- /dev/null +++ b/sound/soc/intel/avs/boards/rt286.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/rt286.h" + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + /* HP jack connectors - unknown if we have jack detect */ + {"Headphone Jack", NULL, "HPO Pin"}, + {"MIC1", NULL, "Mic Jack"}, + + {"Speaker", NULL, "SPOR"}, + {"Speaker", NULL, "SPOL"}, +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + struct snd_soc_card *card = runtime->card; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack, + pins, num_pins); + if (ret) + return ret; + + snd_soc_component_set_jack(component, jack, NULL); + + return 0; +} + +static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int +avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = substream->private_data; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_rt286_ops = { + .hw_params = avs_rt286_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt286-aif1"); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->init = avs_rt286_codec_init; + dl->be_hw_params_fixup = avs_rt286_be_fixup; + dl->ops = &avs_rt286_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) + snd_soc_component_set_jack(component, jack, NULL); + return 0; +} + +static int avs_card_remove(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return avs_card_set_jack(card, jack); +} + +static int avs_rt286_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + card->name = "avs_rt286"; + card->dev = dev; + card->owner = THIS_MODULE; + card->remove = avs_card_remove; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_rt286_driver = { + .probe = avs_rt286_probe, + .driver = { + .name = "avs_rt286", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_rt286_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_rt286"); diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c new file mode 100644 index 000000000000..b28d36872dcb --- /dev/null +++ b/sound/soc/intel/avs/boards/rt298.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/rt298.h" + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + /* HP jack connectors - unknown if we have jack detect */ + {"Headphone Jack", NULL, "HPO Pin"}, + {"MIC1", NULL, "Mic Jack"}, + + {"Speaker", NULL, "SPOR"}, + {"Speaker", NULL, "SPOL"}, +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + struct snd_soc_card *card = runtime->card; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack, + pins, num_pins); + if (ret) + return ret; + + snd_soc_component_set_jack(component, jack, NULL); + + return 0; +} + +static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int +avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_rt298_ops = { + .hw_params = avs_rt298_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt298-aif1"); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->init = avs_rt298_codec_init; + dl->be_hw_params_fixup = avs_rt298_be_fixup; + dl->ops = &avs_rt298_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) + snd_soc_component_set_jack(component, jack, NULL); + return 0; +} + +static int avs_card_remove(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return avs_card_set_jack(card, jack); +} + +static int avs_rt298_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + card->name = "avs_rt298"; + card->dev = dev; + card->owner = THIS_MODULE; + card->remove = avs_card_remove; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_rt298_driver = { + .probe = avs_rt298_probe, + .driver = { + .name = "avs_rt298", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_rt298_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_rt298"); diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c new file mode 100644 index 000000000000..01f9b9f0c12b --- /dev/null +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/clk.h> +#include <linux/dmi.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/rt5682.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../common/soc-intel-quirks.h" +#include "../../../codecs/rt5682.h" + +#define AVS_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) +#define AVS_RT5682_SSP_CODEC_MASK (GENMASK(2, 0)) +#define AVS_RT5682_MCLK_EN BIT(3) +#define AVS_RT5682_MCLK_24MHZ BIT(4) + +/* Default: MCLK on, MCLK 19.2M, SSP0 */ +static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0); + +static int avs_rt5682_quirk_cb(const struct dmi_system_id *id) +{ + avs_rt5682_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id avs_rt5682_quirk_table[] = { + { + .callback = avs_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), + }, + .driver_data = (void *)(AVS_RT5682_MCLK_EN | + AVS_RT5682_MCLK_24MHZ | + AVS_RT5682_SSP_CODEC(1)), + }, + { + .callback = avs_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), + }, + .driver_data = (void *)(AVS_RT5682_MCLK_EN | + AVS_RT5682_SSP_CODEC(0)), + }, + {} +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + /* HP jack connectors - unknown if we have jack detect */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, +}; + +static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + struct snd_soc_jack *jack; + struct snd_soc_card *card = runtime->card; + int ret; + + jack = snd_soc_card_get_drvdata(card); + + /* Need to enable ASRC function for 24MHz mclk rate */ + if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) && + (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)) { + rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | + RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC); + } + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack); + if (ret) { + dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(card->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return 0; +}; + +static int +avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + int clk_id, clk_freq; + int pll_out, ret; + + if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) { + clk_id = RT5682_PLL1_S_MCLK; + if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ) + clk_freq = 24000000; + else + clk_freq = 19200000; + } else { + clk_id = RT5682_PLL1_S_BCLK1; + clk_freq = params_rate(params) * 50; + } + + pll_out = params_rate(params) * 512; + + ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (ret < 0) + dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret); + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + /* slot_width should equal or large than data length, set them be the same */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params)); + if (ret < 0) { + dev_err(runtime->dev, "set TDM slot err:%d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops avs_rt5682_ops = { + .hw_params = avs_rt5682_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt5682-aif1"); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->init = avs_rt5682_codec_init; + dl->ops = &avs_rt5682_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 2; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) + snd_soc_component_set_jack(component, jack, NULL); + return 0; +} + +static int avs_card_remove(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + return avs_card_set_jack(card, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return avs_card_set_jack(card, jack); +} + +static int avs_rt5682_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + if (pdev->id_entry && pdev->id_entry->driver_data) + avs_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data; + + dmi_check_system(avs_rt5682_quirk_table); + dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk); + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + card->name = "avs_rt5682"; + card->dev = dev; + card->owner = THIS_MODULE; + card->remove = avs_card_remove; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_rt5682_driver = { + .probe = avs_rt5682_probe, + .driver = { + .name = "avs_rt5682", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_rt5682_driver) + +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_rt5682"); diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c new file mode 100644 index 000000000000..9f84c8ab3447 --- /dev/null +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/nau8825.h" + +#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" +#define SKL_SSM_CODEC_DAI "ssm4567-hifi" + +static struct snd_soc_codec_conf card_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF("i2c-INT343B:00"), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF("i2c-INT343B:01"), + .name_prefix = "Right", + }, +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Speaker"), + SOC_DAPM_PIN_SWITCH("Right Speaker"), +}; + +static int +platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EINVAL; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(card->dev, "set sysclk err = %d\n", ret); + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(card->dev, "set sysclk err = %d\n", ret); + } + + return ret; +} + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_SPK("Left Speaker", NULL), + SND_SOC_DAPM_SPK("Right Speaker", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route card_base_routes[] = { + {"Left Speaker", NULL, "Left OUT"}, + {"Right Speaker", NULL, "Right OUT"}, +}; + +static int avs_ssm4567_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + + /* Slot 1 for left */ + ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48); + if (ret < 0) + return ret; + + /* Slot 2 for right */ + ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48); + if (ret < 0) + return ret; + + return 0; +} + +static int +avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; +} + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:00"); + dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi"); + dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:01"); + dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi"); + if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name || + !dl->codecs[1].name || !dl->codecs[1].dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 2; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->init = avs_ssm4567_codec_init; + dl->be_hw_params_fixup = avs_ssm4567_be_fixup; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + dl->ignore_pmdown_time = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_create_dapm_routes(struct device *dev, int ssp_port, + struct snd_soc_dapm_route **routes, int *num_routes) +{ + struct snd_soc_dapm_route *dr; + const int num_base = ARRAY_SIZE(card_base_routes); + const int num_dr = num_base + 4; + int idx; + + dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + memcpy(dr, card_base_routes, num_base * sizeof(*dr)); + + idx = num_base; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right Playback"); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Left Capture Sense"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + idx++; + dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port); + dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Right Capture Sense"); + if (!dr[idx].sink || !dr[idx].source) + return -ENOMEM; + + *routes = dr; + *num_routes = num_dr; + + return 0; +} + +static int avs_ssm4567_probe(struct platform_device *pdev) +{ + struct snd_soc_dapm_route *routes; + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + const char *pname; + int num_routes, ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes); + if (ret) { + dev_err(dev, "Failed to create dapm routes: %d", ret); + return ret; + } + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "avs_ssm4567-adi"; + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = dai_link; + card->num_links = 1; + card->codec_conf = card_codec_conf; + card->num_configs = ARRAY_SIZE(card_codec_conf); + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = routes; + card->num_dapm_routes = num_routes; + card->fully_routed = true; + card->disable_route_checks = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_ssm4567_driver = { + .probe = avs_ssm4567_probe, + .driver = { + .name = "avs_ssm4567", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_ssm4567_driver) + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_ssm4567"); diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f3873b5bea87..4b4c1e1e4808 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -660,7 +660,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW select SND_SOC_RT700_SDW diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index c30a9dca6801..48bf3241b3e6 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -75,7 +75,7 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - rt286_mic_detect(component, &broadwell_headset); + snd_soc_component_set_jack(component, &broadwell_headset, NULL); return 0; } @@ -227,7 +227,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { }, }; -static int broadwell_disable_jack(struct snd_soc_card *card) +static void broadwell_disable_jack(struct snd_soc_card *card) { struct snd_soc_component *component; @@ -235,17 +235,17 @@ static int broadwell_disable_jack(struct snd_soc_card *card) if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "disabling jack detect before going to suspend.\n"); - rt286_mic_detect(component, NULL); + snd_soc_component_set_jack(component, NULL, NULL); break; } } - - return 0; } static int broadwell_suspend(struct snd_soc_card *card) { - return broadwell_disable_jack(card); + broadwell_disable_jack(card); + + return 0; } static int broadwell_resume(struct snd_soc_card *card){ @@ -255,7 +255,7 @@ static int broadwell_resume(struct snd_soc_card *card){ if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "enabling jack detect for resume.\n"); - rt286_mic_detect(component, &broadwell_headset); + snd_soc_component_set_jack(component, &broadwell_headset, NULL); break; } } @@ -315,7 +315,9 @@ static int broadwell_audio_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - return broadwell_disable_jack(card); + broadwell_disable_jack(card); + + return 0; } static struct platform_driver broadwell_audio = { diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index d98376da425a..7c6c95e99ade 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -186,6 +186,17 @@ static const struct snd_soc_dapm_route gemini_map[] = { {"ssp2 Rx", NULL, "Capture"}, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -231,10 +242,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &broxton_headset); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &broxton_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 75995d17597d..4bd93c3ba377 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -176,7 +176,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - rt298_mic_detect(component, &broxton_headset); + snd_soc_component_set_jack(component, &broxton_headset, NULL); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 0eed68a11f7e..ae899866863e 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -126,7 +126,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index eb19bf16afad..a0c8f1d3f8ce 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -81,7 +81,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index a08507783e44..6432b83f616f 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -265,7 +265,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 115c2bcaabd4..7fc03f2efd35 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -61,7 +61,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ed9fa1728722..fb9d9e271845 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1413,7 +1413,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; @@ -1636,7 +1636,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index d467fcaa48ea..2beb686768f2 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -706,7 +706,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { @@ -952,7 +952,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 330c0ace1638..45a6805787f5 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -265,7 +265,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret) { dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index a5160f27adea..64eb73525ee3 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -264,8 +264,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBC_CFC; + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP; ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); if (ret < 0) { diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 45c301ea5e00..96501aed8bee 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -362,7 +362,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -372,7 +372,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BC_FC ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -396,7 +396,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BC_FC); if (ret < 0) { dev_err(rtd->dev, "can't set format to TDM %d\n", ret); return ret; @@ -603,7 +603,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index c80324f34b1b..ca47f6476b07 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -300,7 +300,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c index a99f74a15b5f..20da83d9eece 100644 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -121,6 +121,17 @@ static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = { {"TR Ext Spk", NULL, "TR SPO" }, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) { struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -137,11 +148,13 @@ static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->headset); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index 170164baae7d..cf0f89db3e20 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -78,6 +78,17 @@ static const struct snd_soc_dapm_widget geminilake_widgets[] = { SND_SOC_DAPM_SPK("HDMI3", NULL), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route geminilake_map[] = { /* HP jack connectors - unknown if we have jack detection */ { "Headphone Jack", NULL, "HPOL" }, @@ -173,10 +184,12 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->geminilake_headset); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->geminilake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 5c31ddc0884a..83c7dfbccd9d 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -62,8 +62,8 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, hpcm->pcm = spcm; hpcm->device = spcm->device; dev_dbg(card->dev, - "%s: mapping HDMI converter %d to PCM %d (%p)\n", - __func__, i, hpcm->device, spcm); + "mapping HDMI converter %d to PCM %d (%p)\n", + i, hpcm->device, spcm); } else { hpcm->pcm = NULL; hpcm->device = SNDRV_PCM_INVALID_DEVICE; diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index ceabed85e9da..329457e3e3a2 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -99,6 +99,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_map[] = { { "Headphone Jack", NULL, "HPL" }, { "Headphone Jack", NULL, "HPR" }, @@ -179,10 +190,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset); + ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 703ccff634b0..362579f25835 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -119,6 +119,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_map[] = { /* speaker */ { "Left Spk", NULL, "Left BE_OUT" }, @@ -354,10 +365,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset); + ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 8d37b2676a81..2d4224c5b152 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -206,6 +206,17 @@ static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_5663_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headphone Jack", NULL, "HPOL" }, @@ -271,10 +282,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &ctx->kabylake_headset); + ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 564c70a0fbc8..2c79fca57b19 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -145,6 +145,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_map[] = { /* Headphones */ { "Headphone Jack", NULL, "Platform Clock" }, @@ -228,10 +239,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &ctx->kabylake_headset); + ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index f4b4eeca3e03..81144efb4b44 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -75,7 +75,7 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); int ret = 0; - dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); + dev_dbg(card->dev, "dai link name - %s\n", link->name); link->platforms->name = ctx->platform_name; link->nonatomic = 1; @@ -203,7 +203,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) struct skl_hda_private *ctx; int ret; - dev_dbg(&pdev->dev, "%s: entry\n", __func__); + dev_dbg(&pdev->dev, "entry\n"); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 8e2d03e36079..8dceb0b02581 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -97,6 +97,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route skylake_map[] = { /* HP jack connectors - unknown if we have jack detection */ { "Headphone Jack", NULL, "HPOL" }, @@ -163,9 +174,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset); + ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 501f0bbfc404..62c0d46d0086 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -101,6 +101,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route skylake_map[] = { /* HP jack connectors - unknown if we have jack detection */ {"Headphone Jack", NULL, "HPOL"}, @@ -182,9 +193,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) * 4 buttons here map to the google Reference headset * The use of these buttons can be decided by the user space. */ - ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset); + ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index e9f9520dcea4..4f3d655e2bfa 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -133,7 +133,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - rt286_mic_detect(component, &skylake_headset); + snd_soc_component_set_jack(component, &skylake_headset, NULL); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 6a979c333bc5..a1a14d6d7c23 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -52,6 +52,17 @@ enum { LINK_HDMI = 4, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + /* Default: SSP2 */ static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2); @@ -98,11 +109,13 @@ static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - jack); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index a83f30b687cf..34cf849a8344 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -135,6 +135,17 @@ static const struct snd_soc_dapm_route max98360a_map[] = { {"DMic", NULL, "SoC DMIC"}, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_jack headset; static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) @@ -156,11 +167,13 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &headset); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 97dcd204a246..f49700eb721b 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -81,6 +81,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -93,11 +104,13 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sof_headset); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sof_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 6815204e58d5..d4c67d5340a9 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -419,7 +419,7 @@ static int sof_audio_probe(struct platform_device *pdev) static int sof_pcm512x_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct snd_soc_component *component = NULL; + struct snd_soc_component *component; for_each_card_components(card, component) { if (!strcmp(component->name, pcm512x_component[0].name)) { diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index 2ab568c1d40b..b9643ca2e2f2 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -463,26 +463,26 @@ EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); * 2-amp Configuration for RT1019 */ -static const struct snd_soc_dapm_route rt1019_dapm_routes[] = { +static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "Speaker" }, { "Right Spk", NULL, "Speaker" }, }; -static struct snd_soc_dai_link_component rt1019_components[] = { +static struct snd_soc_dai_link_component rt1019p_components[] = { { - .name = RT1019_DEV0_NAME, - .dai_name = RT1019_CODEC_DAI, + .name = RT1019P_DEV0_NAME, + .dai_name = RT1019P_CODEC_DAI, }, }; -static int rt1019_init(struct snd_soc_pcm_runtime *rtd) +static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int ret; - ret = snd_soc_dapm_add_routes(&card->dapm, rt1019_dapm_routes, - ARRAY_SIZE(rt1019_dapm_routes)); + ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes, + ARRAY_SIZE(rt1019p_dapm_routes)); if (ret) { dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); return ret; @@ -490,13 +490,13 @@ static int rt1019_init(struct snd_soc_pcm_runtime *rtd) return ret; } -void sof_rt1019_dai_link(struct snd_soc_dai_link *link) +void sof_rt1019p_dai_link(struct snd_soc_dai_link *link) { - link->codecs = rt1019_components; - link->num_codecs = ARRAY_SIZE(rt1019_components); - link->init = rt1019_init; + link->codecs = rt1019p_components; + link->num_codecs = ARRAY_SIZE(rt1019p_components); + link->init = rt1019p_init; } -EXPORT_SYMBOL_NS(sof_rt1019_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index ec3eea633e04..778443421090 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -39,9 +39,9 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card); #define RT1308_DEV0_NAME "i2c-10EC1308:00" void sof_rt1308_dai_link(struct snd_soc_dai_link *link); -#define RT1019_CODEC_DAI "HiFi" -#define RT1019_DEV0_NAME "RTL1019:00" +#define RT1019P_CODEC_DAI "HiFi" +#define RT1019P_DEV0_NAME "RTL1019:00" -void sof_rt1019_dai_link(struct snd_soc_dai_link *link); +void sof_rt1019p_dai_link(struct snd_soc_dai_link *link); #endif /* __SOF_REALTEK_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 5d67a2c87a1d..a24fb71d5ff3 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -248,6 +248,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -295,11 +306,13 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sof_headset); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sof_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -735,7 +748,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) { sof_rt1015p_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_RT1019_SPEAKER_AMP_PRESENT) { - sof_rt1019_dai_link(&links[id]); + sof_rt1019p_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { links[id].codecs = max_98373_components; diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ad826ad82d51..0c47d76a79e2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -315,6 +315,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { RT711_JD2 | SOF_SDW_FOUR_SPK), }, + /* MeteorLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), + }, + .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI), + }, {} }; @@ -1127,10 +1135,14 @@ static int sof_card_dai_links_create(struct device *dev, for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) codec_info_list[i].amp_num = 0; - if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) - hdmi_num = SOF_TGL_HDMI_COUNT; - else - hdmi_num = SOF_PRE_TGL_HDMI_COUNT; + if (mach_params->codec_mask & IDISP_CODEC_MASK) { + ctx->idisp_codec = true; + + if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) + hdmi_num = SOF_TGL_HDMI_COUNT; + else + hdmi_num = SOF_PRE_TGL_HDMI_COUNT; + } ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); /* @@ -1150,9 +1162,6 @@ static int sof_card_dai_links_create(struct device *dev, return ret; } - if (mach_params->codec_mask & IDISP_CODEC_MASK) - ctx->idisp_codec = true; - /* enable dmic01 & dmic16k */ dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0; comp_num += dmic_num; @@ -1375,7 +1384,9 @@ HDMI: static int sof_sdw_card_late_probe(struct snd_soc_card *card) { - int i, ret; + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + int ret = 0; + int i; for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { if (!codec_info_list[i].late_probe) @@ -1386,7 +1397,10 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card) return ret; } - return sof_sdw_hdmi_card_late_probe(card); + if (ctx->idisp_codec) + ret = sof_sdw_hdmi_card_late_probe(card); + + return ret; } /* SoC card */ @@ -1433,7 +1447,7 @@ static int mc_probe(struct platform_device *pdev) int amp_num = 0, i; int ret; - dev_dbg(&pdev->dev, "Entry %s\n", __func__); + dev_dbg(&pdev->dev, "Entry\n"); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index fef0b2d1de68..8ca8f872ec80 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ + soc-acpi-intel-mtl-match.o \ soc-acpi-intel-hda-match.o \ soc-acpi-intel-sdw-mockup-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c new file mode 100644 index 000000000000..74d3b82f8d35 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-mtl-match.c - tables and support for MTL ACPI enumeration. + * + * Copyright (c) 2022, Intel Corporation. + * + */ + +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include "soc-acpi-intel-sdw-mockup-match.h" + +struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines); + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_link_adr mtl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { + /* mockup tests need to be first */ + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = GENMASK(2, 0), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg", + }, + { + .link_mask = BIT(0), + .links = mtl_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines); diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index a6fb74ba1c42..d10881fedc8b 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -497,11 +497,11 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) int ret; switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: kmb_i2s->clock_provider = false; ret = 0; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0); ret = clk_prepare_enable(kmb_i2s->clk_i2s); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 9bdf020a2b64..e06eac592da1 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2950,9 +2950,6 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, block_size = ret; off += array->size; - array = (struct snd_soc_tplg_vendor_array *) - (tplg_w->priv.data + off); - data = (tplg_w->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { @@ -3599,9 +3596,6 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, block_size = ret; off += array->size; - array = (struct snd_soc_tplg_vendor_array *) - (manifest->priv.data + off); - data = (manifest->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 7ad5d9a924d8..446c5e061564 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -206,18 +206,18 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER; format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: conf |= JZ_AIC_CONF_SYNC_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_BP_FC: conf |= JZ_AIC_CONF_BIT_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index 496f32bcfb5e..d2f6213a6bfc 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -217,7 +217,8 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) if (!codec_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } for_each_card_prelinks(card, i, dai_link) { if (dai_link->codecs->name) @@ -230,6 +231,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + of_node_put(codec_node); +put_platform_node: + of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 31494930433f..dcaeeeb8aac7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -286,10 +286,8 @@ static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe, static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe, struct clk *m_ck, struct clk *b_ck) { - if (m_ck) - clk_disable_unprepare(m_ck); - if (b_ck) - clk_disable_unprepare(b_ck); + clk_disable_unprepare(m_ck); + clk_disable_unprepare(b_ck); } static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream, diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 70bf312e855f..8794720cea3a 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -256,14 +256,16 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_node; } mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_node; } mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node = mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node; @@ -276,13 +278,15 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_node; } card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); +put_node: of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index d1c94acb4516..e05f2b0231fe 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -280,7 +280,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node = mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node; @@ -293,7 +294,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s codec_capture_dai name fail %d\n", __func__, ret); - return ret; + goto put_platform_node; } mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].dai_name = codec_capture_dai; @@ -315,12 +316,14 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codecs->of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); +put_platform_node: of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c new file mode 100644 index 000000000000..0275f66ddc18 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-afe-clk.c -- Mediatek 8186 afe clock ctrl +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/clk.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> + +#include "mt8186-afe-common.h" +#include "mt8186-afe-clk.h" +#include "mt8186-audsys-clk.h" + +static DEFINE_MUTEX(mutex_request_dram); + +static const char *aud_clks[CLK_NUM] = { + [CLK_AFE] = "aud_afe_clk", + [CLK_DAC] = "aud_dac_clk", + [CLK_DAC_PREDIS] = "aud_dac_predis_clk", + [CLK_ADC] = "aud_adc_clk", + [CLK_TML] = "aud_tml_clk", + [CLK_APLL22M] = "aud_apll22m_clk", + [CLK_APLL24M] = "aud_apll24m_clk", + [CLK_APLL1_TUNER] = "aud_apll_tuner_clk", + [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk", + [CLK_TDM] = "aud_tdm_clk", + [CLK_NLE] = "aud_nle_clk", + [CLK_DAC_HIRES] = "aud_dac_hires_clk", + [CLK_ADC_HIRES] = "aud_adc_hires_clk", + [CLK_I2S1_BCLK] = "aud_i2s1_bclk", + [CLK_I2S2_BCLK] = "aud_i2s2_bclk", + [CLK_I2S3_BCLK] = "aud_i2s3_bclk", + [CLK_I2S4_BCLK] = "aud_i2s4_bclk", + [CLK_CONNSYS_I2S_ASRC] = "aud_connsys_i2s_asrc", + [CLK_GENERAL1_ASRC] = "aud_general1_asrc", + [CLK_GENERAL2_ASRC] = "aud_general2_asrc", + [CLK_ADC_HIRES_TML] = "aud_adc_hires_tml", + [CLK_ADDA6_ADC] = "aud_adda6_adc", + [CLK_ADDA6_ADC_HIRES] = "aud_adda6_adc_hires", + [CLK_3RD_DAC] = "aud_3rd_dac", + [CLK_3RD_DAC_PREDIS] = "aud_3rd_dac_predis", + [CLK_3RD_DAC_TML] = "aud_3rd_dac_tml", + [CLK_3RD_DAC_HIRES] = "aud_3rd_dac_hires", + [CLK_ETDM_IN1_BCLK] = "aud_etdm_in1_bclk", + [CLK_ETDM_OUT1_BCLK] = "aud_etdm_out1_bclk", + [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk", + [CLK_INFRA_AUDIO_26M] = "mtkaif_26m_clk", + [CLK_MUX_AUDIO] = "top_mux_audio", + [CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int", + [CLK_TOP_MAINPLL_D2_D4] = "top_mainpll_d2_d4", + [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1", + [CLK_TOP_APLL1_CK] = "top_apll1_ck", + [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2", + [CLK_TOP_APLL2_CK] = "top_apll2_ck", + [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1", + [CLK_TOP_APLL1_D8] = "top_apll1_d8", + [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2", + [CLK_TOP_APLL2_D8] = "top_apll2_d8", + [CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h", + [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel", + [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel", + [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel", + [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel", + [CLK_TOP_TDM_M_SEL] = "top_tdm_m_sel", + [CLK_TOP_APLL12_DIV0] = "top_apll12_div0", + [CLK_TOP_APLL12_DIV1] = "top_apll12_div1", + [CLK_TOP_APLL12_DIV2] = "top_apll12_div2", + [CLK_TOP_APLL12_DIV4] = "top_apll12_div4", + [CLK_TOP_APLL12_DIV_TDM] = "top_apll12_div_tdm", + [CLK_CLK26M] = "top_clk26m_clk", +}; + +int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, + int clk_id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS], + afe_priv->clk[clk_id]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], + aud_clks[clk_id], ret); + return ret; + } + + return 0; +} + +static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_TOP_APLL1_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_TOP_APLL1_CK], ret); + return ret; + } + + /* 180.6336 / 8 = 22.5792MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_TOP_APLL1_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_TOP_APLL1_D8], ret); + return ret; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + } + + return 0; +} + +static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_TOP_APLL2_CK], ret); + return ret; + } + + /* 196.608 / 8 = 24.576MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_TOP_APLL2_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_TOP_APLL2_D8], ret); + return ret; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + } + + return 0; +} + +int mt8186_afe_enable_cgs(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + int i; + + for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) { + ret = clk_prepare_enable(afe_priv->clk[i]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[i], ret); + return ret; + } + } + + return 0; +} + +void mt8186_afe_disable_cgs(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int i; + + for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) + clk_disable_unprepare(afe_priv->clk[i]); +} + +int mt8186_afe_enable_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret); + goto clk_infra_sys_audio_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_AUDIO_26M], ret); + goto clk_infra_audio_26m_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], ret); + goto clk_mux_audio_err; + } + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], + aud_clks[CLK_CLK26M], ret); + goto clk_mux_audio_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto clk_mux_audio_intbus_err; + } + ret = mt8186_set_audio_int_bus_parent(afe, + CLK_TOP_MAINPLL_D2_D4); + if (ret) + goto clk_mux_audio_intbus_parent_err; + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUDIO_H], + aud_clks[CLK_TOP_APLL2_CK], ret); + goto clk_mux_audio_h_parent_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_AFE], ret); + goto clk_afe_err; + } + + return 0; + +clk_afe_err: + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); +clk_mux_audio_h_parent_err: +clk_mux_audio_intbus_parent_err: + mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); +clk_mux_audio_intbus_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); +clk_mux_audio_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); +clk_infra_sys_audio_err: + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +clk_infra_audio_26m_err: + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + + return ret; +} + +void mt8186_afe_disable_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); + mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +} + +int mt8186_afe_suspend_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* set audio int bus to 26M */ + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto clk_mux_audio_intbus_err; + } + ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); + if (ret) + goto clk_mux_audio_intbus_parent_err; + + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + + return 0; + +clk_mux_audio_intbus_parent_err: + mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4); +clk_mux_audio_intbus_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + return ret; +} + +int mt8186_afe_resume_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* set audio int bus to normal working clock */ + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto clk_mux_audio_intbus_err; + } + ret = mt8186_set_audio_int_bus_parent(afe, + CLK_TOP_MAINPLL_D2_D4); + if (ret) + goto clk_mux_audio_intbus_parent_err; + + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + + return 0; + +clk_mux_audio_intbus_parent_err: + mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); +clk_mux_audio_intbus_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + return ret; +} + +int mt8186_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll1_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL22M], ret); + goto err_clk_apll22m; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1_TUNER], ret); + goto err_clk_apll1_tuner; + } + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0xfff7, 0x832); + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, BIT(AFE_22M_ON_SFT)); + + return 0; + +err_clk_apll1_tuner: + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); +err_clk_apll22m: + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + return ret; +} + +void mt8186_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, 0); + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + apll1_mux_setting(afe, false); +} + +int mt8186_apll2_enable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll2_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL24M], ret); + goto err_clk_apll24m; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2_TUNER], ret); + goto err_clk_apll2_tuner; + } + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0xfff7, 0x634); + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, BIT(AFE_24M_ON_SFT)); + + return 0; + +err_clk_apll2_tuner: + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); +err_clk_apll24m: + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + return ret; +} + +void mt8186_apll2_disable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, 0); + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + apll2_mux_setting(afe, false); +} + +int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll) +{ + return (apll == MT8186_APLL1) ? 180633600 : 196608000; +} + +int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8186_APLL2 : MT8186_APLL1; +} + +int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8186_APLL1; + + return MT8186_APLL2; +} + +/* mck */ +struct mt8186_mck_div { + u32 m_sel_id; + u32 div_clk_id; +}; + +static const struct mt8186_mck_div mck_div[MT8186_MCK_NUM] = { + [MT8186_I2S0_MCK] = { + .m_sel_id = CLK_TOP_I2S0_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV0, + }, + [MT8186_I2S1_MCK] = { + .m_sel_id = CLK_TOP_I2S1_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV1, + }, + [MT8186_I2S2_MCK] = { + .m_sel_id = CLK_TOP_I2S2_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV2, + }, + [MT8186_I2S4_MCK] = { + .m_sel_id = CLK_TOP_I2S4_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV4, + }, + [MT8186_TDM_MCK] = { + .m_sel_id = CLK_TOP_TDM_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV_TDM, + }, +}; + +int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int apll = mt8186_get_apll_by_rate(afe, rate); + int apll_clk_id = apll == MT8186_APLL1 ? + CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + int ret; + + /* select apll */ + if (m_sel_id >= 0) { + ret = clk_prepare_enable(afe_priv->clk[m_sel_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[m_sel_id], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[m_sel_id], + afe_priv->clk[apll_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[m_sel_id], + aud_clks[apll_clk_id], ret); + return ret; + } + } + + /* enable div, set rate */ + ret = clk_prepare_enable(afe_priv->clk[div_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[div_clk_id], ret); + return ret; + } + ret = clk_set_rate(afe_priv->clk[div_clk_id], rate); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n", + __func__, aud_clks[div_clk_id], rate, ret); + return ret; + } + + return 0; +} + +void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + + clk_disable_unprepare(afe_priv->clk[div_clk_id]); + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +} + +int mt8186_init_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct device_node *of_node = afe->dev->of_node; + int i = 0; + + mt8186_audsys_clk_register(afe); + + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk), + GFP_KERNEL); + if (!afe_priv->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clk[i])) { + dev_err(afe->dev, "%s devm_clk_get %s fail, ret %ld\n", + __func__, + aud_clks[i], PTR_ERR(afe_priv->clk[i])); + afe_priv->clk[i] = NULL; + } + } + + afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,apmixedsys"); + if (IS_ERR(afe_priv->apmixedsys)) { + dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n", + __func__, PTR_ERR(afe_priv->apmixedsys)); + return PTR_ERR(afe_priv->apmixedsys); + } + + afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,topckgen"); + if (IS_ERR(afe_priv->topckgen)) { + dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n", + __func__, PTR_ERR(afe_priv->topckgen)); + return PTR_ERR(afe_priv->topckgen); + } + + afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,infracfg"); + if (IS_ERR(afe_priv->infracfg)) { + dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n", + __func__, PTR_ERR(afe_priv->infracfg)); + return PTR_ERR(afe_priv->infracfg); + } + + return 0; +} + +void mt8186_deinit_clock(struct mtk_base_afe *afe) +{ + mt8186_audsys_clk_unregister(afe); +} diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h new file mode 100644 index 000000000000..c539557d7c78 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-afe-clk.h -- Mediatek 8186 afe clock ctrl definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT8186_AFE_CLOCK_CTRL_H_ +#define _MT8186_AFE_CLOCK_CTRL_H_ + +#define PERI_BUS_DCM_CTRL 0x74 + +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" +enum { + MT8186_APLL1 = 0, + MT8186_APLL2, +}; + +enum { + CLK_AFE = 0, + CLK_DAC, + CLK_DAC_PREDIS, + CLK_ADC, + CLK_TML, + CLK_APLL22M, + CLK_APLL24M, + CLK_APLL1_TUNER, + CLK_APLL2_TUNER, + CLK_TDM, + CLK_NLE, + CLK_DAC_HIRES, + CLK_ADC_HIRES, + CLK_I2S1_BCLK, + CLK_I2S2_BCLK, + CLK_I2S3_BCLK, + CLK_I2S4_BCLK, + CLK_CONNSYS_I2S_ASRC, + CLK_GENERAL1_ASRC, + CLK_GENERAL2_ASRC, + CLK_ADC_HIRES_TML, + CLK_ADDA6_ADC, + CLK_ADDA6_ADC_HIRES, + CLK_3RD_DAC, + CLK_3RD_DAC_PREDIS, + CLK_3RD_DAC_TML, + CLK_3RD_DAC_HIRES, + CLK_ETDM_IN1_BCLK, + CLK_ETDM_OUT1_BCLK, + CLK_INFRA_SYS_AUDIO, + CLK_INFRA_AUDIO_26M, + CLK_MUX_AUDIO, + CLK_MUX_AUDIOINTBUS, + CLK_TOP_MAINPLL_D2_D4, + /* apll related mux */ + CLK_TOP_MUX_AUD_1, + CLK_TOP_APLL1_CK, + CLK_TOP_MUX_AUD_2, + CLK_TOP_APLL2_CK, + CLK_TOP_MUX_AUD_ENG1, + CLK_TOP_APLL1_D8, + CLK_TOP_MUX_AUD_ENG2, + CLK_TOP_APLL2_D8, + CLK_TOP_MUX_AUDIO_H, + CLK_TOP_I2S0_M_SEL, + CLK_TOP_I2S1_M_SEL, + CLK_TOP_I2S2_M_SEL, + CLK_TOP_I2S4_M_SEL, + CLK_TOP_TDM_M_SEL, + CLK_TOP_APLL12_DIV0, + CLK_TOP_APLL12_DIV1, + CLK_TOP_APLL12_DIV2, + CLK_TOP_APLL12_DIV4, + CLK_TOP_APLL12_DIV_TDM, + CLK_CLK26M, + CLK_NUM +}; + +struct mtk_base_afe; +int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id); +int mt8186_init_clock(struct mtk_base_afe *afe); +void mt8186_deinit_clock(struct mtk_base_afe *afe); +int mt8186_afe_enable_cgs(struct mtk_base_afe *afe); +void mt8186_afe_disable_cgs(struct mtk_base_afe *afe); +int mt8186_afe_enable_clock(struct mtk_base_afe *afe); +void mt8186_afe_disable_clock(struct mtk_base_afe *afe); +int mt8186_afe_suspend_clock(struct mtk_base_afe *afe); +int mt8186_afe_resume_clock(struct mtk_base_afe *afe); + +int mt8186_apll1_enable(struct mtk_base_afe *afe); +void mt8186_apll1_disable(struct mtk_base_afe *afe); + +int mt8186_apll2_enable(struct mtk_base_afe *afe); +void mt8186_apll2_disable(struct mtk_base_afe *afe); + +int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll); +int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name); + +/* these will be replaced by using CCF */ +int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate); +void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id); + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c new file mode 100644 index 000000000000..274c0c8ec2f2 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-afe-gpio.c -- Mediatek 8186 afe gpio ctrl +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/gpio.h> +#include <linux/pinctrl/consumer.h> + +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" + +struct pinctrl *aud_pinctrl; + +enum mt8186_afe_gpio { + MT8186_AFE_GPIO_CLK_MOSI_OFF, + MT8186_AFE_GPIO_CLK_MOSI_ON, + MT8186_AFE_GPIO_CLK_MISO_OFF, + MT8186_AFE_GPIO_CLK_MISO_ON, + MT8186_AFE_GPIO_DAT_MISO_OFF, + MT8186_AFE_GPIO_DAT_MISO_ON, + MT8186_AFE_GPIO_DAT_MOSI_OFF, + MT8186_AFE_GPIO_DAT_MOSI_ON, + MT8186_AFE_GPIO_I2S0_OFF, + MT8186_AFE_GPIO_I2S0_ON, + MT8186_AFE_GPIO_I2S1_OFF, + MT8186_AFE_GPIO_I2S1_ON, + MT8186_AFE_GPIO_I2S2_OFF, + MT8186_AFE_GPIO_I2S2_ON, + MT8186_AFE_GPIO_I2S3_OFF, + MT8186_AFE_GPIO_I2S3_ON, + MT8186_AFE_GPIO_TDM_OFF, + MT8186_AFE_GPIO_TDM_ON, + MT8186_AFE_GPIO_PCM_OFF, + MT8186_AFE_GPIO_PCM_ON, + MT8186_AFE_GPIO_GPIO_NUM +}; + +struct audio_gpio_attr { + const char *name; + bool gpio_prepare; + struct pinctrl_state *gpioctrl; +}; + +static struct audio_gpio_attr aud_gpios[MT8186_AFE_GPIO_GPIO_NUM] = { + [MT8186_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL}, + [MT8186_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL}, + [MT8186_AFE_GPIO_CLK_MISO_OFF] = {"aud_clk_miso_off", false, NULL}, + [MT8186_AFE_GPIO_CLK_MISO_ON] = {"aud_clk_miso_on", false, NULL}, + [MT8186_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL}, + [MT8186_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL}, + [MT8186_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL}, + [MT8186_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL}, + [MT8186_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL}, + [MT8186_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL}, + [MT8186_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL}, + [MT8186_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL}, + [MT8186_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL}, + [MT8186_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL}, + [MT8186_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL}, + [MT8186_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL}, + [MT8186_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL}, + [MT8186_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL}, + [MT8186_AFE_GPIO_PCM_OFF] = {"aud_gpio_pcm_off", false, NULL}, + [MT8186_AFE_GPIO_PCM_ON] = {"aud_gpio_pcm_on", false, NULL}, +}; + +static DEFINE_MUTEX(gpio_request_mutex); + +int mt8186_afe_gpio_init(struct device *dev) +{ + int i, j, ret; + + aud_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(aud_pinctrl)) { + ret = PTR_ERR(aud_pinctrl); + dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n", + __func__, ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) { + aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl, + aud_gpios[i].name); + if (IS_ERR(aud_gpios[i].gpioctrl)) { + ret = PTR_ERR(aud_gpios[i].gpioctrl); + dev_info(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n", + __func__, aud_gpios[i].name, ret); + } else { + aud_gpios[i].gpio_prepare = true; + } + } + + /* gpio status init */ + for (i = MT8186_DAI_ADDA; i <= MT8186_DAI_TDM_IN; i++) { + for (j = 0; j <= 1; j++) + mt8186_afe_gpio_request(dev, false, i, j); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt8186_afe_gpio_init); + +static int mt8186_afe_gpio_select(struct device *dev, + enum mt8186_afe_gpio type) +{ + int ret = 0; + + if (type < 0 || type >= MT8186_AFE_GPIO_GPIO_NUM) { + dev_err(dev, "%s(), error, invalid gpio type %d\n", + __func__, type); + return -EINVAL; + } + + if (!aud_gpios[type].gpio_prepare) { + dev_err(dev, "%s(), error, gpio type %d not prepared\n", + __func__, type); + return -EIO; + } + + ret = pinctrl_select_state(aud_pinctrl, + aud_gpios[type].gpioctrl); + if (ret) { + dev_err(dev, "%s(), error, can not set gpio type %d\n", + __func__, type); + return ret; + } + + return 0; +} + +static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable) +{ + int ret; + + if (enable) { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_ON); + if (ret) { + dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON); + if (ret) { + dev_err(dev, "%s(), MOSI DAT ON select fail!\n", __func__); + return ret; + } + } else { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_OFF); + if (ret) { + dev_err(dev, "%s(), MOSI DAT OFF select fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF); + if (ret) { + dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__); + return ret; + } + } + + return 0; +} + +static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable) +{ + int ret; + + if (enable) { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_ON); + if (ret) { + dev_err(dev, "%s(), MISO CLK ON slect fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON); + if (ret) { + dev_err(dev, "%s(), MISO DAT ON slect fail!\n", __func__); + return ret; + } + } else { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_OFF); + if (ret) { + dev_err(dev, "%s(), MISO DAT OFF slect fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF); + if (ret) { + dev_err(dev, "%s(), MISO CLK OFF slect fail!\n", __func__); + return ret; + } + } + + return 0; +} + +int mt8186_afe_gpio_request(struct device *dev, bool enable, + int dai, int uplink) +{ + enum mt8186_afe_gpio sel; + int ret = -EINVAL; + + mutex_lock(&gpio_request_mutex); + + switch (dai) { + case MT8186_DAI_ADDA: + if (uplink) + ret = mt8186_afe_gpio_adda_ul(dev, enable); + else + ret = mt8186_afe_gpio_adda_dl(dev, enable); + goto unlock; + case MT8186_DAI_I2S_0: + sel = enable ? MT8186_AFE_GPIO_I2S0_ON : MT8186_AFE_GPIO_I2S0_OFF; + break; + case MT8186_DAI_I2S_1: + sel = enable ? MT8186_AFE_GPIO_I2S1_ON : MT8186_AFE_GPIO_I2S1_OFF; + break; + case MT8186_DAI_I2S_2: + sel = enable ? MT8186_AFE_GPIO_I2S2_ON : MT8186_AFE_GPIO_I2S2_OFF; + break; + case MT8186_DAI_I2S_3: + sel = enable ? MT8186_AFE_GPIO_I2S3_ON : MT8186_AFE_GPIO_I2S3_OFF; + break; + case MT8186_DAI_TDM_IN: + sel = enable ? MT8186_AFE_GPIO_TDM_ON : MT8186_AFE_GPIO_TDM_OFF; + break; + case MT8186_DAI_PCM: + sel = enable ? MT8186_AFE_GPIO_PCM_ON : MT8186_AFE_GPIO_PCM_OFF; + break; + default: + dev_err(dev, "%s(), invalid dai %d\n", __func__, dai); + goto unlock; + } + + ret = mt8186_afe_gpio_select(dev, sel); + +unlock: + mutex_unlock(&gpio_request_mutex); + + return ret; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h new file mode 100644 index 000000000000..1ddc27838eb1 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt6833-afe-gpio.h -- Mediatek 6833 afe gpio ctrl definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT8186_AFE_GPIO_H_ +#define _MT8186_AFE_GPIO_H_ + +struct mtk_base_afe; + +int mt8186_afe_gpio_init(struct device *dev); + +int mt8186_afe_gpio_request(struct device *dev, bool enable, + int dai, int uplink); + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c new file mode 100644 index 000000000000..578969ca91c8 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-audsys-clk.h -- Mediatek 8186 audsys clock control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include "mt8186-afe-common.h" +#include "mt8186-audsys-clk.h" +#include "mt8186-audsys-clkid.h" +#include "mt8186-reg.h" + +struct afe_gate { + int id; + const char *name; + const char *parent_name; + int reg; + u8 bit; + const struct clk_ops *ops; + unsigned long flags; + u8 cg_flags; +}; + +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .reg = _reg, \ + .bit = _bit, \ + .flags = _flags, \ + .cg_flags = _cgflags, \ + } + +#define GATE_AFE(_id, _name, _parent, _reg, _bit) \ + GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \ + CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE) + +#define GATE_AUD0(_id, _name, _parent, _bit) \ + GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit) + +#define GATE_AUD1(_id, _name, _parent, _bit) \ + GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit) + +#define GATE_AUD2(_id, _name, _parent, _bit) \ + GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit) + +static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = { + /* AUD0 */ + GATE_AUD0(CLK_AUD_AFE, "aud_afe_clk", "top_audio", 2), + GATE_AUD0(CLK_AUD_22M, "aud_apll22m_clk", "top_aud_engen1", 8), + GATE_AUD0(CLK_AUD_24M, "aud_apll24m_clk", "top_aud_engen2", 9), + GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner_clk", "top_aud_engen2", 18), + GATE_AUD0(CLK_AUD_APLL_TUNER, "aud_apll_tuner_clk", "top_aud_engen1", 19), + GATE_AUD0(CLK_AUD_TDM, "aud_tdm_clk", "top_aud_1", 20), + GATE_AUD0(CLK_AUD_ADC, "aud_adc_clk", "top_audio", 24), + GATE_AUD0(CLK_AUD_DAC, "aud_dac_clk", "top_audio", 25), + GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis_clk", "top_audio", 26), + GATE_AUD0(CLK_AUD_TML, "aud_tml_clk", "top_audio", 27), + GATE_AUD0(CLK_AUD_NLE, "aud_nle_clk", "top_audio", 28), + + /* AUD1 */ + GATE_AUD1(CLK_AUD_I2S1_BCLK, "aud_i2s1_bclk", "top_audio", 4), + GATE_AUD1(CLK_AUD_I2S2_BCLK, "aud_i2s2_bclk", "top_audio", 5), + GATE_AUD1(CLK_AUD_I2S3_BCLK, "aud_i2s3_bclk", "top_audio", 6), + GATE_AUD1(CLK_AUD_I2S4_BCLK, "aud_i2s4_bclk", "top_audio", 7), + GATE_AUD1(CLK_AUD_CONNSYS_I2S_ASRC, "aud_connsys_i2s_asrc", "top_audio", 12), + GATE_AUD1(CLK_AUD_GENERAL1_ASRC, "aud_general1_asrc", "top_audio", 13), + GATE_AUD1(CLK_AUD_GENERAL2_ASRC, "aud_general2_asrc", "top_audio", 14), + GATE_AUD1(CLK_AUD_DAC_HIRES, "aud_dac_hires_clk", "top_audio_h", 15), + GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires_clk", "top_audio_h", 16), + GATE_AUD1(CLK_AUD_ADC_HIRES_TML, "aud_adc_hires_tml", "top_audio_h", 17), + GATE_AUD1(CLK_AUD_ADDA6_ADC, "aud_adda6_adc", "top_audio", 20), + GATE_AUD1(CLK_AUD_ADDA6_ADC_HIRES, "aud_adda6_adc_hires", "top_audio_h", 21), + GATE_AUD1(CLK_AUD_3RD_DAC, "aud_3rd_dac", "top_audio", 28), + GATE_AUD1(CLK_AUD_3RD_DAC_PREDIS, "aud_3rd_dac_predis", "top_audio", 29), + GATE_AUD1(CLK_AUD_3RD_DAC_TML, "aud_3rd_dac_tml", "top_audio", 30), + GATE_AUD1(CLK_AUD_3RD_DAC_HIRES, "aud_3rd_dac_hires", "top_audio_h", 31), + + /* AUD2 */ + GATE_AUD2(CLK_AUD_ETDM_IN1_BCLK, "aud_etdm_in1_bclk", "top_audio", 23), + GATE_AUD2(CLK_AUD_ETDM_OUT1_BCLK, "aud_etdm_out1_bclk", "top_audio", 24), +}; + +int mt8186_audsys_clk_register(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct clk *clk; + struct clk_lookup *cl; + int i; + + afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK, + sizeof(*afe_priv->lookup), + GFP_KERNEL); + + if (!afe_priv->lookup) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) { + const struct afe_gate *gate = &aud_clks[i]; + + clk = clk_register_gate(afe->dev, gate->name, gate->parent_name, + gate->flags, afe->base_addr + gate->reg, + gate->bit, gate->cg_flags, NULL); + + if (IS_ERR(clk)) { + dev_err(afe->dev, "Failed to register clk %s: %ld\n", + gate->name, PTR_ERR(clk)); + continue; + } + + /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */ + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->clk = clk; + cl->con_id = gate->name; + cl->dev_id = dev_name(afe->dev); + clkdev_add(cl); + + afe_priv->lookup[i] = cl; + } + + return 0; +} + +void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct clk *clk; + struct clk_lookup *cl; + int i; + + if (!afe_priv) + return; + + for (i = 0; i < CLK_AUD_NR_CLK; i++) { + cl = afe_priv->lookup[i]; + if (!cl) + continue; + + clk = cl->clk; + clk_unregister_gate(clk); + + clkdev_drop(cl); + } +} diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h new file mode 100644 index 000000000000..b8d6a06e11e8 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-audsys-clk.h -- Mediatek 8186 audsys clock definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Trevor Wu <trevor.wu@mediatek.com> + */ + +#ifndef _MT8186_AUDSYS_CLK_H_ +#define _MT8186_AUDSYS_CLK_H_ + +int mt8186_audsys_clk_register(struct mtk_base_afe *afe); +void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe); + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h new file mode 100644 index 000000000000..3ce5937c1823 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-audsys-clkid.h -- Mediatek 8186 audsys clock id definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT8186_AUDSYS_CLKID_H_ +#define _MT8186_AUDSYS_CLKID_H_ + +enum{ + CLK_AUD_AFE, + CLK_AUD_22M, + CLK_AUD_24M, + CLK_AUD_APLL2_TUNER, + CLK_AUD_APLL_TUNER, + CLK_AUD_TDM, + CLK_AUD_ADC, + CLK_AUD_DAC, + CLK_AUD_DAC_PREDIS, + CLK_AUD_TML, + CLK_AUD_NLE, + CLK_AUD_I2S1_BCLK, + CLK_AUD_I2S2_BCLK, + CLK_AUD_I2S3_BCLK, + CLK_AUD_I2S4_BCLK, + CLK_AUD_CONNSYS_I2S_ASRC, + CLK_AUD_GENERAL1_ASRC, + CLK_AUD_GENERAL2_ASRC, + CLK_AUD_DAC_HIRES, + CLK_AUD_ADC_HIRES, + CLK_AUD_ADC_HIRES_TML, + CLK_AUD_ADDA6_ADC, + CLK_AUD_ADDA6_ADC_HIRES, + CLK_AUD_3RD_DAC, + CLK_AUD_3RD_DAC_PREDIS, + CLK_AUD_3RD_DAC_TML, + CLK_AUD_3RD_DAC_HIRES, + CLK_AUD_ETDM_IN1_BCLK, + CLK_AUD_ETDM_OUT1_BCLK, + CLK_AUD_NR_CLK, +}; + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c new file mode 100644 index 000000000000..db71b032770d --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c @@ -0,0 +1,873 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI ADDA Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/regmap.h> +#include <linux/delay.h> +#include "mt8186-afe-clk.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +enum { + UL_IIR_SW = 0, + UL_IIR_5HZ, + UL_IIR_10HZ, + UL_IIR_25HZ, + UL_IIR_50HZ, + UL_IIR_75HZ, +}; + +enum { + AUDIO_SDM_LEVEL_MUTE = 0, + AUDIO_SDM_LEVEL_NORMAL = 0x1d, + /* if you change level normal */ + /* you need to change formula of hp impedance and dc trim too */ +}; + +enum { + AUDIO_SDM_2ND = 0, + AUDIO_SDM_3RD, +}; + +enum { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO2, +}; + +enum { + 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 { + 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, +}; + +#define SDM_AUTO_RESET_THRESHOLD 0x190000 + +struct mtk_afe_adda_priv { + int dl_rate; + int ul_rate; +}; + +static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id; + + if (strncmp(name, "aud_dac_hires_clk", 7) == 0 || + strncmp(name, "aud_adc_hires_clk", 7) == 0) + dai_id = MT8186_DAI_ADDA; + else + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe, + unsigned int 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; +} + +static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, + unsigned int 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; +} + +/* dai component */ +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN3, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN3, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN3, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN3_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN3_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN3_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN3_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN3, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN3, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN3, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1 Switch", AFE_CONN3, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN3_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1 Switch", AFE_CONN3_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN4, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN4, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN4, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN4, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN4, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN4, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN4, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN4_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN4_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN4_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN4_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN4, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN4, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN4, + I_PCM_2_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN4_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2 Switch", AFE_CONN4_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_ADDA_AFE_ON, + SUPPLY_SEQ_ADDA_DL_ON, + SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SUPPLY_SEQ_ADDA_FIFO, + SUPPLY_SEQ_ADDA_AP_DMIC, + SUPPLY_SEQ_ADDA_UL_ON, +}; + +static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id) +{ + unsigned int reg; + + switch (id) { + case MT8186_DAI_ADDA: + case MT8186_DAI_AP_DMIC: + reg = AFE_ADDA_UL_SRC_CON0; + break; + default: + return -EINVAL; + } + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, reg, + DIGMIC_3P25M_1P625M_SEL_MASK_SFT, 0); + regmap_update_bits(afe->regmap, reg, + DMIC_LOW_POWER_CTL_MASK_SFT, 0); + + /* turn on dmic, ch1, ch2 */ + regmap_update_bits(afe->regmap, reg, + UL_SDM_3_LEVEL_MASK_SFT, + BIT(UL_SDM_3_LEVEL_SFT)); + regmap_update_bits(afe->regmap, reg, + UL_MODE_3P25M_CH1_CTL_MASK_SFT, + BIT(UL_MODE_3P25M_CH1_CTL_SFT)); + regmap_update_bits(afe->regmap, reg, + UL_MODE_3P25M_CH2_CTL_MASK_SFT, + BIT(UL_MODE_3P25M_CH2_CTL_SFT)); + + return 0; +} + +static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n", + __func__, w->name, event, mtkaif_dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 1); + + /* update setting to dmic */ + if (mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + MTKAIF_RXIF_VOICE_MODE_MASK_SFT, + 0x0); + mtk_adda_ul_src_dmic(afe, MT8186_DAI_ADDA); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 1); + + /* reset dmic */ + afe_priv->mtkaif_dmic = 0; + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39); + else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31); + else + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int delay_data; + int delay_cycle; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) { + /* set protocol 2 */ + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000); + /* mtkaif_rxif_clkinv_adc inverse */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + MTKAIF_RXIF_CLKINV_ADC_MASK_SFT, + BIT(MTKAIF_RXIF_CLKINV_ADC_SFT)); + + if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0) { + if (afe_priv->mtkaif_chosen_phase[0] < 0 && + afe_priv->mtkaif_chosen_phase[1] < 0) { + dev_err(afe->dev, + "%s(), calib fail mtkaif_chosen_phase[0/1]:%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1]); + break; + } + + if (afe_priv->mtkaif_chosen_phase[0] < 0 || + afe_priv->mtkaif_chosen_phase[1] < 0) { + dev_err(afe->dev, + "%s(), skip delay setting mtkaif_chosen_phase[0/1]:%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1]); + break; + } + } + + /* set delay for ch12 */ + if (afe_priv->mtkaif_phase_cycle[0] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; + delay_cycle = afe_priv->mtkaif_phase_cycle[0] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[0]; + } + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_DATA_MASK_SFT, + delay_data << + MTKAIF_RXIF_DELAY_DATA_SFT); + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << + MTKAIF_RXIF_DELAY_CYCLE_SFT); + + } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) { + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000); + } else { + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0); + } + + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 0); + break; + default: + break; + } + + return 0; +} + +static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic; + + return 0; +} + +static int mt8186_adda_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dmic_on; + + dmic_on = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n", + __func__, kcontrol->id.name, dmic_on); + + if (afe_priv->mtkaif_dmic == dmic_on) + return 0; + + afe_priv->mtkaif_dmic = dmic_on; + + return 1; +} + +static const struct snd_kcontrol_new mtk_adda_controls[] = { + SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1, + DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0), + SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0, + mt8186_adda_dmic_get, mt8186_adda_dmic_set), +}; + +/* ADDA UL MUX */ +enum { + ADDA_UL_MUX_MTKAIF = 0, + ADDA_UL_MUX_AP_DMIC, + ADDA_UL_MUX_MASK = 0x1, +}; + +static const char * const adda_ul_mux_map[] = { + "MTKAIF", "AP_DMIC" +}; + +static int adda_ul_map_value[] = { + ADDA_UL_MUX_MTKAIF, + ADDA_UL_MUX_AP_DMIC, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum, + SND_SOC_NOPM, + 0, + ADDA_UL_MUX_MASK, + adda_ul_mux_map, + adda_ul_map_value); + +static const struct snd_kcontrol_new adda_ul_mux_control = + SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), + + SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, + AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA_DL_SRC2_CON0, + DL_2_SRC_ON_CTL_PRE_SFT, 0, + mtk_adda_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL_SRC_CON0, + UL_SRC_ON_CTL_SFT, 0, + mtk_adda_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + 0, 0, 0, + mtk_adda_pad_top_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC, + AFE_ADDA_UL_SRC_CON0, + UL_AP_DMIC_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO, + AFE_ADDA_UL_DL_CON0, + AFE_ADDA_FIFO_AUTO_RST_SFT, 1, + NULL, 0), + + SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ul_mux_control), + + SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"), + + /* clock */ + SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires_clk"), +}; + +#define HIRES_THRESHOLD 48000 +static int mtk_afe_dac_hires_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_adda_priv *adda_priv; + + adda_priv = get_adda_priv_by_name(afe, w->name); + + if (!adda_priv) { + dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); + return 0; + } + + return (adda_priv->dl_rate > HIRES_THRESHOLD) ? 1 : 0; +} + +static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_adda_priv *adda_priv; + + adda_priv = get_adda_priv_by_name(afe, w->name); + + if (!adda_priv) { + dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); + return 0; + } + + return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + /* playback */ + {"ADDA_DL_CH1", "DL1_CH1 Switch", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH1 Switch", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH2 Switch", "DL1"}, + + {"ADDA_DL_CH1", "DL12_CH1 Switch", "DL12"}, + {"ADDA_DL_CH2", "DL12_CH2 Switch", "DL12"}, + + {"ADDA_DL_CH1", "DL6_CH1 Switch", "DL6"}, + {"ADDA_DL_CH2", "DL6_CH2 Switch", "DL6"}, + + {"ADDA_DL_CH1", "DL8_CH1 Switch", "DL8"}, + {"ADDA_DL_CH2", "DL8_CH2 Switch", "DL8"}, + + {"ADDA_DL_CH1", "DL2_CH1 Switch", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH1 Switch", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH2 Switch", "DL2"}, + + {"ADDA_DL_CH1", "DL3_CH1 Switch", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH1 Switch", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH2 Switch", "DL3"}, + + {"ADDA_DL_CH1", "DL4_CH1 Switch", "DL4"}, + {"ADDA_DL_CH2", "DL4_CH2 Switch", "DL4"}, + + {"ADDA_DL_CH1", "DL5_CH1 Switch", "DL5"}, + {"ADDA_DL_CH2", "DL5_CH2 Switch", "DL5"}, + + {"ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"ADDA Playback", NULL, "ADDA_DL_CH2"}, + + {"ADDA Playback", NULL, "ADDA Enable"}, + {"ADDA Playback", NULL, "ADDA Playback Enable"}, + + /* capture */ + {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"}, + {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"}, + + {"ADDA Capture", NULL, "ADDA Enable"}, + {"ADDA Capture", NULL, "ADDA Capture Enable"}, + {"ADDA Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"}, + + {"AP DMIC Capture", NULL, "ADDA Enable"}, + {"AP DMIC Capture", NULL, "ADDA Capture Enable"}, + {"AP DMIC Capture", NULL, "ADDA_FIFO"}, + {"AP DMIC Capture", NULL, "AP_DMIC_EN"}, + + {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"}, + + /* clk */ + {"ADDA Playback", NULL, "aud_dac_clk"}, + {"ADDA Playback", NULL, "aud_dac_predis_clk"}, + {"ADDA Playback", NULL, "aud_dac_hires_clk", mtk_afe_dac_hires_connect}, + + {"ADDA Capture Enable", NULL, "aud_adc_clk"}, + {"ADDA Capture Enable", NULL, "aud_adc_hires_clk", + mtk_afe_adc_hires_connect}, + + /* hires source from apll1 */ + {"top_mux_audio_h", NULL, APLL2_W_NAME}, + + {"aud_dac_hires_clk", NULL, "top_mux_audio_h"}, + {"aud_adc_hires_clk", NULL, "top_mux_audio_h"}, +}; + +/* dai ops */ +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + unsigned int rate = params_rate(params); + int id = dai->id; + struct mtk_afe_adda_priv *adda_priv = afe_priv->dai_priv[id]; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, id, substream->stream, rate); + + if (!adda_priv) { + dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + unsigned int dl_src2_con0; + unsigned int dl_src2_con1; + + adda_priv->dl_rate = rate; + + /* set sampling rate */ + dl_src2_con0 = adda_dl_rate_transform(afe, rate) << + DL_2_INPUT_MODE_CTL_SFT; + + /* set output mode, UP_SAMPLING_RATE_X8 */ + dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT); + + /* turn off mute function */ + dl_src2_con0 |= BIT(DL_2_MUTE_CH2_OFF_CTL_PRE_SFT); + dl_src2_con0 |= BIT(DL_2_MUTE_CH1_OFF_CTL_PRE_SFT); + + /* set voice input data if input sample rate is 8k or 16k */ + if (rate == 8000 || rate == 16000) + dl_src2_con0 |= BIT(DL_2_VOICE_MODE_CTL_PRE_SFT); + + /* SA suggest apply -0.3db to audio/speech path */ + dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL << + DL_2_GAIN_CTL_PRE_SFT; + + /* turn on down-link gain */ + dl_src2_con0 |= BIT(DL_2_GAIN_ON_CTL_PRE_SFT); + + if (id == MT8186_DAI_ADDA) { + /* clean predistortion */ + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); + + regmap_write(afe->regmap, + AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); + regmap_write(afe->regmap, + AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); + + /* set sdm gain */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + ATTGAIN_CTL_MASK_SFT, + AUDIO_SDM_LEVEL_NORMAL << + ATTGAIN_CTL_SFT); + + /* Use new 2nd sdm */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DITHER_CON, + AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT, + BIT(AFE_DL_SDM_DITHER_64TAP_EN_SFT)); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + AFE_DL_USE_NEW_2ND_SDM_MASK_SFT, + BIT(AFE_DL_USE_NEW_2ND_SDM_SFT)); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + USE_3RD_SDM_MASK_SFT, + AUDIO_SDM_2ND << USE_3RD_SDM_SFT); + + /* sdm auto reset */ + regmap_write(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + SDM_AUTO_RESET_THRESHOLD); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + SDM_AUTO_RESET_TEST_ON_MASK_SFT, + BIT(SDM_AUTO_RESET_TEST_ON_SFT)); + } + } else { + unsigned int ul_src_con0 = 0; + unsigned int voice_mode = adda_ul_rate_transform(afe, rate); + + adda_priv->ul_rate = rate; + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); + + /* enable iir */ + ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) & + UL_IIR_ON_TMP_CTL_MASK_SFT; + ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) & + UL_IIRMODE_CTL_MASK_SFT; + switch (id) { + case MT8186_DAI_ADDA: + case MT8186_DAI_AP_DMIC: + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_02_01, 0); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_04_03, 0x3fb8); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_06_05, 0x3fb80000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_08_07, 0x3fb80000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_10_09, 0xc048); + + regmap_write(afe->regmap, + AFE_ADDA_UL_SRC_CON0, ul_src_con0); + + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, BIT(0), 0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, BIT(0), 0); + break; + default: + break; + } + + /* ap dmic */ + switch (id) { + case MT8186_DAI_AP_DMIC: + mtk_adda_ul_src_dmic(afe, id); + break; + default: + break; + } + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_adda_ops = { + .hw_params = mtk_dai_adda_hw_params, +}; + +/* dai driver */ +#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "ADDA", + .id = MT8186_DAI_ADDA, + .playback = { + .stream_name = "ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC", + .id = MT8186_DAI_AP_DMIC, + .capture = { + .stream_name = "AP DMIC Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, +}; + +int mt8186_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + + dai->controls = mtk_adda_controls; + dai->num_controls = ARRAY_SIZE(mtk_adda_controls); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + + /* set dai priv */ + ret = mt8186_dai_set_priv(afe, MT8186_DAI_ADDA, + sizeof(struct mtk_afe_adda_priv), NULL); + if (ret) + return ret; + + /* ap dmic priv share with adda */ + afe_priv->dai_priv[MT8186_DAI_AP_DMIC] = + afe_priv->dai_priv[MT8186_DAI_ADDA]; + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c b/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c new file mode 100644 index 000000000000..bf0d83840cf4 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI Hostless Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include "mt8186-afe-common.h" + +static const struct snd_pcm_hardware mt8186_hostless_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 4 * 48 * 1024, + .fifo_size = 0, +}; + +/* dai component */ +static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = { + /* Hostless ADDA Loopback */ + {"ADDA_DL_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"}, + {"ADDA_DL_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"}, + {"ADDA_DL_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"}, + {"ADDA_DL_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"}, + {"I2S1_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"}, + {"I2S1_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"}, + {"I2S3_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"}, + {"I2S3_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"}, + {"I2S3_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"}, + {"I2S3_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"}, + {"Hostless LPBK UL", NULL, "ADDA_UL_Mux"}, + + /* Hostelss FM */ + /* connsys_i2s to hw gain 1*/ + {"Hostless FM UL", NULL, "Connsys I2S"}, + + {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1 Switch", "Hostless FM DL"}, + {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2 Switch", "Hostless FM DL"}, + /* hw gain to adda dl */ + {"Hostless FM UL", NULL, "HW Gain 1 Out"}, + + {"ADDA_DL_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"}, + {"ADDA_DL_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"}, + /* hw gain to i2s3 */ + {"I2S3_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"}, + {"I2S3_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"}, + /* hw gain to i2s1 */ + {"I2S1_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"}, + {"I2S1_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"}, + + /* Hostless_SRC */ + {"ADDA_DL_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"}, + {"ADDA_DL_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"}, + {"I2S1_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"}, + {"I2S1_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"}, + {"I2S3_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"}, + {"I2S3_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"}, + {"Hostless_SRC_1_UL", NULL, "HW_SRC_1_Out"}, + + /* Hostless_SRC_bargein */ + {"HW_SRC_1_IN_CH1", "I2S0_CH1 Switch", "Hostless_SRC_Bargein_DL"}, + {"HW_SRC_1_IN_CH2", "I2S0_CH2 Switch", "Hostless_SRC_Bargein_DL"}, + {"Hostless_SRC_Bargein_UL", NULL, "I2S0"}, + + /* Hostless AAudio */ + {"Hostless HW Gain AAudio In", NULL, "HW Gain 2 In"}, + {"Hostless SRC AAudio UL", NULL, "HW Gain 2 Out"}, + {"HW_SRC_2_IN_CH1", "HW_GAIN2_OUT_CH1 Switch", "Hostless SRC AAudio DL"}, + {"HW_SRC_2_IN_CH2", "HW_GAIN2_OUT_CH2 Switch", "Hostless SRC AAudio DL"}, +}; + +/* dai ops */ +static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + snd_soc_set_runtime_hwparams(substream, &mt8186_hostless_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_hostless_ops = { + .startup = mtk_dai_hostless_startup, +}; + +/* dai driver */ +#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = { + { + .name = "Hostless LPBK DAI", + .id = MT8186_DAI_HOSTLESS_LPBK, + .playback = { + .stream_name = "Hostless LPBK DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless LPBK UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless FM DAI", + .id = MT8186_DAI_HOSTLESS_FM, + .playback = { + .stream_name = "Hostless FM DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless FM UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless_SRC_1_DAI", + .id = MT8186_DAI_HOSTLESS_SRC_1, + .playback = { + .stream_name = "Hostless_SRC_1_DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless_SRC_1_UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless_SRC_Bargein_DAI", + .id = MT8186_DAI_HOSTLESS_SRC_BARGEIN, + .playback = { + .stream_name = "Hostless_SRC_Bargein_DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless_SRC_Bargein_UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + /* BE dai */ + { + .name = "Hostless_UL1 DAI", + .id = MT8186_DAI_HOSTLESS_UL1, + .capture = { + .stream_name = "Hostless_UL1 UL", + .channels_min = 1, + .channels_max = 4, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless_UL2 DAI", + .id = MT8186_DAI_HOSTLESS_UL2, + .capture = { + .stream_name = "Hostless_UL2 UL", + .channels_min = 1, + .channels_max = 4, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless_UL3 DAI", + .id = MT8186_DAI_HOSTLESS_UL3, + .capture = { + .stream_name = "Hostless_UL3 UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless_UL5 DAI", + .id = MT8186_DAI_HOSTLESS_UL5, + .capture = { + .stream_name = "Hostless_UL5 UL", + .channels_min = 1, + .channels_max = 12, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless_UL6 DAI", + .id = MT8186_DAI_HOSTLESS_UL6, + .capture = { + .stream_name = "Hostless_UL6 UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless HW Gain AAudio DAI", + .id = MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO, + .capture = { + .stream_name = "Hostless HW Gain AAudio In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless SRC AAudio DAI", + .id = MT8186_DAI_HOSTLESS_SRC_AAUDIO, + .playback = { + .stream_name = "Hostless SRC AAudio DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless SRC AAudio UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, +}; + +int mt8186_dai_hostless_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_hostless_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver); + + dai->dapm_routes = mtk_dai_hostless_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes); + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c new file mode 100644 index 000000000000..33edd6cbde12 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI HW Gain Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/regmap.h> +#include "mt8186-afe-common.h" +#include "mt8186-interconnection.h" + +#define HW_GAIN_1_EN_W_NAME "HW GAIN 1 Enable" +#define HW_GAIN_2_EN_W_NAME "HW GAIN 2 Enable" + +/* dai component */ +static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13_1, + I_CONNSYS_I2S_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14_1, + I_CONNSYS_I2S_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain2_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN15, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain2_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN16, + I_ADDA_UL_CH2, 1, 0), +}; + +static int mtk_hw_gain_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + unsigned int gain_cur; + unsigned int gain_con1; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) { + gain_cur = AFE_GAIN1_CUR; + gain_con1 = AFE_GAIN1_CON1; + } else { + gain_cur = AFE_GAIN2_CUR; + gain_con1 = AFE_GAIN2_CON1; + } + + /* let hw gain ramp up, set cur gain to 0 */ + regmap_update_bits(afe->regmap, gain_cur, AFE_GAIN1_CUR_MASK_SFT, 0); + + /* set target gain to 0 */ + regmap_update_bits(afe->regmap, gain_con1, GAIN1_TARGET_MASK_SFT, 0); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_hw_gain_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_gain1_in_ch1_mix, + ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_gain1_in_ch2_mix, + ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_gain2_in_ch1_mix, + ARRAY_SIZE(mtk_hw_gain2_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_gain2_in_ch2_mix, + ARRAY_SIZE(mtk_hw_gain2_in_ch2_mix)), + + SND_SOC_DAPM_SUPPLY(HW_GAIN_1_EN_W_NAME, + AFE_GAIN1_CON0, GAIN1_ON_SFT, 0, + mtk_hw_gain_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY(HW_GAIN_2_EN_W_NAME, + AFE_GAIN2_CON0, GAIN2_ON_SFT, 0, + mtk_hw_gain_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"), + SND_SOC_DAPM_INPUT("HW Gain 2 Out Endpoint"), + SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"), +}; + +static const struct snd_soc_dapm_route mtk_dai_hw_gain_routes[] = { + {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"}, + {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"}, + {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH1"}, + {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH2"}, + + {"HW Gain 1 In", NULL, HW_GAIN_1_EN_W_NAME}, + {"HW Gain 1 Out", NULL, HW_GAIN_1_EN_W_NAME}, + {"HW Gain 2 In", NULL, HW_GAIN_2_EN_W_NAME}, + {"HW Gain 2 Out", NULL, HW_GAIN_2_EN_W_NAME}, + + {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"}, + {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"}, + {"HW Gain 2 Out", NULL, "HW Gain 2 Out Endpoint"}, +}; + +static const struct snd_kcontrol_new mtk_hw_gain_controls[] = { + SOC_SINGLE("HW Gain 1 Volume", AFE_GAIN1_CON1, + GAIN1_TARGET_SFT, GAIN1_TARGET_MASK, 0), + SOC_SINGLE("HW Gain 2 Volume", AFE_GAIN2_CON1, + GAIN2_TARGET_SFT, GAIN2_TARGET_MASK, 0), +}; + +/* dai ops */ +static int mtk_dai_gain_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id); + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + /* rate */ + regmap_update_bits(afe->regmap, + dai->id == MT8186_DAI_HW_GAIN_1 ? + AFE_GAIN1_CON0 : AFE_GAIN2_CON0, + GAIN1_MODE_MASK_SFT, + rate_reg << GAIN1_MODE_SFT); + + /* sample per step */ + regmap_update_bits(afe->regmap, + dai->id == MT8186_DAI_HW_GAIN_1 ? + AFE_GAIN1_CON0 : AFE_GAIN2_CON0, + GAIN1_SAMPLE_PER_STEP_MASK_SFT, + (dai->id == MT8186_DAI_HW_GAIN_1 ? 0x40 : 0x0) << + GAIN1_SAMPLE_PER_STEP_SFT); + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_gain_ops = { + .hw_params = mtk_dai_gain_hw_params, +}; + +/* dai driver */ +#define MTK_HW_GAIN_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_HW_GAIN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_gain_driver[] = { + { + .name = "HW Gain 1", + .id = MT8186_DAI_HW_GAIN_1, + .playback = { + .stream_name = "HW Gain 1 In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .capture = { + .stream_name = "HW Gain 1 Out", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .ops = &mtk_dai_gain_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + }, + { + .name = "HW Gain 2", + .id = MT8186_DAI_HW_GAIN_2, + .playback = { + .stream_name = "HW Gain 2 In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .capture = { + .stream_name = "HW Gain 2 Out", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .ops = &mtk_dai_gain_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + }, +}; + +int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_gain_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_gain_driver); + + dai->controls = mtk_hw_gain_controls; + dai->num_controls = ARRAY_SIZE(mtk_hw_gain_controls); + dai->dapm_widgets = mtk_dai_hw_gain_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_hw_gain_widgets); + dai->dapm_routes = mtk_dai_hw_gain_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hw_gain_routes); + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c new file mode 100644 index 000000000000..5c1290b950e8 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -0,0 +1,1286 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/bitops.h> +#include <linux/regmap.h> +#include <sound/pcm_params.h> +#include "mt8186-afe-clk.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +enum { + I2S_FMT_EIAJ = 0, + I2S_FMT_I2S = 1, +}; + +enum { + I2S_WLEN_16_BIT = 0, + I2S_WLEN_32_BIT = 1, +}; + +enum { + I2S_HD_NORMAL = 0, + I2S_HD_LOW_JITTER = 1, +}; + +enum { + I2S1_SEL_O28_O29 = 0, + I2S1_SEL_O03_O04 = 1, +}; + +enum { + I2S_IN_PAD_CONNSYS = 0, + I2S_IN_PAD_IO_MUX = 1, +}; + +struct mtk_afe_i2s_priv { + int id; + int rate; /* for determine which apll to use */ + int low_jitter_en; + int master; /* only i2s0 has slave mode*/ + + const char *share_property_name; + int share_i2s_id; + + int mclk_id; + int mclk_rate; + int mclk_apll; +}; + +static unsigned int get_i2s_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + I2S_WLEN_16_BIT : I2S_WLEN_32_BIT; +} + +#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux" +#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux" +#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux" +#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux" +#define MTK_AFE_I2S0_SRC_KCONTROL_NAME "I2S0_SRC_Mux" + +#define I2S0_HD_EN_W_NAME "I2S0_HD_EN" +#define I2S1_HD_EN_W_NAME "I2S1_HD_EN" +#define I2S2_HD_EN_W_NAME "I2S2_HD_EN" +#define I2S3_HD_EN_W_NAME "I2S3_HD_EN" + +#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN" +#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN" +#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN" +#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN" + +static int get_i2s_id_by_name(struct mtk_base_afe *afe, + const char *name) +{ + if (strncmp(name, "I2S0", 4) == 0) + return MT8186_DAI_I2S_0; + else if (strncmp(name, "I2S1", 4) == 0) + return MT8186_DAI_I2S_1; + else if (strncmp(name, "I2S2", 4) == 0) + return MT8186_DAI_I2S_2; + else if (strncmp(name, "I2S3", 4) == 0) + return MT8186_DAI_I2S_3; + + return -EINVAL; +} + +static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_i2s_id_by_name(afe, name); + + if (dai_id < 0) + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +/* low jitter control */ +static const char * const mt8186_i2s_hd_str[] = { + "Normal", "Low_Jitter" +}; + +static const struct soc_enum mt8186_i2s_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_i2s_hd_str), + mt8186_i2s_hd_str), +}; + +static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en; + + return 0; +} + +static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int hd_en; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + hd_en = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, hd_en); + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + if (i2s_priv->low_jitter_en == hd_en) + return 0; + + i2s_priv->low_jitter_en = hd_en; + + return 1; +} + +static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = { + SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), +}; + +/* dai component */ +/* i2s virtual mux to output widget */ +static const char * const i2s_mux_map[] = { + "Normal", "Dummy_Widget", +}; + +static int i2s_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + i2s_mux_map, + i2s_mux_map_value); + +static const struct snd_kcontrol_new i2s0_in_mux_control = + SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s1_out_mux_control = + SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s2_in_mux_control = + SOC_DAPM_ENUM("I2S2 In Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s3_out_mux_control = + SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum); + +/* i2s in lpbk */ +static const char * const i2s_lpbk_mux_map[] = { + "Normal", "Lpbk", +}; + +static int i2s_lpbk_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum, + AFE_I2S_CON, + I2S_LOOPBACK_SFT, + 1, + i2s_lpbk_mux_map, + i2s_lpbk_mux_map_value); + +static const struct snd_kcontrol_new i2s0_lpbk_mux_control = + SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum, + AFE_I2S_CON2, + I2S3_LOOPBACK_SFT, + 1, + i2s_lpbk_mux_map, + i2s_lpbk_mux_map_value); + +static const struct snd_kcontrol_new i2s2_lpbk_mux_control = + SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum); + +/* interconnection */ +static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN0, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN0, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN0, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN0, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN0, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN0_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN0_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN0_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN0_1, + I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN0, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN0, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN0_1, + I_SRC_1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN1, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN1, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN1, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN1, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN1, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN1_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN1_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN1_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN1_1, + I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN1, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN1, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN1, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN1, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN1, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN1, + I_PCM_2_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN1_1, + I_SRC_1_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN28, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN28, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN28, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN28, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN28, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN28_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN28_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN28_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN28_1, + I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN28, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN28, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN28, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN28_1, + I_SRC_1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN29, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN29, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN29, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN29, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN29, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN29_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN29_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN29_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN29_1, + I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN29, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN29, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN29, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN29, + I_PCM_2_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN29_1, + I_SRC_1_OUT_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_I2S_MCLK_EN, + SUPPLY_SEQ_I2S_HD_EN, + SUPPLY_SEQ_I2S_EN, +}; + +static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, i2s_priv->id, 0); + break; + case SND_SOC_DAPM_POST_PMD: + mt8186_afe_gpio_request(afe->dev, false, i2s_priv->id, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_apll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8186_apll1_enable(afe); + else + mt8186_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8186_apll1_disable(afe); + else + mt8186_apll2_disable(afe); + break; + default: + break; + } + + return 0; +} + +static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + i2s_priv->mclk_rate = 0; + mt8186_mck_disable(afe, i2s_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = { + SND_SOC_DAPM_INPUT("CONNSYS"), + + SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch1_mix, + ARRAY_SIZE(mtk_i2s1_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch2_mix, + ARRAY_SIZE(mtk_i2s1_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch1_mix, + ARRAY_SIZE(mtk_i2s3_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch2_mix, + ARRAY_SIZE(mtk_i2s3_ch2_mix)), + + /* i2s en*/ + SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON1, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON2, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON3, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* i2s hd en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON, I2S1_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* i2s mclk en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* apll */ + SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* allow i2s on without codec on */ + SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"), + SND_SOC_DAPM_MUX("I2S1_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control), + SND_SOC_DAPM_MUX("I2S3_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control), + SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"), + SND_SOC_DAPM_MUX("I2S0_In_Mux", + SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control), + SND_SOC_DAPM_MUX("I2S2_In_Mux", + SND_SOC_NOPM, 0, 0, &i2s2_in_mux_control), + + /* i2s in lpbk */ + SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control), + SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control), +}; + +static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (i2s_priv->share_i2s_id < 0) + return 0; + + return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name); +} + +static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + /* check if share i2s need hd en */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + return 0; +} + +static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + int i2s_need_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8186_get_apll_by_name(afe, source->name); + + /* choose APLL from i2s rate */ + i2s_need_apll = mt8186_get_apll_by_rate(afe, i2s_priv->rate); + + return (i2s_need_apll == cur_apll) ? 1 : 0; +} + +static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + /* check if share i2s need mclk */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + return 0; +} + +static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8186_get_apll_by_name(afe, source->name); + + return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { + {"Connsys I2S", NULL, "CONNSYS"}, + + /* i2s0 */ + {"I2S0", NULL, "I2S0_EN"}, + {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + + {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s1 */ + {"I2S1_CH1", "DL1_CH1 Switch", "DL1"}, + {"I2S1_CH2", "DL1_CH2 Switch", "DL1"}, + + {"I2S1_CH1", "DL2_CH1 Switch", "DL2"}, + {"I2S1_CH2", "DL2_CH2 Switch", "DL2"}, + + {"I2S1_CH1", "DL3_CH1 Switch", "DL3"}, + {"I2S1_CH2", "DL3_CH2 Switch", "DL3"}, + + {"I2S1_CH1", "DL12_CH1 Switch", "DL12"}, + {"I2S1_CH2", "DL12_CH2 Switch", "DL12"}, + + {"I2S1_CH1", "DL12_CH3 Switch", "DL12"}, + {"I2S1_CH2", "DL12_CH4 Switch", "DL12"}, + + {"I2S1_CH1", "DL6_CH1 Switch", "DL6"}, + {"I2S1_CH2", "DL6_CH2 Switch", "DL6"}, + + {"I2S1_CH1", "DL4_CH1 Switch", "DL4"}, + {"I2S1_CH2", "DL4_CH2 Switch", "DL4"}, + + {"I2S1_CH1", "DL5_CH1 Switch", "DL5"}, + {"I2S1_CH2", "DL5_CH2 Switch", "DL5"}, + + {"I2S1_CH1", "DL8_CH1 Switch", "DL8"}, + {"I2S1_CH2", "DL8_CH2 Switch", "DL8"}, + + {"I2S1", NULL, "I2S1_CH1"}, + {"I2S1", NULL, "I2S1_CH2"}, + + {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S1_EN"}, + {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + + {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s2 */ + {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S2_EN"}, + {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + + {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s3 */ + {"I2S3_CH1", "DL1_CH1 Switch", "DL1"}, + {"I2S3_CH2", "DL1_CH2 Switch", "DL1"}, + + {"I2S3_CH1", "DL2_CH1 Switch", "DL2"}, + {"I2S3_CH2", "DL2_CH2 Switch", "DL2"}, + + {"I2S3_CH1", "DL3_CH1 Switch", "DL3"}, + {"I2S3_CH2", "DL3_CH2 Switch", "DL3"}, + + {"I2S3_CH1", "DL12_CH1 Switch", "DL12"}, + {"I2S3_CH2", "DL12_CH2 Switch", "DL12"}, + + {"I2S3_CH1", "DL12_CH3 Switch", "DL12"}, + {"I2S3_CH2", "DL12_CH4 Switch", "DL12"}, + + {"I2S3_CH1", "DL6_CH1 Switch", "DL6"}, + {"I2S3_CH2", "DL6_CH2 Switch", "DL6"}, + + {"I2S3_CH1", "DL4_CH1 Switch", "DL4"}, + {"I2S3_CH2", "DL4_CH2 Switch", "DL4"}, + + {"I2S3_CH1", "DL5_CH1 Switch", "DL5"}, + {"I2S3_CH2", "DL5_CH2 Switch", "DL5"}, + + {"I2S3_CH1", "DL8_CH1 Switch", "DL8"}, + {"I2S3_CH2", "DL8_CH2 Switch", "DL8"}, + + {"I2S3", NULL, "I2S3_CH1"}, + {"I2S3", NULL, "I2S3_CH2"}, + + {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S3_EN"}, + + {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* allow i2s on without codec on */ + {"I2S0", NULL, "I2S0_In_Mux"}, + {"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"}, + + {"I2S1_Out_Mux", "Dummy_Widget", "I2S1"}, + {"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"}, + + {"I2S2", NULL, "I2S2_In_Mux"}, + {"I2S2_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"}, + + {"I2S3_Out_Mux", "Dummy_Widget", "I2S3"}, + {"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"}, + + /* i2s in lpbk */ + {"I2S0_Lpbk_Mux", "Lpbk", "I2S3"}, + {"I2S2_Lpbk_Mux", "Lpbk", "I2S1"}, + {"I2S0", NULL, "I2S0_Lpbk_Mux"}, + {"I2S2", NULL, "I2S2_Lpbk_Mux"}, +}; + +/* dai ops */ +static int mtk_dai_connsys_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, + rate, dai->id); + unsigned int i2s_con = 0; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + /* non-inverse, i2s mode, slave, 16bits, from connsys */ + i2s_con |= 0 << INV_PAD_CTRL_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= 1 << I2S_SRC_SFT; + i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT; + i2s_con |= 0 << I2SIN_PAD_SEL_SFT; + regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con); + + /* use asrc */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_BYPSRC_MASK_SFT, 0); + + /* slave mode, set i2s for asrc */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT); + + if (rate == 44100) + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1b9000); + else if (rate == 32000) + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000); + else + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1e0000); + + /* Calibration setting */ + regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x140000); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x36000); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x2fc00); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x7ef4); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0xff5986); + + /* 0:Stereo 1:Mono */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2, + CHSET_IS_MONO_MASK_SFT, 0); + + return 0; +} + +static int mtk_dai_connsys_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n", + __func__, cmd, substream->stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* i2s enable */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_EN_MASK_SFT, + BIT(I2S_EN_SFT)); + + /* calibrator enable */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON5, + CALI_EN_MASK_SFT, + BIT(CALI_EN_SFT)); + + /* asrc enable */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_CHSET_STR_CLR_MASK_SFT, + BIT(CON0_CHSET_STR_CLR_SFT)); + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_ASM_ON_MASK_SFT, + BIT(CON0_ASM_ON_SFT)); + + afe_priv->dai_on[dai->id] = true; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + CON0_ASM_ON_MASK_SFT, 0); + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5, + CALI_EN_MASK_SFT, 0); + + /* i2s disable */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_EN_MASK_SFT, 0); + + /* bypass asrc */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_BYPSRC_MASK_SFT, BIT(I2S_BYPSRC_SFT)); + + afe_priv->dai_on[dai->id] = false; + return 0; + default: + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = { + .hw_params = mtk_dai_connsys_i2s_hw_params, + .trigger = mtk_dai_connsys_i2s_trigger, +}; + +/* i2s */ +static int mtk_dai_i2s_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + int i2s_id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id]; + + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, + rate, i2s_id); + snd_pcm_format_t format = params_format(params); + unsigned int i2s_con = 0; + int ret; + + dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n", + __func__, i2s_id, rate, format); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + i2s_priv->rate = rate; + + switch (i2s_id) { + case MT8186_DAI_I2S_0: + i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT; + i2s_con |= rate_reg << I2S_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON, + 0xffffeffa, i2s_con); + break; + case MT8186_DAI_I2S_1: + i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT; + i2s_con |= rate_reg << I2S2_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0xffffeffa, i2s_con); + break; + case MT8186_DAI_I2S_2: + i2s_con = 8 << I2S3_UPDATE_WORD_SFT; + i2s_con |= rate_reg << I2S3_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON2, + 0xffffeffa, i2s_con); + break; + case MT8186_DAI_I2S_3: + i2s_con = rate_reg << I2S4_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON3, + 0xffffeffa, i2s_con); + break; + default: + dev_err(afe->dev, "%s(), id %d not support\n", + __func__, i2s_id); + return -EINVAL; + } + + /* set share i2s */ + if (i2s_priv && i2s_priv->share_i2s_id >= 0) { + ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id); + if (ret) + return ret; + } + + return 0; +} + +static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return mtk_dai_i2s_config(afe, params, dai->id); +} + +static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id]; + int apll; + int apll_rate; + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); + + apll = mt8186_get_apll_by_rate(afe, freq); + apll_rate = mt8186_get_apll_rate(afe, apll); + + if (freq > apll_rate) { + dev_err(afe->dev, "%s(), freq > apll rate", __func__); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_err(afe->dev, "%s(), APLL cannot generate freq Hz", __func__); + return -EINVAL; + } + + i2s_priv->mclk_rate = freq; + i2s_priv->mclk_apll = apll; + + if (i2s_priv->share_i2s_id > 0) { + struct mtk_afe_i2s_priv *share_i2s_priv; + + share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id]; + if (!share_i2s_priv) { + dev_err(afe->dev, "%s(), share_i2s_priv == NULL", __func__); + return -EINVAL; + } + + share_i2s_priv->mclk_rate = i2s_priv->mclk_rate; + share_i2s_priv->mclk_apll = i2s_priv->mclk_apll; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_i2s_ops = { + .hw_params = mtk_dai_i2s_hw_params, + .set_sysclk = mtk_dai_i2s_set_sysclk, +}; + +/* dai driver */ +#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = { + { + .name = "CONNSYS_I2S", + .id = MT8186_DAI_CONNSYS_I2S, + .capture = { + .stream_name = "Connsys I2S", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_CONNSYS_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_connsys_i2s_ops, + }, + { + .name = "I2S0", + .id = MT8186_DAI_I2S_0, + .capture = { + .stream_name = "I2S0", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S1", + .id = MT8186_DAI_I2S_1, + .playback = { + .stream_name = "I2S1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S2", + .id = MT8186_DAI_I2S_2, + .capture = { + .stream_name = "I2S2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S3", + .id = MT8186_DAI_I2S_3, + .playback = { + .stream_name = "I2S3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + } +}; + +/* this enum is merely for mtk_afe_i2s_priv declare */ +enum { + DAI_I2S0 = 0, + DAI_I2S1, + DAI_I2S2, + DAI_I2S3, + DAI_I2S_NUM, +}; + +static const struct mtk_afe_i2s_priv mt8186_i2s_priv[DAI_I2S_NUM] = { + [DAI_I2S0] = { + .id = MT8186_DAI_I2S_0, + .mclk_id = MT8186_I2S0_MCK, + .share_property_name = "i2s0-share", + .share_i2s_id = -1, + }, + [DAI_I2S1] = { + .id = MT8186_DAI_I2S_1, + .mclk_id = MT8186_I2S1_MCK, + .share_property_name = "i2s1-share", + .share_i2s_id = -1, + }, + [DAI_I2S2] = { + .id = MT8186_DAI_I2S_2, + .mclk_id = MT8186_I2S2_MCK, + .share_property_name = "i2s2-share", + .share_i2s_id = -1, + }, + [DAI_I2S3] = { + .id = MT8186_DAI_I2S_3, + /* clock gate naming is hf_faud_i2s4_m_ck*/ + .mclk_id = MT8186_I2S4_MCK, + .share_property_name = "i2s3-share", + .share_i2s_id = -1, + } +}; + +static int mt8186_dai_i2s_get_share(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + const struct device_node *of_node = afe->dev->of_node; + const char *of_str; + const char *property_name; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = afe_priv->dai_priv[mt8186_i2s_priv[i].id]; + property_name = mt8186_i2s_priv[i].share_property_name; + if (of_property_read_string(of_node, property_name, &of_str)) + continue; + i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); + } + + return 0; +} + +static int mt8186_dai_i2s_set_priv(struct mtk_base_afe *afe) +{ + int i; + int ret; + + for (i = 0; i < DAI_I2S_NUM; i++) { + ret = mt8186_dai_set_priv(afe, mt8186_i2s_priv[i].id, + sizeof(struct mtk_afe_i2s_priv), + &mt8186_i2s_priv[i]); + if (ret) + return ret; + } + + return 0; +} + +int mt8186_dai_i2s_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_i2s_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver); + + dai->controls = mtk_dai_i2s_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls); + dai->dapm_widgets = mtk_dai_i2s_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets); + dai->dapm_routes = mtk_dai_i2s_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); + + /* set all dai i2s private data */ + ret = mt8186_dai_i2s_set_priv(afe); + if (ret) + return ret; + + /* parse share i2s */ + ret = mt8186_dai_i2s_get_share(afe); + if (ret) + return ret; + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c new file mode 100644 index 000000000000..0b0032ecfe6d --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/regmap.h> +#include <sound/pcm_params.h> +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +struct mtk_afe_pcm_priv { + unsigned int id; + unsigned int fmt; + unsigned int bck_invert; + unsigned int lck_invert; +}; + +enum aud_tx_lch_rpt { + AUD_TX_LCH_RPT_NO_REPEAT = 0, + AUD_TX_LCH_RPT_REPEAT = 1 +}; + +enum aud_vbt_16k_mode { + AUD_VBT_16K_MODE_DISABLE = 0, + AUD_VBT_16K_MODE_ENABLE = 1 +}; + +enum aud_ext_modem { + AUD_EXT_MODEM_SELECT_INTERNAL = 0, + AUD_EXT_MODEM_SELECT_EXTERNAL = 1 +}; + +enum aud_pcm_sync_type { + /* bck sync length = 1 */ + AUD_PCM_ONE_BCK_CYCLE_SYNC = 0, + /* bck sync length = PCM_INTF_CON1[9:13] */ + AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1 +}; + +enum aud_bt_mode { + AUD_BT_MODE_DUAL_MIC_ON_TX = 0, + AUD_BT_MODE_SINGLE_MIC_ON_TX = 1 +}; + +enum aud_pcm_afifo_src { + /* slave mode & external modem uses different crystal */ + AUD_PCM_AFIFO_ASRC = 0, + /* slave mode & external modem uses the same crystal */ + AUD_PCM_AFIFO_AFIFO = 1 +}; + +enum aud_pcm_clock_source { + AUD_PCM_CLOCK_MASTER_MODE = 0, + AUD_PCM_CLOCK_SLAVE_MODE = 1 +}; + +enum aud_pcm_wlen { + AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0, + AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1 +}; + +enum aud_pcm_24bit { + AUD_PCM_24BIT_PCM_16_BITS = 0, + AUD_PCM_24BIT_PCM_24_BITS = 1 +}; + +enum aud_pcm_mode { + AUD_PCM_MODE_PCM_MODE_8K = 0, + AUD_PCM_MODE_PCM_MODE_16K = 1, + AUD_PCM_MODE_PCM_MODE_32K = 2, + AUD_PCM_MODE_PCM_MODE_48K = 3, +}; + +enum aud_pcm_fmt { + AUD_PCM_FMT_I2S = 0, + AUD_PCM_FMT_EIAJ = 1, + AUD_PCM_FMT_PCM_MODE_A = 2, + AUD_PCM_FMT_PCM_MODE_B = 3 +}; + +enum aud_bclk_out_inv { + AUD_BCLK_OUT_INV_NO_INVERSE = 0, + AUD_BCLK_OUT_INV_INVERSE = 1 +}; + +enum aud_lrclk_out_inv { + AUD_LRCLK_OUT_INV_NO_INVERSE = 0, + AUD_LRCLK_OUT_INV_INVERSE = 1 +}; + +enum aud_pcm_en { + AUD_PCM_EN_DISABLE = 0, + AUD_PCM_EN_ENABLE = 1 +}; + +/* dai component */ +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN7, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN7, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN7_1, + I_DL4_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN8, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN8, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN8_1, + I_DL4_CH2, 1, 0), +}; + +static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_PCM, 0); + break; + case SND_SOC_DAPM_POST_PMD: + mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_PCM, 0); + break; + } + + return 0; +} + +/* pcm in/out lpbk */ +static const char * const pcm_lpbk_mux_map[] = { + "Normal", "Lpbk", +}; + +static int pcm_lpbk_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_in_lpbk_mux_map_enum, + PCM_INTF_CON1, + PCM_I2S_PCM_LOOPBACK_SFT, + 1, + pcm_lpbk_mux_map, + pcm_lpbk_mux_map_value); + +static const struct snd_kcontrol_new pcm_in_lpbk_mux_control = + SOC_DAPM_ENUM("PCM In Lpbk Select", pcm_in_lpbk_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_out_lpbk_mux_map_enum, + PCM_INTF_CON1, + PCM_I2S_PCM_LOOPBACK_SFT, + 1, + pcm_lpbk_mux_map, + pcm_lpbk_mux_map_value); + +static const struct snd_kcontrol_new pcm_out_lpbk_mux_control = + SOC_DAPM_ENUM("PCM Out Lpbk Select", pcm_out_lpbk_mux_map_enum); + +static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)), + + SND_SOC_DAPM_SUPPLY("PCM_1_EN", + PCM_INTF_CON1, PCM_EN_SFT, 0, + mtk_pcm_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* pcm in lpbk */ + SND_SOC_DAPM_MUX("PCM_In_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &pcm_in_lpbk_mux_control), + + /* pcm out lpbk */ + SND_SOC_DAPM_MUX("PCM_Out_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &pcm_out_lpbk_mux_control), +}; + +static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { + {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"}, + + {"PCM 1 Playback", NULL, "PCM_1_EN"}, + {"PCM 1 Capture", NULL, "PCM_1_EN"}, + + {"PCM_1_PB_CH1", "DL2_CH1 Switch", "DL2"}, + {"PCM_1_PB_CH2", "DL2_CH2 Switch", "DL2"}, + + {"PCM_1_PB_CH1", "DL4_CH1 Switch", "DL4"}, + {"PCM_1_PB_CH2", "DL4_CH2 Switch", "DL4"}, + + /* pcm out lpbk */ + {"PCM_Out_Lpbk_Mux", "Lpbk", "PCM 1 Playback"}, + {"I2S0", NULL, "PCM_Out_Lpbk_Mux"}, + + /* pcm in lpbk */ + {"PCM_In_Lpbk_Mux", "Lpbk", "PCM 1 Capture"}, + {"I2S3", NULL, "PCM_In_Lpbk_Mux"}, +}; + +/* dai ops */ +static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int pcm_id = dai->id; + struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[pcm_id]; + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id); + snd_pcm_format_t format = params_format(params); + unsigned int data_width = + snd_pcm_format_width(format); + unsigned int wlen_width = + snd_pcm_format_physical_width(format); + unsigned int pcm_con = 0; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n", + __func__, dai->id, substream->stream, dai->playback_widget->active, + dai->capture_widget->active); + dev_dbg(afe->dev, "%s(), rate %d, rate_reg %d, data_width %d, wlen_width %d\n", + __func__, rate, rate_reg, data_width, wlen_width); + + if (dai->playback_widget->active || dai->capture_widget->active) + return 0; + + switch (dai->id) { + case MT8186_DAI_PCM: + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT; + pcm_con |= AUD_EXT_MODEM_SELECT_EXTERNAL << PCM_EXT_MODEM_SFT; + pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT; + pcm_con |= AUD_PCM_CLOCK_MASTER_MODE << PCM_SLAVE_SFT; + pcm_con |= 0 << PCM_SYNC_LENGTH_SFT; + + /* sampling rate */ + pcm_con |= rate_reg << PCM_MODE_SFT; + + /* format */ + pcm_con |= pcm_priv->fmt << PCM_FMT_SFT; + + /* 24bit data width */ + if (data_width > 16) + pcm_con |= AUD_PCM_24BIT_PCM_24_BITS << PCM_24BIT_SFT; + else + pcm_con |= AUD_PCM_24BIT_PCM_16_BITS << PCM_24BIT_SFT; + + /* wlen width*/ + if (wlen_width > 16) + pcm_con |= AUD_PCM_WLEN_PCM_64_BCK_CYCLES << PCM_WLEN_SFT; + else + pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM_WLEN_SFT; + + /* clock invert */ + pcm_con |= pcm_priv->lck_invert << PCM_SYNC_OUT_INV_SFT; + pcm_con |= pcm_priv->bck_invert << PCM_BCLK_OUT_INV_SFT; + + regmap_update_bits(afe->regmap, PCM_INTF_CON1, 0xfffffffe, pcm_con); + break; + default: + dev_err(afe->dev, "%s(), id %d not support\n", __func__, dai->id); + return -EINVAL; + } + + return 0; +} + +static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id]; + + if (!pcm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + /* DAI mode*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + pcm_priv->fmt = AUD_PCM_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + pcm_priv->fmt = AUD_PCM_FMT_EIAJ; + break; + case SND_SOC_DAIFMT_DSP_A: + pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_A; + break; + case SND_SOC_DAIFMT_DSP_B: + pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_B; + break; + default: + pcm_priv->fmt = AUD_PCM_FMT_I2S; + } + + /* DAI clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; + pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; + break; + case SND_SOC_DAIFMT_NB_IF: + pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; + pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE; + break; + case SND_SOC_DAIFMT_IB_NF: + pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE; + pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; + break; + case SND_SOC_DAIFMT_IB_IF: + pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE; + pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE; + break; + default: + pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; + pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { + .hw_params = mtk_dai_pcm_hw_params, + .set_fmt = mtk_dai_pcm_set_fmt, +}; + +/* dai driver */ +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { + { + .name = "PCM 1", + .id = MT8186_DAI_PCM, + .playback = { + .stream_name = "PCM 1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + }, +}; + +static struct mtk_afe_pcm_priv *init_pcm_priv_data(struct mtk_base_afe *afe) +{ + struct mtk_afe_pcm_priv *pcm_priv; + + pcm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_pcm_priv), + GFP_KERNEL); + if (!pcm_priv) + return NULL; + + pcm_priv->id = MT8186_DAI_PCM; + pcm_priv->fmt = AUD_PCM_FMT_I2S; + pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; + pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; + + return pcm_priv; +} + +int mt8186_dai_pcm_register(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_pcm_priv *pcm_priv; + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_pcm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); + + dai->dapm_widgets = mtk_dai_pcm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); + dai->dapm_routes = mtk_dai_pcm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); + + pcm_priv = init_pcm_priv_data(afe); + if (!pcm_priv) + return -ENOMEM; + + afe_priv->dai_priv[MT8186_DAI_PCM] = pcm_priv; + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-src.c b/sound/soc/mediatek/mt8186/mt8186-dai-src.c new file mode 100644 index 000000000000..67989ffd67ca --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-src.c @@ -0,0 +1,695 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI SRC Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/regmap.h> +#include "mt8186-afe-common.h" +#include "mt8186-interconnection.h" + +struct mtk_afe_src_priv { + int dl_rate; + int ul_rate; +}; + +static const unsigned int src_iir_coeff_32_to_16[] = { + 0x0dbae6, 0xff9b0a, 0x0dbae6, 0x05e488, 0xe072b9, 0x000002, + 0x0dbae6, 0x000f3b, 0x0dbae6, 0x06a537, 0xe17d79, 0x000002, + 0x0dbae6, 0x01246a, 0x0dbae6, 0x087261, 0xe306be, 0x000002, + 0x0dbae6, 0x03437d, 0x0dbae6, 0x0bc16f, 0xe57c87, 0x000002, + 0x0dbae6, 0x072981, 0x0dbae6, 0x111dd3, 0xe94f2a, 0x000002, + 0x0dbae6, 0x0dc4a6, 0x0dbae6, 0x188611, 0xee85a0, 0x000002, + 0x0dbae6, 0x168b9a, 0x0dbae6, 0x200e8f, 0xf3ccf1, 0x000002, + 0x000000, 0x1b75cb, 0x1b75cb, 0x2374a2, 0x000000, 0x000001 +}; + +static const unsigned int src_iir_coeff_44_to_16[] = { + 0x09ae28, 0xf7d97d, 0x09ae28, 0x212a3d, 0xe0ac3a, 0x000002, + 0x09ae28, 0xf8525a, 0x09ae28, 0x216d72, 0xe234be, 0x000002, + 0x09ae28, 0xf980f5, 0x09ae28, 0x22a057, 0xe45a81, 0x000002, + 0x09ae28, 0xfc0a08, 0x09ae28, 0x24d3bd, 0xe7752d, 0x000002, + 0x09ae28, 0x016162, 0x09ae28, 0x27da01, 0xeb6ea8, 0x000002, + 0x09ae28, 0x0b67df, 0x09ae28, 0x2aca4a, 0xef34c4, 0x000002, + 0x000000, 0x135c50, 0x135c50, 0x2c1079, 0x000000, 0x000001 +}; + +static const unsigned int src_iir_coeff_44_to_32[] = { + 0x096966, 0x0c4d35, 0x096966, 0xedee81, 0xf05070, 0x000003, + 0x12d2cc, 0x193910, 0x12d2cc, 0xddbf4f, 0xe21e1d, 0x000002, + 0x12d2cc, 0x1a9e60, 0x12d2cc, 0xe18916, 0xe470fd, 0x000002, + 0x12d2cc, 0x1d06e0, 0x12d2cc, 0xe8a4a6, 0xe87b24, 0x000002, + 0x12d2cc, 0x207578, 0x12d2cc, 0xf4fe62, 0xef5917, 0x000002, + 0x12d2cc, 0x24055f, 0x12d2cc, 0x05ee2b, 0xf8b502, 0x000002, + 0x000000, 0x25a599, 0x25a599, 0x0fabe2, 0x000000, 0x000001 +}; + +static const unsigned int src_iir_coeff_48_to_16[] = { + 0x0296a4, 0xfd69dd, 0x0296a4, 0x209439, 0xe01ff9, 0x000002, + 0x0f4ff3, 0xf0d6d4, 0x0f4ff3, 0x209bc9, 0xe076c3, 0x000002, + 0x0e8490, 0xf1fe63, 0x0e8490, 0x20cfd6, 0xe12124, 0x000002, + 0x14852f, 0xed794a, 0x14852f, 0x21503d, 0xe28b32, 0x000002, + 0x136222, 0xf17677, 0x136222, 0x225be1, 0xe56964, 0x000002, + 0x0a8d85, 0xfc4a97, 0x0a8d85, 0x24310c, 0xea6952, 0x000002, + 0x05eff5, 0x043455, 0x05eff5, 0x4ced8f, 0xe134d6, 0x000001, + 0x000000, 0x3aebe6, 0x3aebe6, 0x04f3b0, 0x000000, 0x000004 +}; + +static const unsigned int src_iir_coeff_48_to_32[] = { + 0x10c1b8, 0x10a7df, 0x10c1b8, 0xe7514e, 0xe0b41f, 0x000002, + 0x10c1b8, 0x116257, 0x10c1b8, 0xe9402f, 0xe25aaa, 0x000002, + 0x10c1b8, 0x130c89, 0x10c1b8, 0xed3cc3, 0xe4dddb, 0x000002, + 0x10c1b8, 0x1600dd, 0x10c1b8, 0xf48000, 0xe90c55, 0x000002, + 0x10c1b8, 0x1a672e, 0x10c1b8, 0x00494c, 0xefa807, 0x000002, + 0x10c1b8, 0x1f38e6, 0x10c1b8, 0x0ee076, 0xf7c5f3, 0x000002, + 0x000000, 0x218370, 0x218370, 0x168b40, 0x000000, 0x000001 +}; + +static const unsigned int src_iir_coeff_48_to_44[] = { + 0x0bf71c, 0x170f3f, 0x0bf71c, 0xe3a4c8, 0xf096cb, 0x000003, + 0x0bf71c, 0x17395e, 0x0bf71c, 0xe58085, 0xf210c8, 0x000003, + 0x0bf71c, 0x1782bd, 0x0bf71c, 0xe95ef6, 0xf4c899, 0x000003, + 0x0bf71c, 0x17cd97, 0x0bf71c, 0xf1608a, 0xfa3b18, 0x000003, + 0x000000, 0x2fdc6f, 0x2fdc6f, 0xf15663, 0x000000, 0x000001 +}; + +static const unsigned int src_iir_coeff_96_to_16[] = { + 0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002, + 0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003, + 0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003, + 0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003, + 0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002, + 0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002, + 0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002, + 0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001, +}; + +static const unsigned int src_iir_coeff_96_to_44[] = { + 0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002, + 0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002, + 0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002, + 0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002, + 0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002, + 0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002, + 0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001, + 0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001, +}; + +static unsigned int mtk_get_src_freq_mode(struct mtk_base_afe *afe, int rate) +{ + switch (rate) { + case 8000: + return 0x50000; + case 11025: + return 0x6e400; + case 12000: + return 0x78000; + case 16000: + return 0xa0000; + case 22050: + return 0xdc800; + case 24000: + return 0xf0000; + case 32000: + return 0x140000; + case 44100: + return 0x1b9000; + case 48000: + return 0x1e0000; + case 88200: + return 0x372000; + case 96000: + return 0x3c0000; + case 176400: + return 0x6e4000; + case 192000: + return 0x780000; + default: + dev_err(afe->dev, "%s(), rate %d invalid!!!\n", + __func__, rate); + return 0; + } +} + +static const unsigned int *get_iir_coeff(unsigned int rate_in, + unsigned int rate_out, + unsigned int *param_num) +{ + if (rate_in == 32000 && rate_out == 16000) { + *param_num = ARRAY_SIZE(src_iir_coeff_32_to_16); + return src_iir_coeff_32_to_16; + } else if (rate_in == 44100 && rate_out == 16000) { + *param_num = ARRAY_SIZE(src_iir_coeff_44_to_16); + return src_iir_coeff_44_to_16; + } else if (rate_in == 44100 && rate_out == 32000) { + *param_num = ARRAY_SIZE(src_iir_coeff_44_to_32); + return src_iir_coeff_44_to_32; + } else if ((rate_in == 48000 && rate_out == 16000) || + (rate_in == 96000 && rate_out == 32000)) { + *param_num = ARRAY_SIZE(src_iir_coeff_48_to_16); + return src_iir_coeff_48_to_16; + } else if (rate_in == 48000 && rate_out == 32000) { + *param_num = ARRAY_SIZE(src_iir_coeff_48_to_32); + return src_iir_coeff_48_to_32; + } else if (rate_in == 48000 && rate_out == 44100) { + *param_num = ARRAY_SIZE(src_iir_coeff_48_to_44); + return src_iir_coeff_48_to_44; + } else if (rate_in == 96000 && rate_out == 16000) { + *param_num = ARRAY_SIZE(src_iir_coeff_96_to_16); + return src_iir_coeff_96_to_16; + } else if ((rate_in == 96000 && rate_out == 44100) || + (rate_in == 48000 && rate_out == 22050)) { + *param_num = ARRAY_SIZE(src_iir_coeff_96_to_44); + return src_iir_coeff_96_to_44; + } + + *param_num = 0; + return NULL; +} + +static int mtk_set_src_1_param(struct mtk_base_afe *afe, int id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; + unsigned int iir_coeff_num; + unsigned int iir_stage; + int rate_in = src_priv->dl_rate; + int rate_out = src_priv->ul_rate; + unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out); + unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in); + + /* set out freq mode */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON3, + G_SRC_ASM_FREQ_4_MASK_SFT, + out_freq_mode << G_SRC_ASM_FREQ_4_SFT); + + /* set in freq mode */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON4, + G_SRC_ASM_FREQ_5_MASK_SFT, + in_freq_mode << G_SRC_ASM_FREQ_5_SFT); + + regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5986); + regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5987); + regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON6, 0x1fbd); + regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, 0); + + /* set iir if in_rate > out_rate */ + if (rate_in > rate_out) { + int i; + const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out, + &iir_coeff_num); + + if (iir_coeff_num == 0 || !iir_coeff) { + dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n", + __func__, iir_coeff_num, iir_coeff); + return -EINVAL; + } + + /* COEFF_SRAM_CTRL */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0, + G_SRC_COEFF_SRAM_CTRL_MASK_SFT, + BIT(G_SRC_COEFF_SRAM_CTRL_SFT)); + /* Clear coeff history to r/w coeff from the first position */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON13, + G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0); + /* Write SRC coeff, should not read the reg during write */ + for (i = 0; i < iir_coeff_num; i++) + regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON12, + iir_coeff[i]); + /* disable sram access */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0, + G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0); + /* CHSET_IIR_STAGE */ + iir_stage = (iir_coeff_num / 6) - 1; + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, + G_SRC_CHSET_IIR_STAGE_MASK_SFT, + iir_stage << G_SRC_CHSET_IIR_STAGE_SFT); + /* CHSET_IIR_EN */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, + G_SRC_CHSET_IIR_EN_MASK_SFT, + BIT(G_SRC_CHSET_IIR_EN_SFT)); + } else { + /* CHSET_IIR_EN off */ + regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, + G_SRC_CHSET_IIR_EN_MASK_SFT, 0); + } + + return 0; +} + +static int mtk_set_src_2_param(struct mtk_base_afe *afe, int id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; + unsigned int iir_coeff_num; + unsigned int iir_stage; + int rate_in = src_priv->dl_rate; + int rate_out = src_priv->ul_rate; + unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out); + unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in); + + /* set out freq mode */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON3, + G_SRC_ASM_FREQ_4_MASK_SFT, + out_freq_mode << G_SRC_ASM_FREQ_4_SFT); + + /* set in freq mode */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON4, + G_SRC_ASM_FREQ_5_MASK_SFT, + in_freq_mode << G_SRC_ASM_FREQ_5_SFT); + + regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5986); + regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5987); + regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON6, 0x1fbd); + regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, 0); + + /* set iir if in_rate > out_rate */ + if (rate_in > rate_out) { + int i; + const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out, + &iir_coeff_num); + + if (iir_coeff_num == 0 || !iir_coeff) { + dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n", + __func__, iir_coeff_num, iir_coeff); + return -EINVAL; + } + + /* COEFF_SRAM_CTRL */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0, + G_SRC_COEFF_SRAM_CTRL_MASK_SFT, + BIT(G_SRC_COEFF_SRAM_CTRL_SFT)); + /* Clear coeff history to r/w coeff from the first position */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON13, + G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0); + /* Write SRC coeff, should not read the reg during write */ + for (i = 0; i < iir_coeff_num; i++) + regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON12, + iir_coeff[i]); + /* disable sram access */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0, + G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0); + /* CHSET_IIR_STAGE */ + iir_stage = (iir_coeff_num / 6) - 1; + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, + G_SRC_CHSET_IIR_STAGE_MASK_SFT, + iir_stage << G_SRC_CHSET_IIR_STAGE_SFT); + /* CHSET_IIR_EN */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, + G_SRC_CHSET_IIR_EN_MASK_SFT, + BIT(G_SRC_CHSET_IIR_EN_SFT)); + } else { + /* CHSET_IIR_EN off */ + regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, + G_SRC_CHSET_IIR_EN_MASK_SFT, 0); + } + + return 0; +} + +#define HW_SRC_1_EN_W_NAME "HW_SRC_1_Enable" +#define HW_SRC_2_EN_W_NAME "HW_SRC_2_Enable" + +static int mtk_hw_src_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int id; + struct mtk_afe_src_priv *src_priv; + unsigned int reg; + + if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0) + id = MT8186_DAI_SRC_1; + else + id = MT8186_DAI_SRC_2; + + src_priv = afe_priv->dai_priv[id]; + + dev_dbg(afe->dev, + "%s(), name %s, event 0x%x, id %d, src_priv %p, dl_rate %d, ul_rate %d\n", + __func__, w->name, event, id, src_priv, + src_priv->dl_rate, src_priv->ul_rate); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (id == MT8186_DAI_SRC_1) + mtk_set_src_1_param(afe, id); + else + mtk_set_src_2_param(afe, id); + break; + case SND_SOC_DAPM_POST_PMU: + reg = (id == MT8186_DAI_SRC_1) ? + AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0; + /* ASM_ON */ + regmap_update_bits(afe->regmap, reg, + G_SRC_ASM_ON_MASK_SFT, + BIT(G_SRC_ASM_ON_SFT)); + /* CHSET_ON */ + regmap_update_bits(afe->regmap, reg, + G_SRC_CHSET_ON_MASK_SFT, + BIT(G_SRC_CHSET_ON_SFT)); + /* CHSET_STR_CLR */ + regmap_update_bits(afe->regmap, reg, + G_SRC_CHSET_STR_CLR_MASK_SFT, + BIT(G_SRC_CHSET_STR_CLR_SFT)); + break; + case SND_SOC_DAPM_PRE_PMD: + reg = (id == MT8186_DAI_SRC_1) ? + AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0; + /* ASM_OFF */ + regmap_update_bits(afe->regmap, reg, G_SRC_ASM_ON_MASK_SFT, 0); + /* CHSET_OFF */ + regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_ON_MASK_SFT, 0); + /* CHSET_STR_CLR */ + regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_STR_CLR_MASK_SFT, 0); + break; + default: + break; + } + + return 0; +} + +/* dai component */ +static const struct snd_kcontrol_new mtk_hw_src_1_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN40, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN40, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN40, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN40_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN40_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN40, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN40_1, + I_DL5_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_src_1_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN41, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN41, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN41, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN41_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN41_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN41, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN41_1, + I_DL5_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_src_2_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN42, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN42, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN42, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN42, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN42_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN42_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch", AFE_CONN42, + I_GAIN2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_src_2_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN43, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN43, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN43, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN43, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN43_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN43_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch", AFE_CONN43, + I_GAIN2_OUT_CH2, 1, 0), +}; + +static const struct snd_soc_dapm_widget mtk_dai_src_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_src_1_in_ch1_mix, + ARRAY_SIZE(mtk_hw_src_1_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_src_1_in_ch2_mix, + ARRAY_SIZE(mtk_hw_src_1_in_ch2_mix)), + SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_src_2_in_ch1_mix, + ARRAY_SIZE(mtk_hw_src_2_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_src_2_in_ch2_mix, + ARRAY_SIZE(mtk_hw_src_2_in_ch2_mix)), + + SND_SOC_DAPM_SUPPLY(HW_SRC_1_EN_W_NAME, + GENERAL_ASRC_EN_ON, GENERAL1_ASRC_EN_ON_SFT, 0, + mtk_hw_src_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY(HW_SRC_2_EN_W_NAME, + GENERAL_ASRC_EN_ON, GENERAL2_ASRC_EN_ON_SFT, 0, + mtk_hw_src_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_INPUT("HW SRC 1 Out Endpoint"), + SND_SOC_DAPM_INPUT("HW SRC 2 Out Endpoint"), + SND_SOC_DAPM_OUTPUT("HW SRC 1 In Endpoint"), + SND_SOC_DAPM_OUTPUT("HW SRC 2 In Endpoint"), +}; + +static int mtk_afe_src_en_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_src_priv *src_priv; + + if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0) + src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_1]; + else + src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_2]; + + dev_dbg(afe->dev, + "%s(), source %s, sink %s, dl_rate %d, ul_rate %d\n", + __func__, source->name, sink->name, + src_priv->dl_rate, src_priv->ul_rate); + + return (src_priv->dl_rate > 0 && src_priv->ul_rate > 0) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_src_routes[] = { + {"HW_SRC_1_IN_CH1", "DL1_CH1 Switch", "DL1"}, + {"HW_SRC_1_IN_CH2", "DL1_CH2 Switch", "DL1"}, + {"HW_SRC_2_IN_CH1", "DL1_CH1 Switch", "DL1"}, + {"HW_SRC_2_IN_CH2", "DL1_CH2 Switch", "DL1"}, + {"HW_SRC_1_IN_CH1", "DL2_CH1 Switch", "DL2"}, + {"HW_SRC_1_IN_CH2", "DL2_CH2 Switch", "DL2"}, + {"HW_SRC_2_IN_CH1", "DL2_CH1 Switch", "DL2"}, + {"HW_SRC_2_IN_CH2", "DL2_CH2 Switch", "DL2"}, + {"HW_SRC_1_IN_CH1", "DL3_CH1 Switch", "DL3"}, + {"HW_SRC_1_IN_CH2", "DL3_CH2 Switch", "DL3"}, + {"HW_SRC_2_IN_CH1", "DL3_CH1 Switch", "DL3"}, + {"HW_SRC_2_IN_CH2", "DL3_CH2 Switch", "DL3"}, + {"HW_SRC_1_IN_CH1", "DL6_CH1 Switch", "DL6"}, + {"HW_SRC_1_IN_CH2", "DL6_CH2 Switch", "DL6"}, + {"HW_SRC_2_IN_CH1", "DL6_CH1 Switch", "DL6"}, + {"HW_SRC_2_IN_CH2", "DL6_CH2 Switch", "DL6"}, + {"HW_SRC_1_IN_CH1", "DL5_CH1 Switch", "DL5"}, + {"HW_SRC_1_IN_CH2", "DL5_CH2 Switch", "DL5"}, + {"HW_SRC_2_IN_CH1", "DL5_CH1 Switch", "DL5"}, + {"HW_SRC_2_IN_CH2", "DL5_CH2 Switch", "DL5"}, + {"HW_SRC_1_IN_CH1", "DL4_CH1 Switch", "DL4"}, + {"HW_SRC_1_IN_CH2", "DL4_CH2 Switch", "DL4"}, + {"HW_SRC_2_IN_CH1", "DL4_CH1 Switch", "DL4"}, + {"HW_SRC_2_IN_CH2", "DL4_CH2 Switch", "DL4"}, + + {"HW_SRC_1_In", NULL, "HW_SRC_1_IN_CH1"}, + {"HW_SRC_1_In", NULL, "HW_SRC_1_IN_CH2"}, + + {"HW_SRC_2_In", NULL, "HW_SRC_2_IN_CH1"}, + {"HW_SRC_2_In", NULL, "HW_SRC_2_IN_CH2"}, + + {"HW_SRC_1_In", NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect}, + {"HW_SRC_1_Out", NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect}, + {"HW_SRC_2_In", NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect}, + {"HW_SRC_2_Out", NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect}, + + {"HW SRC 1 In Endpoint", NULL, "HW_SRC_1_In"}, + {"HW SRC 2 In Endpoint", NULL, "HW_SRC_2_In"}, + {"HW_SRC_1_Out", NULL, "HW SRC 1 Out Endpoint"}, + {"HW_SRC_2_Out", NULL, "HW SRC 2 Out Endpoint"}, +}; + +/* dai ops */ +static int mtk_dai_src_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int id = dai->id; + struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; + unsigned int sft, mask; + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, id); + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, id, substream->stream, rate); + + /* rate */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + src_priv->dl_rate = rate; + if (id == MT8186_DAI_SRC_1) { + sft = GENERAL1_ASRCIN_MODE_SFT; + mask = GENERAL1_ASRCIN_MODE_MASK; + } else { + sft = GENERAL2_ASRCIN_MODE_SFT; + mask = GENERAL2_ASRCIN_MODE_MASK; + } + } else { + src_priv->ul_rate = rate; + if (id == MT8186_DAI_SRC_1) { + sft = GENERAL1_ASRCOUT_MODE_SFT; + mask = GENERAL1_ASRCOUT_MODE_MASK; + } else { + sft = GENERAL2_ASRCOUT_MODE_SFT; + mask = GENERAL2_ASRCOUT_MODE_MASK; + } + } + + regmap_update_bits(afe->regmap, GENERAL_ASRC_MODE, mask << sft, rate_reg << sft); + + return 0; +} + +static int mtk_dai_src_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int id = dai->id; + struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; + + dev_dbg(afe->dev, "%s(), id %d, stream %d\n", + __func__, id, substream->stream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + src_priv->dl_rate = 0; + else + src_priv->ul_rate = 0; + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_src_ops = { + .hw_params = mtk_dai_src_hw_params, + .hw_free = mtk_dai_src_hw_free, +}; + +/* dai driver */ +#define MTK_SRC_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_SRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_src_driver[] = { + { + .name = "HW_SRC_1", + .id = MT8186_DAI_SRC_1, + .playback = { + .stream_name = "HW_SRC_1_In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_SRC_RATES, + .formats = MTK_SRC_FORMATS, + }, + .capture = { + .stream_name = "HW_SRC_1_Out", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_SRC_RATES, + .formats = MTK_SRC_FORMATS, + }, + .ops = &mtk_dai_src_ops, + }, + { + .name = "HW_SRC_2", + .id = MT8186_DAI_SRC_2, + .playback = { + .stream_name = "HW_SRC_2_In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_SRC_RATES, + .formats = MTK_SRC_FORMATS, + }, + .capture = { + .stream_name = "HW_SRC_2_Out", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_SRC_RATES, + .formats = MTK_SRC_FORMATS, + }, + .ops = &mtk_dai_src_ops, + }, +}; + +int mt8186_dai_src_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_src_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_src_driver); + + dai->dapm_widgets = mtk_dai_src_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_src_widgets); + dai->dapm_routes = mtk_dai_src_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_src_routes); + + /* set dai priv */ + ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_1, + sizeof(struct mtk_afe_src_priv), NULL); + if (ret) + return ret; + + ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_2, + sizeof(struct mtk_afe_src_priv), NULL); + if (ret) + return ret; + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c new file mode 100644 index 000000000000..c6ead7c252f0 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c @@ -0,0 +1,698 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI TDM Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/regmap.h> +#include <sound/pcm_params.h> + +#include "mt8186-afe-clk.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +#define TDM_HD_EN_W_NAME "TDM_HD_EN" +#define TDM_MCLK_EN_W_NAME "TDM_MCLK_EN" +#define MTK_AFE_TDM_KCONTROL_NAME "TDM_HD_Mux" + +struct mtk_afe_tdm_priv { + unsigned int id; + unsigned int rate; /* for determine which apll to use */ + unsigned int bck_invert; + unsigned int lck_invert; + unsigned int lrck_width; + unsigned int mclk_id; + unsigned int mclk_multiple; /* according to sample rate */ + unsigned int mclk_rate; + unsigned int mclk_apll; + unsigned int tdm_mode; + unsigned int data_mode; + unsigned int slave_mode; + unsigned int low_jitter_en; +}; + +enum { + TDM_IN_I2S = 0, + TDM_IN_LJ = 1, + TDM_IN_RJ = 2, + TDM_IN_DSP_A = 4, + TDM_IN_DSP_B = 5, +}; + +enum { + TDM_DATA_ONE_PIN = 0, + TDM_DATA_MULTI_PIN, +}; + +enum { + TDM_BCK_NON_INV = 0, + TDM_BCK_INV = 1, +}; + +enum { + TDM_LCK_NON_INV = 0, + TDM_LCK_INV = 1, +}; + +static unsigned int get_tdm_lrck_width(snd_pcm_format_t format, + unsigned int mode) +{ + if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B) + return 0; + + return snd_pcm_format_physical_width(format) - 1; +} + +static unsigned int get_tdm_ch_fixup(unsigned int channels) +{ + if (channels > 4) + return 8; + else if (channels > 2) + return 4; + + return 2; +} + +static unsigned int get_tdm_ch_per_sdata(unsigned int mode, + unsigned int channels) +{ + if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B) + return get_tdm_ch_fixup(channels); + + return 2; +} + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_TDM_MCK_EN, + SUPPLY_SEQ_TDM_HD_EN, + SUPPLY_SEQ_TDM_EN, +}; + +static int get_tdm_id_by_name(const char *name) +{ + return MT8186_DAI_TDM_IN; +} + +static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, tdm_priv->id, 0); + break; + case SND_SOC_DAPM_POST_PMD: + mt8186_afe_gpio_request(afe->dev, false, tdm_priv->id, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", + __func__, w->name, event, dai_id); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + tdm_priv->mclk_rate = 0; + mt8186_mck_disable(afe, tdm_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +/* dai component */ +/* tdm virtual mux to output widget */ +static const char * const tdm_mux_map[] = { + "Normal", "Dummy_Widget", +}; + +static int tdm_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(tdm_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + tdm_mux_map, + tdm_mux_map_value); + +static const struct snd_kcontrol_new tdm_in_mux_control = + SOC_DAPM_ENUM("TDM In Select", tdm_mux_map_enum); + +static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { + SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"), + + SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN, + ETDM_IN1_CON0, ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT, + 0, mtk_tdm_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* tdm hd en */ + SND_SOC_DAPM_SUPPLY_S(TDM_HD_EN_W_NAME, SUPPLY_SEQ_TDM_HD_EN, + ETDM_IN1_CON2, ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT, + 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S(TDM_MCLK_EN_W_NAME, SUPPLY_SEQ_TDM_MCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_mck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("TDM_DUMMY_IN"), + + SND_SOC_DAPM_MUX("TDM_In_Mux", + SND_SOC_NOPM, 0, 0, &tdm_in_mux_control), +}; + +static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return 0; + } + + return (tdm_priv->mclk_rate > 0) ? 1 : 0; +} + +static int mtk_afe_tdm_mclk_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + int cur_apll; + + /* which apll */ + cur_apll = mt8186_get_apll_by_name(afe, source->name); + + return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return 0; + } + + return tdm_priv->low_jitter_en; +} + +static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + int cur_apll; + int tdm_need_apll; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8186_get_apll_by_name(afe, source->name); + + /* choose APLL from tdm rate */ + tdm_need_apll = mt8186_get_apll_by_rate(afe, tdm_priv->rate); + + return (tdm_need_apll == cur_apll) ? 1 : 0; +} + +/* low jitter control */ +static const char * const mt8186_tdm_hd_str[] = { + "Normal", "Low_Jitter" +}; + +static const struct soc_enum mt8186_tdm_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_tdm_hd_str), + mt8186_tdm_hd_str), +}; + +static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(kcontrol->id.name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en; + + return 0; +} + +static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(kcontrol->id.name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int hd_en; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + hd_en = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, hd_en); + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + if (tdm_priv->low_jitter_en == hd_en) + return 0; + + tdm_priv->low_jitter_en = hd_en; + + return 1; +} + +static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = { + SOC_ENUM_EXT(MTK_AFE_TDM_KCONTROL_NAME, mt8186_tdm_enum[0], + mt8186_tdm_hd_get, mt8186_tdm_hd_set), +}; + +static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { + {"TDM IN", NULL, "aud_tdm_clk"}, + {"TDM IN", NULL, "TDM_EN"}, + {"TDM IN", NULL, TDM_HD_EN_W_NAME, mtk_afe_tdm_hd_connect}, + {TDM_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, + {TDM_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, + + {"TDM IN", NULL, TDM_MCLK_EN_W_NAME, mtk_afe_tdm_mclk_connect}, + {TDM_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_mclk_apll_connect}, + {TDM_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_mclk_apll_connect}, + + /* allow tdm on without codec on */ + {"TDM IN", NULL, "TDM_In_Mux"}, + {"TDM_In_Mux", "Dummy_Widget", "TDM_DUMMY_IN"}, +}; + +/* dai ops */ +static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, + struct mtk_afe_tdm_priv *tdm_priv, + int freq) +{ + int apll; + int apll_rate; + + apll = mt8186_get_apll_by_rate(afe, freq); + apll_rate = mt8186_get_apll_rate(afe, apll); + + if (!freq || freq > apll_rate) { + dev_err(afe->dev, + "%s(), freq(%d Hz) invalid\n", __func__, freq); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_err(afe->dev, + "%s(), APLL cannot generate %d Hz", __func__, freq); + return -EINVAL; + } + + tdm_priv->mclk_rate = freq; + tdm_priv->mclk_apll = apll; + + return 0; +} + +static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int tdm_id = dai->id; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int tdm_mode = tdm_priv->tdm_mode; + unsigned int data_mode = tdm_priv->data_mode; + unsigned int rate = params_rate(params); + unsigned int channels = params_channels(params); + snd_pcm_format_t format = params_format(params); + unsigned int bit_width = + snd_pcm_format_physical_width(format); + unsigned int tdm_channels = (data_mode == TDM_DATA_ONE_PIN) ? + get_tdm_ch_per_sdata(tdm_mode, channels) : 2; + unsigned int lrck_width = + get_tdm_lrck_width(format, tdm_mode); + unsigned int tdm_con = 0; + bool slave_mode = tdm_priv->slave_mode; + bool lrck_inv = tdm_priv->lck_invert; + bool bck_inv = tdm_priv->bck_invert; + unsigned int tran_rate; + unsigned int tran_relatch_rate; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + tdm_priv->rate = rate; + + tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id); + tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate); + + /* calculate mclk_rate, if not set explicitly */ + if (!tdm_priv->mclk_rate) { + tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; + mtk_dai_tdm_cal_mclk(afe, + tdm_priv, + tdm_priv->mclk_rate); + } + + /* ETDM_IN1_CON0 */ + tdm_con |= slave_mode << ETDM_IN1_CON0_REG_SLAVE_MODE_SFT; + tdm_con |= tdm_mode << ETDM_IN1_CON0_REG_FMT_SFT; + tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_BIT_LENGTH_SFT; + tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_WORD_LENGTH_SFT; + tdm_con |= (tdm_channels - 1) << ETDM_IN1_CON0_REG_CH_NUM_SFT; + /* need to disable sync mode otherwise this may cause latch data error */ + tdm_con |= 0 << ETDM_IN1_CON0_REG_SYNC_MODE_SFT; + /* relatch 1x en clock fix to h26m */ + tdm_con |= 0 << ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT; + regmap_update_bits(afe->regmap, ETDM_IN1_CON0, ETDM_IN_CON0_CTRL_MASK, tdm_con); + + /* ETDM_IN1_CON1 */ + tdm_con = 0; + tdm_con |= 0 << ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT; + tdm_con |= 1 << ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT; + tdm_con |= (lrck_width - 1) << ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT; + regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con); + + /* ETDM_IN1_CON3 */ + tdm_con = 0; + tdm_con = ETDM_IN_CON3_FS(tran_rate); + regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con); + + /* ETDM_IN1_CON4 */ + tdm_con = 0; + tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate); + if (slave_mode) { + if (lrck_inv) + tdm_con |= ETDM_IN_CON4_CON0_SLAVE_LRCK_INV; + if (bck_inv) + tdm_con |= ETDM_IN_CON4_CON0_SLAVE_BCK_INV; + } else { + if (lrck_inv) + tdm_con |= ETDM_IN_CON4_CON0_MASTER_LRCK_INV; + if (bck_inv) + tdm_con |= ETDM_IN_CON4_CON0_MASTER_BCK_INV; + } + regmap_update_bits(afe->regmap, ETDM_IN1_CON4, ETDM_IN_CON4_CTRL_MASK, tdm_con); + + /* ETDM_IN1_CON2 */ + tdm_con = 0; + if (data_mode == TDM_DATA_MULTI_PIN) { + tdm_con |= ETDM_IN_CON2_MULTI_IP_2CH_MODE; + tdm_con |= ETDM_IN_CON2_MULTI_IP_CH(channels); + } + regmap_update_bits(afe->regmap, ETDM_IN1_CON2, ETDM_IN_CON2_CTRL_MASK, tdm_con); + + /* ETDM_IN1_CON8 */ + tdm_con = 0; + if (slave_mode) { + tdm_con |= 1 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT; + tdm_con |= 0 << ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT; + tdm_con |= ETDM_IN_CON8_FS(tran_relatch_rate); + } else { + tdm_con |= 0 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT; + } + regmap_update_bits(afe->regmap, ETDM_IN1_CON8, ETDM_IN_CON8_CTRL_MASK, tdm_con); + + return 0; +} + +static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_IN) { + dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); + + return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); +} + +static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + /* DAI mode*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_priv->tdm_mode = TDM_IN_I2S; + tdm_priv->data_mode = TDM_DATA_MULTI_PIN; + break; + case SND_SOC_DAIFMT_LEFT_J: + tdm_priv->tdm_mode = TDM_IN_LJ; + tdm_priv->data_mode = TDM_DATA_MULTI_PIN; + break; + case SND_SOC_DAIFMT_RIGHT_J: + tdm_priv->tdm_mode = TDM_IN_RJ; + tdm_priv->data_mode = TDM_DATA_MULTI_PIN; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_priv->tdm_mode = TDM_IN_DSP_A; + tdm_priv->data_mode = TDM_DATA_ONE_PIN; + break; + case SND_SOC_DAIFMT_DSP_B: + tdm_priv->tdm_mode = TDM_IN_DSP_B; + tdm_priv->data_mode = TDM_DATA_ONE_PIN; + break; + default: + dev_err(afe->dev, "%s(), invalid DAIFMT_FORMAT_MASK", __func__); + return -EINVAL; + } + + /* DAI clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + default: + dev_err(afe->dev, "%s(), invalid DAIFMT_INV_MASK", __func__); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: + tdm_priv->slave_mode = false; + break; + case SND_SOC_DAIFMT_BC_FC: + tdm_priv->slave_mode = true; + break; + default: + dev_err(afe->dev, "%s(), invalid DAIFMT_CLOCK_PROVIDER_MASK", + __func__); + return -EINVAL; + } + + return 0; +} + +static int mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + dev_dbg(dai->dev, "%s %d slot_width %d\n", __func__, dai->id, slot_width); + + tdm_priv->lrck_width = slot_width; + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { + .hw_params = mtk_dai_tdm_hw_params, + .set_sysclk = mtk_dai_tdm_set_sysclk, + .set_fmt = mtk_dai_tdm_set_fmt, + .set_tdm_slot = mtk_dai_tdm_set_tdm_slot, +}; + +/* dai driver */ +#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { + { + .name = "TDM IN", + .id = MT8186_DAI_TDM_IN, + .capture = { + .stream_name = "TDM IN", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_TDM_RATES, + .formats = MTK_TDM_FORMATS, + }, + .ops = &mtk_dai_tdm_ops, + }, +}; + +static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe) +{ + struct mtk_afe_tdm_priv *tdm_priv; + + tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), + GFP_KERNEL); + if (!tdm_priv) + return NULL; + + tdm_priv->mclk_multiple = 512; + tdm_priv->mclk_id = MT8186_TDM_MCK; + tdm_priv->id = MT8186_DAI_TDM_IN; + + return tdm_priv; +} + +int mt8186_dai_tdm_register(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv; + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_tdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); + + dai->controls = mtk_dai_tdm_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls); + dai->dapm_widgets = mtk_dai_tdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); + dai->dapm_routes = mtk_dai_tdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); + + tdm_priv = init_tdm_priv_data(afe); + if (!tdm_priv) + return -ENOMEM; + + afe_priv->dai_priv[MT8186_DAI_TDM_IN] = tdm_priv; + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-interconnection.h b/sound/soc/mediatek/mt8186/mt8186-interconnection.h new file mode 100644 index 000000000000..5b188d93ebd3 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-interconnection.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Mediatek MT8186 audio driver interconnection definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT8186_INTERCONNECTION_H_ +#define _MT8186_INTERCONNECTION_H_ + +/* in port define */ +#define I_I2S0_CH1 0 +#define I_I2S0_CH2 1 +#define I_ADDA_UL_CH1 3 +#define I_ADDA_UL_CH2 4 +#define I_DL1_CH1 5 +#define I_DL1_CH2 6 +#define I_DL2_CH1 7 +#define I_DL2_CH2 8 +#define I_PCM_1_CAP_CH1 9 +#define I_GAIN1_OUT_CH1 10 +#define I_GAIN1_OUT_CH2 11 +#define I_GAIN2_OUT_CH1 12 +#define I_GAIN2_OUT_CH2 13 +#define I_PCM_2_CAP_CH1 14 +#define I_ADDA_UL_CH3 17 +#define I_ADDA_UL_CH4 18 +#define I_DL12_CH1 19 +#define I_DL12_CH2 20 +#define I_DL12_CH3 5 +#define I_DL12_CH4 6 +#define I_PCM_2_CAP_CH2 21 +#define I_PCM_1_CAP_CH2 22 +#define I_DL3_CH1 23 +#define I_DL3_CH2 24 +#define I_I2S2_CH1 25 +#define I_I2S2_CH2 26 +#define I_I2S2_CH3 27 +#define I_I2S2_CH4 28 + +/* in port define >= 32 */ +#define I_32_OFFSET 32 +#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET) +#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET) +#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET) +#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET) +#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET) +#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET) +#define I_DL4_CH1 (40 - I_32_OFFSET) +#define I_DL4_CH2 (41 - I_32_OFFSET) +#define I_DL5_CH1 (42 - I_32_OFFSET) +#define I_DL5_CH2 (43 - I_32_OFFSET) +#define I_DL6_CH1 (44 - I_32_OFFSET) +#define I_DL6_CH2 (45 - I_32_OFFSET) +#define I_DL7_CH1 (46 - I_32_OFFSET) +#define I_DL7_CH2 (47 - I_32_OFFSET) +#define I_DL8_CH1 (48 - I_32_OFFSET) +#define I_DL8_CH2 (49 - I_32_OFFSET) +#define I_TDM_IN_CH1 (56 - I_32_OFFSET) +#define I_TDM_IN_CH2 (57 - I_32_OFFSET) +#define I_TDM_IN_CH3 (58 - I_32_OFFSET) +#define I_TDM_IN_CH4 (59 - I_32_OFFSET) +#define I_TDM_IN_CH5 (60 - I_32_OFFSET) +#define I_TDM_IN_CH6 (61 - I_32_OFFSET) +#define I_TDM_IN_CH7 (62 - I_32_OFFSET) +#define I_TDM_IN_CH8 (63 - I_32_OFFSET) + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-misc-control.c b/sound/soc/mediatek/mt8186/mt8186-misc-control.c new file mode 100644 index 000000000000..2317de8c44c0 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-misc-control.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio Misc Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "../common/mtk-afe-fe-dai.h" +#include "../common/mtk-afe-platform-driver.h" +#include "mt8186-afe-common.h" + +static const char * const mt8186_sgen_mode_str[] = { + "I0I1", "I2", "I3I4", "I5I6", + "I7I8", "I9I22", "I10I11", "I12I13", + "I14I21", "I15I16", "I17I18", "I19I20", + "I23I24", "I25I26", "I27I28", "I33", + "I34I35", "I36I37", "I38I39", "I40I41", + "I42I43", "I44I45", "I46I47", "I48I49", + "I56I57", "I58I59", "I60I61", "I62I63", + "O0O1", "O2", "O3O4", "O5O6", + "O7O8", "O9O10", "O11", "O12", + "O13O14", "O15O16", "O17O18", "O19O20", + "O21O22", "O23O24", "O25", "O28O29", + "O34", "O35", "O32O33", "O36O37", + "O38O39", "O30O31", "O40O41", "O42O43", + "O44O45", "O46O47", "O48O49", "O50O51", + "O58O59", "O60O61", "O62O63", "O64O65", + "O66O67", "O68O69", "O26O27", "OFF", +}; + +static const int mt8186_sgen_mode_idx[] = { + 0, 2, 4, 6, + 8, 22, 10, 12, + 14, -1, 18, 20, + 24, 26, 28, 33, + 34, 36, 38, 40, + 42, 44, 46, 48, + 56, 58, 60, 62, + 128, 130, 132, 134, + 135, 138, 139, 140, + 142, 144, 166, 148, + 150, 152, 153, 156, + 162, 163, 160, 164, + 166, -1, 168, 170, + 172, 174, 176, 178, + 186, 188, 190, 192, + 194, 196, -1, -1, +}; + +static const char * const mt8186_sgen_rate_str[] = { + "8K", "11K", "12K", "16K", + "22K", "24K", "32K", "44K", + "48K", "88k", "96k", "176k", + "192k" +}; + +static const int mt8186_sgen_rate_idx[] = { + 0, 1, 2, 4, + 5, 6, 8, 9, + 10, 11, 12, 13, + 14 +}; + +/* this order must match reg bit amp_div_ch1/2 */ +static const char * const mt8186_sgen_amp_str[] = { + "1/128", "1/64", "1/32", "1/16", "1/8", "1/4", "1/2", "1" }; + +static int mt8186_sgen_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->sgen_mode; + + return 0; +} + +static int mt8186_sgen_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int mode; + int mode_idx; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + mode = ucontrol->value.integer.value[0]; + mode_idx = mt8186_sgen_mode_idx[mode]; + + dev_dbg(afe->dev, "%s(), mode %d, mode_idx %d\n", + __func__, mode, mode_idx); + + if (mode == afe_priv->sgen_mode) + return 0; + + if (mode_idx >= 0) { + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2, + INNER_LOOP_BACK_MODE_MASK_SFT, + mode_idx << INNER_LOOP_BACK_MODE_SFT); + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0, + DAC_EN_MASK_SFT, BIT(DAC_EN_SFT)); + } else { + /* disable sgen */ + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0, + DAC_EN_MASK_SFT, 0); + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2, + INNER_LOOP_BACK_MODE_MASK_SFT, + 0x3f << INNER_LOOP_BACK_MODE_SFT); + } + + afe_priv->sgen_mode = mode; + + return 1; +} + +static int mt8186_sgen_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->sgen_rate; + + return 0; +} + +static int mt8186_sgen_rate_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int rate; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + rate = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), rate %d\n", __func__, rate); + + if (rate == afe_priv->sgen_rate) + return 0; + + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0, + SINE_MODE_CH1_MASK_SFT, + mt8186_sgen_rate_idx[rate] << SINE_MODE_CH1_SFT); + + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0, + SINE_MODE_CH2_MASK_SFT, + mt8186_sgen_rate_idx[rate] << SINE_MODE_CH2_SFT); + + afe_priv->sgen_rate = rate; + + return 1; +} + +static int mt8186_sgen_amplitude_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->sgen_amplitude; + return 0; +} + +static int mt8186_sgen_amplitude_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int amplitude; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + amplitude = ucontrol->value.integer.value[0]; + if (amplitude > AMP_DIV_CH1_MASK) { + dev_err(afe->dev, "%s(), amplitude %d invalid\n", + __func__, amplitude); + return -EINVAL; + } + + dev_dbg(afe->dev, "%s(), amplitude %d\n", __func__, amplitude); + + if (amplitude == afe_priv->sgen_amplitude) + return 0; + + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0, + AMP_DIV_CH1_MASK_SFT, + amplitude << AMP_DIV_CH1_SFT); + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0, + AMP_DIV_CH2_MASK_SFT, + amplitude << AMP_DIV_CH2_SFT); + + afe_priv->sgen_amplitude = amplitude; + + return 1; +} + +static const struct soc_enum mt8186_afe_sgen_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_mode_str), + mt8186_sgen_mode_str), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_rate_str), + mt8186_sgen_rate_str), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_amp_str), + mt8186_sgen_amp_str), +}; + +static const struct snd_kcontrol_new mt8186_afe_sgen_controls[] = { + SOC_ENUM_EXT("Audio_SineGen_Switch", mt8186_afe_sgen_enum[0], + mt8186_sgen_get, mt8186_sgen_set), + SOC_ENUM_EXT("Audio_SineGen_SampleRate", mt8186_afe_sgen_enum[1], + mt8186_sgen_rate_get, mt8186_sgen_rate_set), + SOC_ENUM_EXT("Audio_SineGen_Amplitude", mt8186_afe_sgen_enum[2], + mt8186_sgen_amplitude_get, mt8186_sgen_amplitude_set), + SOC_SINGLE("Audio_SineGen_Mute_Ch1", AFE_SINEGEN_CON0, + MUTE_SW_CH1_MASK_SFT, MUTE_SW_CH1_MASK, 0), + SOC_SINGLE("Audio_SineGen_Mute_Ch2", AFE_SINEGEN_CON0, + MUTE_SW_CH2_MASK_SFT, MUTE_SW_CH2_MASK, 0), + SOC_SINGLE("Audio_SineGen_Freq_Div_Ch1", AFE_SINEGEN_CON0, + FREQ_DIV_CH1_SFT, FREQ_DIV_CH1_MASK, 0), + SOC_SINGLE("Audio_SineGen_Freq_Div_Ch2", AFE_SINEGEN_CON0, + FREQ_DIV_CH2_SFT, FREQ_DIV_CH2_MASK, 0), +}; + +int mt8186_add_misc_control(struct snd_soc_component *component) +{ + snd_soc_add_component_controls(component, + mt8186_afe_sgen_controls, + ARRAY_SIZE(mt8186_afe_sgen_controls)); + + return 0; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-reg.h b/sound/soc/mediatek/mt8186/mt8186-reg.h new file mode 100644 index 000000000000..53c3eb7283d8 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-reg.h @@ -0,0 +1,2913 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-reg.h -- Mediatek 8186 audio driver reg definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu <jiaxin.yu@mediatek.com> + */ + +#ifndef _MT8186_REG_H_ +#define _MT8186_REG_H_ + +/* reg bit enum */ +enum { + MT8186_MEMIF_PBUF_SIZE_32_BYTES, + MT8186_MEMIF_PBUF_SIZE_64_BYTES, + MT8186_MEMIF_PBUF_SIZE_128_BYTES, + MT8186_MEMIF_PBUF_SIZE_256_BYTES, + MT8186_MEMIF_PBUF_SIZE_NUM, +}; + +/***************************************************************************** + * R E G I S T E R D E F I N I T I O N + *****************************************************************************/ +/* AUDIO_TOP_CON0 */ +#define RESERVED_SFT 31 +#define RESERVED_MASK_SFT BIT(31) +#define AHB_IDLE_EN_INT_SFT 30 +#define AHB_IDLE_EN_INT_MASK_SFT BIT(30) +#define AHB_IDLE_EN_EXT_SFT 29 +#define AHB_IDLE_EN_EXT_MASK_SFT BIT(29) +#define PDN_NLE_SFT 28 +#define PDN_NLE_MASK_SFT BIT(28) +#define PDN_TML_SFT 27 +#define PDN_TML_MASK_SFT BIT(27) +#define PDN_DAC_PREDIS_SFT 26 +#define PDN_DAC_PREDIS_MASK_SFT BIT(26) +#define PDN_DAC_SFT 25 +#define PDN_DAC_MASK_SFT BIT(25) +#define PDN_ADC_SFT 24 +#define PDN_ADC_MASK_SFT BIT(24) +#define PDN_TDM_CK_SFT 20 +#define PDN_TDM_CK_MASK_SFT BIT(20) +#define PDN_APLL_TUNER_SFT 19 +#define PDN_APLL_TUNER_MASK_SFT BIT(19) +#define PDN_APLL2_TUNER_SFT 18 +#define PDN_APLL2_TUNER_MASK_SFT BIT(18) +#define APB3_SEL_SFT 14 +#define APB3_SEL_MASK_SFT BIT(14) +#define APB_R2T_SFT 13 +#define APB_R2T_MASK_SFT BIT(13) +#define APB_W2T_SFT 12 +#define APB_W2T_MASK_SFT BIT(12) +#define PDN_24M_SFT 9 +#define PDN_24M_MASK_SFT BIT(9) +#define PDN_22M_SFT 8 +#define PDN_22M_MASK_SFT BIT(8) +#define PDN_AFE_SFT 2 +#define PDN_AFE_MASK_SFT BIT(2) + +/* AUDIO_TOP_CON1 */ +#define PDN_3RD_DAC_HIRES_SFT 31 +#define PDN_3RD_DAC_HIRES_MASK_SFT BIT(31) +#define PDN_3RD_DAC_TML_SFT 30 +#define PDN_3RD_DAC_TML_MASK_SFT BIT(30) +#define PDN_3RD_DAC_PREDIS_SFT 29 +#define PDN_3RD_DAC_PREDIS_MASK_SFT BIT(29) +#define PDN_3RD_DAC_SFT 28 +#define PDN_3RD_DAC_MASK_SFT BIT(28) +#define I2S_SOFT_RST5_SFT 22 +#define I2S_SOFT_RST5_MASK_SFT BIT(22) +#define PDN_ADDA6_ADC_HIRES_SFT 21 +#define PDN_ADDA6_ADC_HIRES_MASK_SFT BIT(21) +#define PDN_ADDA6_ADC_SFT 20 +#define PDN_ADDA6_ADC_MASK_SFT BIT(20) +#define PDN_ADC_HIRES_TML_SFT 17 +#define PDN_ADC_HIRES_TML_MASK_SFT BIT(17) +#define PDN_ADC_HIRES_SFT 16 +#define PDN_ADC_HIRES_MASK_SFT BIT(16) +#define PDN_DAC_HIRES_SFT 15 +#define PDN_DAC_HIRES_MASK_SFT BIT(15) +#define PDN_GENERAL2_ASRC_SFT 14 +#define PDN_GENERAL2_ASRC_MASK_SFT BIT(14) +#define PDN_GENERAL1_ASRC_SFT 13 +#define PDN_GENERAL1_ASRC_MASK_SFT BIT(13) +#define PDN_CONNSYS_I2S_ASRC_SFT 12 +#define PDN_CONNSYS_I2S_ASRC_MASK_SFT BIT(12) +#define I2S4_BCLK_SW_CG_SFT 7 +#define I2S4_BCLK_SW_CG_MASK_SFT BIT(7) +#define I2S3_BCLK_SW_CG_SFT 6 +#define I2S3_BCLK_SW_CG_MASK_SFT BIT(6) +#define I2S2_BCLK_SW_CG_SFT 5 +#define I2S2_BCLK_SW_CG_MASK_SFT BIT(5) +#define I2S1_BCLK_SW_CG_SFT 4 +#define I2S1_BCLK_SW_CG_MASK_SFT BIT(4) +#define I2S_SOFT_RST2_SFT 2 +#define I2S_SOFT_RST2_MASK_SFT BIT(2) +#define I2S_SOFT_RST_SFT 1 +#define I2S_SOFT_RST_MASK_SFT BIT(1) + +/* AUDIO_TOP_CON3 */ +#define BUSY_SFT 31 +#define BUSY_MASK_SFT BIT(31) +#define OS_DISABLE_SFT 30 +#define OS_DISABLE_MASK_SFT BIT(30) +#define CG_DISABLE_SFT 29 +#define CG_DISABLE_MASK_SFT BIT(29) +#define CLEAR_FLAG_SFT 0 +#define CLEAR_FLAG_MASK_SFT BIT(0) + +/* AFE_DAC_CON0 */ +#define VUL12_ON_SFT 31 +#define VUL12_ON_MASK_SFT BIT(31) +#define MOD_DAI_ON_SFT 30 +#define MOD_DAI_ON_MASK_SFT BIT(30) +#define DAI_ON_SFT 29 +#define DAI_ON_MASK_SFT BIT(29) +#define DAI2_ON_SFT 28 +#define DAI2_ON_MASK_SFT BIT(28) +#define VUL6_ON_SFT 23 +#define VUL6_ON_MASK_SFT BIT(23) +#define VUL5_ON_SFT 22 +#define VUL5_ON_MASK_SFT BIT(22) +#define VUL4_ON_SFT 21 +#define VUL4_ON_MASK_SFT BIT(21) +#define VUL3_ON_SFT 20 +#define VUL3_ON_MASK_SFT BIT(20) +#define VUL2_ON_SFT 19 +#define VUL2_ON_MASK_SFT BIT(19) +#define VUL_ON_SFT 18 +#define VUL_ON_MASK_SFT BIT(18) +#define AWB2_ON_SFT 17 +#define AWB2_ON_MASK_SFT BIT(17) +#define AWB_ON_SFT 16 +#define AWB_ON_MASK_SFT BIT(16) +#define DL12_ON_SFT 15 +#define DL12_ON_MASK_SFT BIT(15) +#define DL8_ON_SFT 11 +#define DL8_ON_MASK_SFT BIT(11) +#define DL7_ON_SFT 10 +#define DL7_ON_MASK_SFT BIT(10) +#define DL6_ON_SFT 9 +#define DL6_ON_MASK_SFT BIT(9) +#define DL5_ON_SFT 8 +#define DL5_ON_MASK_SFT BIT(8) +#define DL4_ON_SFT 7 +#define DL4_ON_MASK_SFT BIT(7) +#define DL3_ON_SFT 6 +#define DL3_ON_MASK_SFT BIT(6) +#define DL2_ON_SFT 5 +#define DL2_ON_MASK_SFT BIT(5) +#define DL1_ON_SFT 4 +#define DL1_ON_MASK_SFT BIT(4) +#define AUDIO_AFE_ON_SFT 0 +#define AUDIO_AFE_ON_MASK_SFT BIT(0) + +/* AFE_DAC_MON */ +#define AFE_ON_RETM_SFT 0 +#define AFE_ON_RETM_MASK_SFT BIT(0) + +/* AFE_I2S_CON */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK_SFT BIT(30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK_SFT BIT(29) +#define I2SIN_PAD_SEL_SFT 28 +#define I2SIN_PAD_SEL_MASK_SFT BIT(28) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK_SFT BIT(20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17) +#define I2S1_HD_EN_SFT 12 +#define I2S1_HD_EN_MASK_SFT BIT(12) +#define I2S_OUT_MODE_SFT 8 +#define I2S_OUT_MODE_MASK_SFT GENMASK(11, 8) +#define INV_PAD_CTRL_SFT 7 +#define INV_PAD_CTRL_MASK_SFT BIT(7) +#define I2S_BYPSRC_SFT 6 +#define I2S_BYPSRC_MASK_SFT BIT(6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK_SFT BIT(5) +#define I2S_FMT_SFT 3 +#define I2S_FMT_MASK_SFT BIT(3) +#define I2S_SRC_SFT 2 +#define I2S_SRC_MASK_SFT BIT(2) +#define I2S_WLEN_SFT 1 +#define I2S_WLEN_MASK_SFT BIT(1) +#define I2S_EN_SFT 0 +#define I2S_EN_MASK_SFT BIT(0) + +/* AFE_I2S_CON1 */ +#define I2S2_LR_SWAP_SFT 31 +#define I2S2_LR_SWAP_MASK_SFT BIT(31) +#define I2S2_SEL_O19_O20_SFT 18 +#define I2S2_SEL_O19_O20_MASK_SFT BIT(18) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17) +#define I2S2_SEL_O03_O04_SFT 16 +#define I2S2_SEL_O03_O04_MASK_SFT BIT(16) +#define I2S2_HD_EN_SFT 12 +#define I2S2_HD_EN_MASK_SFT BIT(12) +#define I2S2_OUT_MODE_SFT 8 +#define I2S2_OUT_MODE_MASK_SFT GENMASK(11, 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK_SFT BIT(5) +#define I2S2_FMT_SFT 3 +#define I2S2_FMT_MASK_SFT BIT(3) +#define I2S2_WLEN_SFT 1 +#define I2S2_WLEN_MASK_SFT BIT(1) +#define I2S2_EN_SFT 0 +#define I2S2_EN_MASK_SFT BIT(0) + +/* AFE_I2S_CON2 */ +#define I2S3_LR_SWAP_SFT 31 +#define I2S3_LR_SWAP_MASK_SFT BIT(31) +#define I2S3_UPDATE_WORD_SFT 24 +#define I2S3_UPDATE_WORD_MASK_SFT GENMASK(28, 24) +#define I2S3_BCK_INV_SFT 23 +#define I2S3_BCK_INV_MASK_SFT BIT(23) +#define I2S3_FPGA_BIT_TEST_SFT 22 +#define I2S3_FPGA_BIT_TEST_MASK_SFT BIT(22) +#define I2S3_FPGA_BIT_SFT 21 +#define I2S3_FPGA_BIT_MASK_SFT BIT(21) +#define I2S3_LOOPBACK_SFT 20 +#define I2S3_LOOPBACK_MASK_SFT BIT(20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17) +#define I2S3_HD_EN_SFT 12 +#define I2S3_HD_EN_MASK_SFT BIT(12) +#define I2S3_OUT_MODE_SFT 8 +#define I2S3_OUT_MODE_MASK_SFT GENMASK(11, 8) +#define I2S3_FMT_SFT 3 +#define I2S3_FMT_MASK_SFT BIT(3) +#define I2S3_WLEN_SFT 1 +#define I2S3_WLEN_MASK_SFT BIT(1) +#define I2S3_EN_SFT 0 +#define I2S3_EN_MASK_SFT BIT(0) + +/* AFE_I2S_CON3 */ +#define I2S4_LR_SWAP_SFT 31 +#define I2S4_LR_SWAP_MASK_SFT BIT(31) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17) +#define I2S4_HD_EN_SFT 12 +#define I2S4_HD_EN_MASK_SFT BIT(12) +#define I2S4_OUT_MODE_SFT 8 +#define I2S4_OUT_MODE_MASK_SFT GENMASK(11, 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK_SFT BIT(5) +#define I2S4_FMT_SFT 3 +#define I2S4_FMT_MASK_SFT BIT(3) +#define I2S4_WLEN_SFT 1 +#define I2S4_WLEN_MASK_SFT BIT(1) +#define I2S4_EN_SFT 0 +#define I2S4_EN_MASK_SFT BIT(0) + +/* AFE_I2S_CON4 */ +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT BIT(20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT BIT(5) + +/* AFE_CONNSYS_I2S_CON */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK_SFT BIT(30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK_SFT BIT(29) +#define I2SIN_PAD_SEL_SFT 28 +#define I2SIN_PAD_SEL_MASK_SFT BIT(28) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK_SFT BIT(20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17) +#define I2S_MODE_SFT 8 +#define I2S_MODE_MASK_SFT GENMASK(11, 8) +#define INV_PAD_CTRL_SFT 7 +#define INV_PAD_CTRL_MASK_SFT BIT(7) +#define I2S_BYPSRC_SFT 6 +#define I2S_BYPSRC_MASK_SFT BIT(6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK_SFT BIT(5) +#define I2S_FMT_SFT 3 +#define I2S_FMT_MASK_SFT BIT(3) +#define I2S_SRC_SFT 2 +#define I2S_SRC_MASK_SFT BIT(2) +#define I2S_WLEN_SFT 1 +#define I2S_WLEN_MASK_SFT BIT(1) +#define I2S_EN_SFT 0 +#define I2S_EN_MASK_SFT BIT(0) + +/* AFE_ASRC_2CH_CON2 */ +#define CHSET_O16BIT_SFT 19 +#define CHSET_O16BIT_MASK_SFT BIT(19) +#define CHSET_CLR_IIR_HISTORY_SFT 17 +#define CHSET_CLR_IIR_HISTORY_MASK_SFT BIT(17) +#define CHSET_IS_MONO_SFT 16 +#define CHSET_IS_MONO_MASK_SFT BIT(16) +#define CHSET_IIR_EN_SFT 11 +#define CHSET_IIR_EN_MASK_SFT BIT(11) +#define CHSET_IIR_STAGE_SFT 8 +#define CHSET_IIR_STAGE_MASK_SFT GENMASK(10, 8) +#define CHSET_STR_CLR_SFT 5 +#define CHSET_STR_CLR_MASK_SFT BIT(5) +#define CHSET_ON_SFT 2 +#define CHSET_ON_MASK_SFT BIT(2) +#define COEFF_SRAM_CTRL_SFT 1 +#define COEFF_SRAM_CTRL_MASK_SFT BIT(1) +#define ASM_ON_SFT 0 +#define ASM_ON_MASK_SFT BIT(0) + +/* AFE_GAIN1_CON0 */ +#define GAIN1_SAMPLE_PER_STEP_SFT 8 +#define GAIN1_SAMPLE_PER_STEP_MASK_SFT GENMASK(15, 8) +#define GAIN1_MODE_SFT 4 +#define GAIN1_MODE_MASK_SFT GENMASK(7, 4) +#define GAIN1_ON_SFT 0 +#define GAIN1_ON_MASK_SFT BIT(0) + +/* AFE_GAIN1_CON1 */ +#define GAIN1_TARGET_SFT 0 +#define GAIN1_TARGET_MASK 0xfffffff +#define GAIN1_TARGET_MASK_SFT GENMASK(27, 0) + +/* AFE_GAIN2_CON0 */ +#define GAIN2_SAMPLE_PER_STEP_SFT 8 +#define GAIN2_SAMPLE_PER_STEP_MASK_SFT GENMASK(15, 8) +#define GAIN2_MODE_SFT 4 +#define GAIN2_MODE_MASK_SFT GENMASK(7, 4) +#define GAIN2_ON_SFT 0 +#define GAIN2_ON_MASK_SFT BIT(0) + +/* AFE_GAIN2_CON1 */ +#define GAIN2_TARGET_SFT 0 +#define GAIN2_TARGET_MASK 0xfffffff +#define GAIN2_TARGET_MASK_SFT GENMASK(27, 0) + +/* AFE_GAIN1_CUR */ +#define AFE_GAIN1_CUR_SFT 0 +#define AFE_GAIN1_CUR_MASK_SFT GENMASK(27, 0) + +/* AFE_GAIN2_CUR */ +#define AFE_GAIN2_CUR_SFT 0 +#define AFE_GAIN2_CUR_MASK_SFT GENMASK(27, 0) + +/* PCM_INTF_CON1 */ +#define PCM_FIX_VALUE_SEL_SFT 31 +#define PCM_FIX_VALUE_SEL_MASK_SFT BIT(31) +#define PCM_BUFFER_LOOPBACK_SFT 30 +#define PCM_BUFFER_LOOPBACK_MASK_SFT BIT(30) +#define PCM_PARALLEL_LOOPBACK_SFT 29 +#define PCM_PARALLEL_LOOPBACK_MASK_SFT BIT(29) +#define PCM_SERIAL_LOOPBACK_SFT 28 +#define PCM_SERIAL_LOOPBACK_MASK_SFT BIT(28) +#define PCM_DAI_PCM_LOOPBACK_SFT 27 +#define PCM_DAI_PCM_LOOPBACK_MASK_SFT BIT(27) +#define PCM_I2S_PCM_LOOPBACK_SFT 26 +#define PCM_I2S_PCM_LOOPBACK_MASK_SFT BIT(26) +#define PCM_SYNC_DELSEL_SFT 25 +#define PCM_SYNC_DELSEL_MASK_SFT BIT(25) +#define PCM_TX_LR_SWAP_SFT 24 +#define PCM_TX_LR_SWAP_MASK_SFT BIT(24) +#define PCM_SYNC_OUT_INV_SFT 23 +#define PCM_SYNC_OUT_INV_MASK_SFT BIT(23) +#define PCM_BCLK_OUT_INV_SFT 22 +#define PCM_BCLK_OUT_INV_MASK_SFT BIT(22) +#define PCM_SYNC_IN_INV_SFT 21 +#define PCM_SYNC_IN_INV_MASK_SFT BIT(21) +#define PCM_BCLK_IN_INV_SFT 20 +#define PCM_BCLK_IN_INV_MASK_SFT BIT(20) +#define PCM_TX_LCH_RPT_SFT 19 +#define PCM_TX_LCH_RPT_MASK_SFT BIT(19) +#define PCM_VBT_16K_MODE_SFT 18 +#define PCM_VBT_16K_MODE_MASK_SFT BIT(18) +#define PCM_EXT_MODEM_SFT 17 +#define PCM_EXT_MODEM_MASK_SFT BIT(17) +#define PCM_24BIT_SFT 16 +#define PCM_24BIT_MASK_SFT BIT(16) +#define PCM_WLEN_SFT 14 +#define PCM_WLEN_MASK_SFT GENMASK(15, 14) +#define PCM_SYNC_LENGTH_SFT 9 +#define PCM_SYNC_LENGTH_MASK_SFT GENMASK(13, 9) +#define PCM_SYNC_TYPE_SFT 8 +#define PCM_SYNC_TYPE_MASK_SFT BIT(8) +#define PCM_BT_MODE_SFT 7 +#define PCM_BT_MODE_MASK_SFT BIT(7) +#define PCM_BYP_ASRC_SFT 6 +#define PCM_BYP_ASRC_MASK_SFT BIT(6) +#define PCM_SLAVE_SFT 5 +#define PCM_SLAVE_MASK_SFT BIT(5) +#define PCM_MODE_SFT 3 +#define PCM_MODE_MASK_SFT GENMASK(4, 3) +#define PCM_FMT_SFT 1 +#define PCM_FMT_MASK_SFT GENMASK(2, 1) +#define PCM_EN_SFT 0 +#define PCM_EN_MASK_SFT BIT(0) + +/* PCM_INTF_CON2 */ +#define PCM1_TX_FIFO_OV_SFT 31 +#define PCM1_TX_FIFO_OV_MASK_SFT BIT(31) +#define PCM1_RX_FIFO_OV_SFT 30 +#define PCM1_RX_FIFO_OV_MASK_SFT BIT(30) +#define PCM2_TX_FIFO_OV_SFT 29 +#define PCM2_TX_FIFO_OV_MASK_SFT BIT(29) +#define PCM2_RX_FIFO_OV_SFT 28 +#define PCM2_RX_FIFO_OV_MASK_SFT BIT(28) +#define PCM1_SYNC_GLITCH_SFT 27 +#define PCM1_SYNC_GLITCH_MASK_SFT BIT(27) +#define PCM2_SYNC_GLITCH_SFT 26 +#define PCM2_SYNC_GLITCH_MASK_SFT BIT(26) +#define TX3_RCH_DBG_MODE_SFT 17 +#define TX3_RCH_DBG_MODE_MASK_SFT BIT(17) +#define PCM1_PCM2_LOOPBACK_SFT 16 +#define PCM1_PCM2_LOOPBACK_MASK_SFT BIT(16) +#define DAI_PCM_LOOPBACK_CH_SFT 14 +#define DAI_PCM_LOOPBACK_CH_MASK_SFT GENMASK(15, 14) +#define I2S_PCM_LOOPBACK_CH_SFT 12 +#define I2S_PCM_LOOPBACK_CH_MASK_SFT GENMASK(13, 12) +#define TX_FIX_VALUE_SFT 0 +#define TX_FIX_VALUE_MASK_SFT GENMASK(7, 0) + +/* PCM2_INTF_CON */ +#define PCM2_TX_FIX_VALUE_SFT 24 +#define PCM2_TX_FIX_VALUE_MASK_SFT GENMASK(31, 24) +#define PCM2_FIX_VALUE_SEL_SFT 23 +#define PCM2_FIX_VALUE_SEL_MASK_SFT BIT(23) +#define PCM2_BUFFER_LOOPBACK_SFT 22 +#define PCM2_BUFFER_LOOPBACK_MASK_SFT BIT(22) +#define PCM2_PARALLEL_LOOPBACK_SFT 21 +#define PCM2_PARALLEL_LOOPBACK_MASK_SFT BIT(21) +#define PCM2_SERIAL_LOOPBACK_SFT 20 +#define PCM2_SERIAL_LOOPBACK_MASK_SFT BIT(20) +#define PCM2_DAI_PCM_LOOPBACK_SFT 19 +#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT BIT(19) +#define PCM2_I2S_PCM_LOOPBACK_SFT 18 +#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT BIT(18) +#define PCM2_SYNC_DELSEL_SFT 17 +#define PCM2_SYNC_DELSEL_MASK_SFT BIT(17) +#define PCM2_TX_LR_SWAP_SFT 16 +#define PCM2_TX_LR_SWAP_MASK_SFT BIT(16) +#define PCM2_SYNC_IN_INV_SFT 15 +#define PCM2_SYNC_IN_INV_MASK_SFT BIT(15) +#define PCM2_BCLK_IN_INV_SFT 14 +#define PCM2_BCLK_IN_INV_MASK_SFT BIT(14) +#define PCM2_TX_LCH_RPT_SFT 13 +#define PCM2_TX_LCH_RPT_MASK_SFT BIT(13) +#define PCM2_VBT_16K_MODE_SFT 12 +#define PCM2_VBT_16K_MODE_MASK_SFT BIT(12) +#define PCM2_LOOPBACK_CH_SEL_SFT 10 +#define PCM2_LOOPBACK_CH_SEL_MASK_SFT GENMASK(11, 10) +#define PCM2_TX2_BT_MODE_SFT 8 +#define PCM2_TX2_BT_MODE_MASK_SFT BIT(8) +#define PCM2_BT_MODE_SFT 7 +#define PCM2_BT_MODE_MASK_SFT BIT(7) +#define PCM2_AFIFO_SFT 6 +#define PCM2_AFIFO_MASK_SFT BIT(6) +#define PCM2_WLEN_SFT 5 +#define PCM2_WLEN_MASK_SFT BIT(5) +#define PCM2_MODE_SFT 3 +#define PCM2_MODE_MASK_SFT GENMASK(4, 3) +#define PCM2_FMT_SFT 1 +#define PCM2_FMT_MASK_SFT GENMASK(2, 1) +#define PCM2_EN_SFT 0 +#define PCM2_EN_MASK_SFT BIT(0) + +// AFE_CM1_CON +#define CHANNEL_MERGE0_DEBUG_MODE_SFT (31) +#define CHANNEL_MERGE0_DEBUG_MODE_MASK_SFT BIT(31) +#define VUL3_BYPASS_CM_SFT (30) +#define VUL3_BYPASS_CM_MASK (0x1) +#define VUL3_BYPASS_CM_MASK_SFT BIT(30) +#define CM1_DEBUG_MODE_SEL_SFT (29) +#define CM1_DEBUG_MODE_SEL_MASK_SFT BIT(29) +#define CHANNEL_MERGE0_UPDATE_CNT_SFT (16) +#define CHANNEL_MERGE0_UPDATE_CNT_MASK_SFT GENMASK(28, 16) +#define CM1_FS_SELECT_SFT (8) +#define CM1_FS_SELECT_MASK_SFT GENMASK(12, 8) +#define CHANNEL_MERGE0_CHNUM_SFT (3) +#define CHANNEL_MERGE0_CHNUM_MASK_SFT GENMASK(7, 3) +#define CHANNEL_MERGE0_BYTE_SWAP_SFT (1) +#define CHANNEL_MERGE0_BYTE_SWAP_MASK_SFT BIT(1) +#define CHANNEL_MERGE0_EN_SFT (0) +#define CHANNEL_MERGE0_EN_MASK_SFT BIT(0) + +/* AFE_ADDA_MTKAIF_CFG0 */ +#define MTKAIF_RXIF_CLKINV_ADC_SFT 31 +#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT BIT(31) +#define MTKAIF_RXIF_BYPASS_SRC_SFT 17 +#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT BIT(17) +#define MTKAIF_RXIF_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT BIT(16) +#define MTKAIF_TXIF_BYPASS_SRC_SFT 5 +#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT BIT(5) +#define MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT BIT(4) +#define MTKAIF_TXIF_8TO5_SFT 2 +#define MTKAIF_TXIF_8TO5_MASK_SFT BIT(2) +#define MTKAIF_RXIF_8TO5_SFT 1 +#define MTKAIF_RXIF_8TO5_MASK_SFT BIT(1) +#define MTKAIF_IF_LOOPBACK1_SFT 0 +#define MTKAIF_IF_LOOPBACK1_MASK_SFT BIT(0) + +/* AFE_ADDA_MTKAIF_RX_CFG2 */ +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT BIT(16) +#define MTKAIF_RXIF_DELAY_CYCLE_SFT 12 +#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT GENMASK(15, 12) +#define MTKAIF_RXIF_DELAY_DATA_SFT 8 +#define MTKAIF_RXIF_DELAY_DATA_MASK 0x1 +#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT BIT(8) +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT GENMASK(6, 4) + +/* AFE_ADDA_DL_SRC2_CON0 */ +#define DL_2_INPUT_MODE_CTL_SFT 28 +#define DL_2_INPUT_MODE_CTL_MASK_SFT GENMASK(31, 28) +#define DL_2_CH1_SATURATION_EN_CTL_SFT 27 +#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT BIT(27) +#define DL_2_CH2_SATURATION_EN_CTL_SFT 26 +#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT BIT(26) +#define DL_2_OUTPUT_SEL_CTL_SFT 24 +#define DL_2_OUTPUT_SEL_CTL_MASK_SFT GENMASK(25, 24) +#define DL_2_FADEIN_0START_EN_SFT 16 +#define DL_2_FADEIN_0START_EN_MASK_SFT GENMASK(17, 16) +#define DL_DISABLE_HW_CG_CTL_SFT 15 +#define DL_DISABLE_HW_CG_CTL_MASK_SFT BIT(15) +#define C_DATA_EN_SEL_CTL_PRE_SFT 14 +#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT BIT(14) +#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT BIT(13) +#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT BIT(12) +#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT BIT(11) +#define DL2_ARAMPSP_CTL_PRE_SFT 9 +#define DL2_ARAMPSP_CTL_PRE_MASK_SFT GENMASK(10, 9) +#define DL_2_IIRMODE_CTL_PRE_SFT 6 +#define DL_2_IIRMODE_CTL_PRE_MASK_SFT GENMASK(8, 6) +#define DL_2_VOICE_MODE_CTL_PRE_SFT 5 +#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT BIT(5) +#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT BIT(4) +#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT BIT(3) +#define DL_2_IIR_ON_CTL_PRE_SFT 2 +#define DL_2_IIR_ON_CTL_PRE_MASK_SFT BIT(2) +#define DL_2_GAIN_ON_CTL_PRE_SFT 1 +#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT BIT(1) +#define DL_2_SRC_ON_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_CTL_PRE_MASK_SFT BIT(0) + +/* AFE_ADDA_DL_SRC2_CON1 */ +#define DL_2_GAIN_CTL_PRE_SFT 16 +#define DL_2_GAIN_CTL_PRE_MASK 0xffff +#define DL_2_GAIN_CTL_PRE_MASK_SFT GENMASK(31, 16) +#define DL_2_GAIN_MODE_CTL_SFT 0 +#define DL_2_GAIN_MODE_CTL_MASK_SFT BIT(0) + +/* AFE_ADDA_UL_SRC_CON0 */ +#define ULCF_CFG_EN_CTL_SFT 31 +#define ULCF_CFG_EN_CTL_MASK_SFT BIT(31) +#define UL_DMIC_PHASE_SEL_CH1_SFT 27 +#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT GENMASK(29, 27) +#define UL_DMIC_PHASE_SEL_CH2_SFT 24 +#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT GENMASK(26, 24) +#define UL_MODE_3P25M_CH2_CTL_SFT 22 +#define UL_MODE_3P25M_CH2_CTL_MASK_SFT BIT(22) +#define UL_MODE_3P25M_CH1_CTL_SFT 21 +#define UL_MODE_3P25M_CH1_CTL_MASK_SFT BIT(21) +#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT GENMASK(19, 17) +#define UL_AP_DMIC_ON_SFT 16 +#define UL_AP_DMIC_ON_MASK_SFT BIT(16) +#define DMIC_LOW_POWER_CTL_SFT 14 +#define DMIC_LOW_POWER_CTL_MASK_SFT GENMASK(15, 14) +#define UL_DISABLE_HW_CG_CTL_SFT 12 +#define UL_DISABLE_HW_CG_CTL_MASK_SFT BIT(12) +#define UL_IIR_ON_TMP_CTL_SFT 10 +#define UL_IIR_ON_TMP_CTL_MASK_SFT BIT(10) +#define UL_IIRMODE_CTL_SFT 7 +#define UL_IIRMODE_CTL_MASK_SFT GENMASK(9, 7) +#define DIGMIC_4P33M_SEL_SFT 6 +#define DIGMIC_4P33M_SEL_MASK_SFT BIT(6) +#define DIGMIC_3P25M_1P625M_SEL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_MASK_SFT BIT(5) +#define UL_LOOP_BACK_MODE_SFT 2 +#define UL_LOOP_BACK_MODE_MASK_SFT BIT(2) +#define UL_SDM_3_LEVEL_SFT 1 +#define UL_SDM_3_LEVEL_MASK_SFT BIT(1) +#define UL_SRC_ON_CTL_SFT 0 +#define UL_SRC_ON_CTL_MASK_SFT BIT(0) + +/* AFE_ADDA_UL_SRC_CON1 */ +#define C_DAC_EN_CTL_SFT 27 +#define C_DAC_EN_CTL_MASK_SFT BIT(27) +#define C_MUTE_SW_CTL_SFT 26 +#define C_MUTE_SW_CTL_MASK_SFT BIT(26) +#define ASDM_SRC_SEL_CTL_SFT 25 +#define ASDM_SRC_SEL_CTL_MASK_SFT BIT(25) +#define C_AMP_DIV_CH2_CTL_SFT 21 +#define C_AMP_DIV_CH2_CTL_MASK_SFT GENMASK(23, 21) +#define C_FREQ_DIV_CH2_CTL_SFT 16 +#define C_FREQ_DIV_CH2_CTL_MASK_SFT GENMASK(20, 16) +#define C_SINE_MODE_CH2_CTL_SFT 12 +#define C_SINE_MODE_CH2_CTL_MASK_SFT GENMASK(15, 12) +#define C_AMP_DIV_CH1_CTL_SFT 9 +#define C_AMP_DIV_CH1_CTL_MASK_SFT GENMASK(11, 9) +#define C_FREQ_DIV_CH1_CTL_SFT 4 +#define C_FREQ_DIV_CH1_CTL_MASK_SFT GENMASK(8, 4) +#define C_SINE_MODE_CH1_CTL_SFT 0 +#define C_SINE_MODE_CH1_CTL_MASK_SFT GENMASK(3, 0) + +/* AFE_ADDA_TOP_CON0 */ +#define C_LOOP_BACK_MODE_CTL_SFT 12 +#define C_LOOP_BACK_MODE_CTL_MASK_SFT GENMASK(15, 12) +#define ADDA_UL_GAIN_MODE_SFT 8 +#define ADDA_UL_GAIN_MODE_MASK_SFT GENMASK(9, 8) +#define C_EXT_ADC_CTL_SFT 0 +#define C_EXT_ADC_CTL_MASK_SFT BIT(0) + +/* AFE_ADDA_UL_DL_CON0 */ +#define AFE_ADDA_UL_LR_SWAP_SFT 31 +#define AFE_ADDA_UL_LR_SWAP_MASK_SFT BIT(31) +#define AFE_ADDA_CKDIV_RST_SFT 30 +#define AFE_ADDA_CKDIV_RST_MASK_SFT BIT(30) +#define AFE_ADDA_FIFO_AUTO_RST_SFT 29 +#define AFE_ADDA_FIFO_AUTO_RST_MASK_SFT BIT(29) +#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_SFT 21 +#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK_SFT GENMASK(22, 21) +#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 20 +#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT BIT(20) +#define AFE_ADDA6_UL_LR_SWAP_SFT 15 +#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT BIT(15) +#define AFE_ADDA6_CKDIV_RST_SFT 14 +#define AFE_ADDA6_CKDIV_RST_MASK_SFT BIT(14) +#define AFE_ADDA6_FIFO_AUTO_RST_SFT 13 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT BIT(13) +#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_SFT 5 +#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK_SFT GENMASK(6, 5) +#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 4 +#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT BIT(4) +#define ADDA_AFE_ON_SFT 0 +#define ADDA_AFE_ON_MASK_SFT BIT(0) + +/* AFE_SIDETONE_CON0 */ +#define R_RDY_SFT 30 +#define R_RDY_MASK_SFT BIT(30) +#define W_RDY_SFT 29 +#define W_RDY_MASK_SFT BIT(29) +#define R_W_EN_SFT 25 +#define R_W_EN_MASK_SFT BIT(25) +#define R_W_SEL_SFT 24 +#define R_W_SEL_MASK_SFT BIT(24) +#define SEL_CH2_SFT 23 +#define SEL_CH2_MASK_SFT BIT(23) +#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16 +#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT GENMASK(20, 16) +#define SIDE_TONE_COEFFICIENT_SFT 0 +#define SIDE_TONE_COEFFICIENT_MASK_SFT GENMASK(15, 0) + +/* AFE_SIDETONE_COEFF */ +#define SIDE_TONE_COEFF_SFT 0 +#define SIDE_TONE_COEFF_MASK_SFT GENMASK(15, 0) + +/* AFE_SIDETONE_CON1 */ +#define STF_BYPASS_MODE_SFT 31 +#define STF_BYPASS_MODE_MASK_SFT BIT(31) +#define STF_BYPASS_MODE_O28_O29_SFT 30 +#define STF_BYPASS_MODE_O28_O29_MASK_SFT BIT(30) +#define STF_BYPASS_MODE_I2S4_SFT 29 +#define STF_BYPASS_MODE_I2S4_MASK_SFT BIT(29) +#define STF_BYPASS_MODE_DL3_SFT 27 +#define STF_BYPASS_MODE_DL3_MASK_SFT BIT(27) +#define STF_BYPASS_MODE_I2S7_SFT 26 +#define STF_BYPASS_MODE_I2S7_MASK_SFT BIT(26) +#define STF_BYPASS_MODE_I2S9_SFT 25 +#define STF_BYPASS_MODE_I2S9_MASK_SFT BIT(25) +#define STF_O19O20_OUT_EN_SEL_SFT 13 +#define STF_O19O20_OUT_EN_SEL_MASK_SFT BIT(13) +#define STF_SOURCE_FROM_O19O20_SFT 12 +#define STF_SOURCE_FROM_O19O20_MASK_SFT BIT(12) +#define SIDE_TONE_ON_SFT 8 +#define SIDE_TONE_ON_MASK_SFT BIT(8) +#define SIDE_TONE_HALF_TAP_NUM_SFT 0 +#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT GENMASK(5, 0) + +/* AFE_SIDETONE_GAIN */ +#define POSITIVE_GAIN_SFT 16 +#define POSITIVE_GAIN_MASK_SFT GENMASK(18, 16) +#define SIDE_TONE_GAIN_SFT 0 +#define SIDE_TONE_GAIN_MASK_SFT GENMASK(15, 0) + +/* AFE_ADDA_DL_SDM_DCCOMP_CON */ +#define USE_3RD_SDM_SFT 28 +#define USE_3RD_SDM_MASK_SFT BIT(28) +#define DL_FIFO_START_POINT_SFT 24 +#define DL_FIFO_START_POINT_MASK_SFT GENMASK(26, 24) +#define DL_FIFO_SWAP_SFT 20 +#define DL_FIFO_SWAP_MASK_SFT BIT(20) +#define C_AUDSDM1ORDSELECT_CTL_SFT 19 +#define C_AUDSDM1ORDSELECT_CTL_MASK_SFT BIT(19) +#define C_SDM7BITSEL_CTL_SFT 18 +#define C_SDM7BITSEL_CTL_MASK_SFT BIT(18) +#define GAIN_AT_SDM_RST_PRE_CTL_SFT 15 +#define GAIN_AT_SDM_RST_PRE_CTL_MASK_SFT BIT(15) +#define DL_DCM_AUTO_IDLE_EN_SFT 14 +#define DL_DCM_AUTO_IDLE_EN_MASK_SFT BIT(14) +#define AFE_DL_SRC_DCM_EN_SFT 13 +#define AFE_DL_SRC_DCM_EN_MASK_SFT BIT(13) +#define AFE_DL_POST_SRC_DCM_EN_SFT 12 +#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT BIT(12) +#define AUD_SDM_MONO_SFT 9 +#define AUD_SDM_MONO_MASK_SFT BIT(9) +#define AUD_DC_COMP_EN_SFT 8 +#define AUD_DC_COMP_EN_MASK_SFT BIT(8) +#define ATTGAIN_CTL_SFT 0 +#define ATTGAIN_CTL_MASK_SFT GENMASK(5, 0) + +/* AFE_SINEGEN_CON0 */ +#define DAC_EN_SFT 26 +#define DAC_EN_MASK 0x1 +#define DAC_EN_MASK_SFT BIT(26) +#define MUTE_SW_CH2_SFT 25 +#define MUTE_SW_CH2_MASK 0x1 +#define MUTE_SW_CH2_MASK_SFT BIT(25) +#define MUTE_SW_CH1_SFT 24 +#define MUTE_SW_CH1_MASK 0x1 +#define MUTE_SW_CH1_MASK_SFT BIT(24) +#define SINE_MODE_CH2_SFT 20 +#define SINE_MODE_CH2_MASK 0xf +#define SINE_MODE_CH2_MASK_SFT GENMASK(23, 20) +#define AMP_DIV_CH2_SFT 17 +#define AMP_DIV_CH2_MASK 0x7 +#define AMP_DIV_CH2_MASK_SFT GENMASK(19, 17) +#define FREQ_DIV_CH2_SFT 12 +#define FREQ_DIV_CH2_MASK 0x1f +#define FREQ_DIV_CH2_MASK_SFT GENMASK(16, 12) +#define SINE_MODE_CH1_SFT 8 +#define SINE_MODE_CH1_MASK 0xf +#define SINE_MODE_CH1_MASK_SFT GENMASK(11, 8) +#define AMP_DIV_CH1_SFT 5 +#define AMP_DIV_CH1_MASK 0x7 +#define AMP_DIV_CH1_MASK_SFT GENMASK(7, 5) +#define FREQ_DIV_CH1_SFT 0 +#define FREQ_DIV_CH1_MASK 0x1f +#define FREQ_DIV_CH1_MASK_SFT GENMASK(4, 0) + +/* AFE_SINEGEN_CON2 */ +#define INNER_LOOP_BACK_MODE_SFT 0 +#define INNER_LOOP_BACK_MODE_MASK_SFT GENMASK(7, 0) + +/* AFE_HD_ENGEN_ENABLE */ +#define AFE_24M_ON_SFT 1 +#define AFE_24M_ON_MASK_SFT BIT(1) +#define AFE_22M_ON_SFT 0 +#define AFE_22M_ON_MASK_SFT BIT(0) + +/* AFE_ADDA_DL_NLE_FIFO_MON */ +#define DL_NLE_FIFO_WBIN_SFT 8 +#define DL_NLE_FIFO_WBIN_MASK_SFT GENMASK(11, 8) +#define DL_NLE_FIFO_RBIN_SFT 4 +#define DL_NLE_FIFO_RBIN_MASK_SFT GENMASK(7, 4) +#define DL_NLE_FIFO_RDACTIVE_SFT 3 +#define DL_NLE_FIFO_RDACTIVE_MASK_SFT BIT(3) +#define DL_NLE_FIFO_STARTRD_SFT 2 +#define DL_NLE_FIFO_STARTRD_MASK_SFT BIT(2) +#define DL_NLE_FIFO_RD_EMPTY_SFT 1 +#define DL_NLE_FIFO_RD_EMPTY_MASK_SFT BIT(1) +#define DL_NLE_FIFO_WR_FULL_SFT 0 +#define DL_NLE_FIFO_WR_FULL_MASK_SFT BIT(0) + +/* AFE_DL1_CON0 */ +#define DL1_MODE_SFT 24 +#define DL1_MODE_MASK 0xf +#define DL1_MODE_MASK_SFT GENMASK(27, 24) +#define DL1_MINLEN_SFT 20 +#define DL1_MINLEN_MASK 0xf +#define DL1_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL1_MAXLEN_SFT 16 +#define DL1_MAXLEN_MASK 0xf +#define DL1_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL1_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL1_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL1_PBUF_SIZE_SFT 12 +#define DL1_PBUF_SIZE_MASK 0x3 +#define DL1_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL1_MONO_SFT 8 +#define DL1_MONO_MASK 0x1 +#define DL1_MONO_MASK_SFT BIT(8) +#define DL1_NORMAL_MODE_SFT 5 +#define DL1_NORMAL_MODE_MASK 0x1 +#define DL1_NORMAL_MODE_MASK_SFT BIT(5) +#define DL1_HALIGN_SFT 4 +#define DL1_HALIGN_MASK 0x1 +#define DL1_HALIGN_MASK_SFT BIT(4) +#define DL1_HD_MODE_SFT 0 +#define DL1_HD_MODE_MASK 0x3 +#define DL1_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL2_CON0 */ +#define DL2_MODE_SFT 24 +#define DL2_MODE_MASK 0xf +#define DL2_MODE_MASK_SFT GENMASK(27, 24) +#define DL2_MINLEN_SFT 20 +#define DL2_MINLEN_MASK 0xf +#define DL2_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL2_MAXLEN_SFT 16 +#define DL2_MAXLEN_MASK 0xf +#define DL2_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL2_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL2_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL2_PBUF_SIZE_SFT 12 +#define DL2_PBUF_SIZE_MASK 0x3 +#define DL2_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL2_MONO_SFT 8 +#define DL2_MONO_MASK 0x1 +#define DL2_MONO_MASK_SFT BIT(8) +#define DL2_NORMAL_MODE_SFT 5 +#define DL2_NORMAL_MODE_MASK 0x1 +#define DL2_NORMAL_MODE_MASK_SFT BIT(5) +#define DL2_HALIGN_SFT 4 +#define DL2_HALIGN_MASK 0x1 +#define DL2_HALIGN_MASK_SFT BIT(4) +#define DL2_HD_MODE_SFT 0 +#define DL2_HD_MODE_MASK 0x3 +#define DL2_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL3_CON0 */ +#define DL3_MODE_SFT 24 +#define DL3_MODE_MASK 0xf +#define DL3_MODE_MASK_SFT GENMASK(27, 24) +#define DL3_MINLEN_SFT 20 +#define DL3_MINLEN_MASK 0xf +#define DL3_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL3_MAXLEN_SFT 16 +#define DL3_MAXLEN_MASK 0xf +#define DL3_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL3_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL3_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL3_PBUF_SIZE_SFT 12 +#define DL3_PBUF_SIZE_MASK 0x3 +#define DL3_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL3_MONO_SFT 8 +#define DL3_MONO_MASK 0x1 +#define DL3_MONO_MASK_SFT BIT(8) +#define DL3_NORMAL_MODE_SFT 5 +#define DL3_NORMAL_MODE_MASK 0x1 +#define DL3_NORMAL_MODE_MASK_SFT BIT(5) +#define DL3_HALIGN_SFT 4 +#define DL3_HALIGN_MASK 0x1 +#define DL3_HALIGN_MASK_SFT BIT(4) +#define DL3_HD_MODE_SFT 0 +#define DL3_HD_MODE_MASK 0x3 +#define DL3_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL4_CON0 */ +#define DL4_MODE_SFT 24 +#define DL4_MODE_MASK 0xf +#define DL4_MODE_MASK_SFT GENMASK(27, 24) +#define DL4_MINLEN_SFT 20 +#define DL4_MINLEN_MASK 0xf +#define DL4_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL4_MAXLEN_SFT 16 +#define DL4_MAXLEN_MASK 0xf +#define DL4_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL4_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL4_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL4_PBUF_SIZE_SFT 12 +#define DL4_PBUF_SIZE_MASK 0x3 +#define DL4_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL4_MONO_SFT 8 +#define DL4_MONO_MASK 0x1 +#define DL4_MONO_MASK_SFT BIT(8) +#define DL4_NORMAL_MODE_SFT 5 +#define DL4_NORMAL_MODE_MASK 0x1 +#define DL4_NORMAL_MODE_MASK_SFT BIT(5) +#define DL4_HALIGN_SFT 4 +#define DL4_HALIGN_MASK 0x1 +#define DL4_HALIGN_MASK_SFT BIT(4) +#define DL4_HD_MODE_SFT 0 +#define DL4_HD_MODE_MASK 0x3 +#define DL4_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL5_CON0 */ +#define DL5_MODE_SFT 24 +#define DL5_MODE_MASK 0xf +#define DL5_MODE_MASK_SFT GENMASK(27, 24) +#define DL5_MINLEN_SFT 20 +#define DL5_MINLEN_MASK 0xf +#define DL5_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL5_MAXLEN_SFT 16 +#define DL5_MAXLEN_MASK 0xf +#define DL5_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL5_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL5_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL5_PBUF_SIZE_SFT 12 +#define DL5_PBUF_SIZE_MASK 0x3 +#define DL5_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL5_MONO_SFT 8 +#define DL5_MONO_MASK 0x1 +#define DL5_MONO_MASK_SFT BIT(8) +#define DL5_NORMAL_MODE_SFT 5 +#define DL5_NORMAL_MODE_MASK 0x1 +#define DL5_NORMAL_MODE_MASK_SFT BIT(5) +#define DL5_HALIGN_SFT 4 +#define DL5_HALIGN_MASK 0x1 +#define DL5_HALIGN_MASK_SFT BIT(4) +#define DL5_HD_MODE_SFT 0 +#define DL5_HD_MODE_MASK 0x3 +#define DL5_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL6_CON0 */ +#define DL6_MODE_SFT 24 +#define DL6_MODE_MASK 0xf +#define DL6_MODE_MASK_SFT GENMASK(27, 24) +#define DL6_MINLEN_SFT 20 +#define DL6_MINLEN_MASK 0xf +#define DL6_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL6_MAXLEN_SFT 16 +#define DL6_MAXLEN_MASK 0xf +#define DL6_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL6_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL6_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL6_PBUF_SIZE_SFT 12 +#define DL6_PBUF_SIZE_MASK 0x3 +#define DL6_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL6_MONO_SFT 8 +#define DL6_MONO_MASK 0x1 +#define DL6_MONO_MASK_SFT BIT(8) +#define DL6_NORMAL_MODE_SFT 5 +#define DL6_NORMAL_MODE_MASK 0x1 +#define DL6_NORMAL_MODE_MASK_SFT BIT(5) +#define DL6_HALIGN_SFT 4 +#define DL6_HALIGN_MASK 0x1 +#define DL6_HALIGN_MASK_SFT BIT(4) +#define DL6_HD_MODE_SFT 0 +#define DL6_HD_MODE_MASK 0x3 +#define DL6_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL7_CON0 */ +#define DL7_MODE_SFT 24 +#define DL7_MODE_MASK 0xf +#define DL7_MODE_MASK_SFT GENMASK(27, 24) +#define DL7_MINLEN_SFT 20 +#define DL7_MINLEN_MASK 0xf +#define DL7_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL7_MAXLEN_SFT 16 +#define DL7_MAXLEN_MASK 0xf +#define DL7_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL7_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL7_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL7_PBUF_SIZE_SFT 12 +#define DL7_PBUF_SIZE_MASK 0x3 +#define DL7_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL7_MONO_SFT 8 +#define DL7_MONO_MASK 0x1 +#define DL7_MONO_MASK_SFT BIT(8) +#define DL7_NORMAL_MODE_SFT 5 +#define DL7_NORMAL_MODE_MASK 0x1 +#define DL7_NORMAL_MODE_MASK_SFT BIT(5) +#define DL7_HALIGN_SFT 4 +#define DL7_HALIGN_MASK 0x1 +#define DL7_HALIGN_MASK_SFT BIT(4) +#define DL7_HD_MODE_SFT 0 +#define DL7_HD_MODE_MASK 0x3 +#define DL7_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL8_CON0 */ +#define DL8_MODE_SFT 24 +#define DL8_MODE_MASK 0xf +#define DL8_MODE_MASK_SFT GENMASK(27, 24) +#define DL8_MINLEN_SFT 20 +#define DL8_MINLEN_MASK 0xf +#define DL8_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL8_MAXLEN_SFT 16 +#define DL8_MAXLEN_MASK 0xf +#define DL8_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL8_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL8_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL8_PBUF_SIZE_SFT 12 +#define DL8_PBUF_SIZE_MASK 0x3 +#define DL8_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL8_MONO_SFT 8 +#define DL8_MONO_MASK 0x1 +#define DL8_MONO_MASK_SFT BIT(8) +#define DL8_NORMAL_MODE_SFT 5 +#define DL8_NORMAL_MODE_MASK 0x1 +#define DL8_NORMAL_MODE_MASK_SFT BIT(5) +#define DL8_HALIGN_SFT 4 +#define DL8_HALIGN_MASK 0x1 +#define DL8_HALIGN_MASK_SFT BIT(4) +#define DL8_HD_MODE_SFT 0 +#define DL8_HD_MODE_MASK 0x3 +#define DL8_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DL12_CON0 */ +#define DL12_MODE_SFT 24 +#define DL12_MODE_MASK 0xf +#define DL12_MODE_MASK_SFT GENMASK(27, 24) +#define DL12_MINLEN_SFT 20 +#define DL12_MINLEN_MASK 0xf +#define DL12_MINLEN_MASK_SFT GENMASK(23, 20) +#define DL12_MAXLEN_SFT 16 +#define DL12_MAXLEN_MASK 0xf +#define DL12_MAXLEN_MASK_SFT GENMASK(19, 16) +#define DL12_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL12_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL12_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15) +#define DL12_PBUF_SIZE_SFT 12 +#define DL12_PBUF_SIZE_MASK 0x3 +#define DL12_PBUF_SIZE_MASK_SFT GENMASK(13, 12) +#define DL12_4CH_EN_SFT 11 +#define DL12_4CH_EN_MASK 0x1 +#define DL12_4CH_EN_MASK_SFT BIT(11) +#define DL12_MONO_SFT 8 +#define DL12_MONO_MASK 0x1 +#define DL12_MONO_MASK_SFT BIT(8) +#define DL12_NORMAL_MODE_SFT 5 +#define DL12_NORMAL_MODE_MASK 0x1 +#define DL12_NORMAL_MODE_MASK_SFT BIT(5) +#define DL12_HALIGN_SFT 4 +#define DL12_HALIGN_MASK 0x1 +#define DL12_HALIGN_MASK_SFT BIT(4) +#define DL12_HD_MODE_SFT 0 +#define DL12_HD_MODE_MASK 0x3 +#define DL12_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_AWB_CON0 */ +#define AWB_MODE_SFT 24 +#define AWB_MODE_MASK 0xf +#define AWB_MODE_MASK_SFT GENMASK(27, 24) +#define AWB_SW_CLEAR_BUF_FULL_SFT 15 +#define AWB_SW_CLEAR_BUF_FULL_MASK 0x1 +#define AWB_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define AWB_R_MONO_SFT 9 +#define AWB_R_MONO_MASK 0x1 +#define AWB_R_MONO_MASK_SFT BIT(9) +#define AWB_MONO_SFT 8 +#define AWB_MONO_MASK 0x1 +#define AWB_MONO_MASK_SFT BIT(8) +#define AWB_WR_SIGN_SFT 6 +#define AWB_WR_SIGN_MASK 0x1 +#define AWB_WR_SIGN_MASK_SFT BIT(6) +#define AWB_NORMAL_MODE_SFT 5 +#define AWB_NORMAL_MODE_MASK 0x1 +#define AWB_NORMAL_MODE_MASK_SFT BIT(5) +#define AWB_HALIGN_SFT 4 +#define AWB_HALIGN_MASK 0x1 +#define AWB_HALIGN_MASK_SFT BIT(4) +#define AWB_HD_MODE_SFT 0 +#define AWB_HD_MODE_MASK 0x3 +#define AWB_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_AWB2_CON0 */ +#define AWB2_MODE_SFT 24 +#define AWB2_MODE_MASK 0xf +#define AWB2_MODE_MASK_SFT GENMASK(27, 24) +#define AWB2_SW_CLEAR_BUF_FULL_SFT 15 +#define AWB2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define AWB2_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define AWB2_R_MONO_SFT 9 +#define AWB2_R_MONO_MASK 0x1 +#define AWB2_R_MONO_MASK_SFT BIT(9) +#define AWB2_MONO_SFT 8 +#define AWB2_MONO_MASK 0x1 +#define AWB2_MONO_MASK_SFT BIT(8) +#define AWB2_WR_SIGN_SFT 6 +#define AWB2_WR_SIGN_MASK 0x1 +#define AWB2_WR_SIGN_MASK_SFT BIT(6) +#define AWB2_NORMAL_MODE_SFT 5 +#define AWB2_NORMAL_MODE_MASK 0x1 +#define AWB2_NORMAL_MODE_MASK_SFT BIT(5) +#define AWB2_HALIGN_SFT 4 +#define AWB2_HALIGN_MASK 0x1 +#define AWB2_HALIGN_MASK_SFT BIT(4) +#define AWB2_HD_MODE_SFT 0 +#define AWB2_HD_MODE_MASK 0x3 +#define AWB2_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL_CON0 */ +#define VUL_MODE_SFT 24 +#define VUL_MODE_MASK 0xf +#define VUL_MODE_MASK_SFT GENMASK(27, 24) +#define VUL_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL_R_MONO_SFT 9 +#define VUL_R_MONO_MASK 0x1 +#define VUL_R_MONO_MASK_SFT BIT(9) +#define VUL_MONO_SFT 8 +#define VUL_MONO_MASK 0x1 +#define VUL_MONO_MASK_SFT BIT(8) +#define VUL_WR_SIGN_SFT 6 +#define VUL_WR_SIGN_MASK 0x1 +#define VUL_WR_SIGN_MASK_SFT BIT(6) +#define VUL_NORMAL_MODE_SFT 5 +#define VUL_NORMAL_MODE_MASK 0x1 +#define VUL_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL_HALIGN_SFT 4 +#define VUL_HALIGN_MASK 0x1 +#define VUL_HALIGN_MASK_SFT BIT(4) +#define VUL_HD_MODE_SFT 0 +#define VUL_HD_MODE_MASK 0x3 +#define VUL_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL12_CON0 */ +#define VUL12_MODE_SFT 24 +#define VUL12_MODE_MASK 0xf +#define VUL12_MODE_MASK_SFT GENMASK(27, 24) +#define VUL12_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL12_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL12_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL12_4CH_EN_SFT 11 +#define VUL12_4CH_EN_MASK 0x1 +#define VUL12_4CH_EN_MASK_SFT BIT(11) +#define VUL12_R_MONO_SFT 9 +#define VUL12_R_MONO_MASK 0x1 +#define VUL12_R_MONO_MASK_SFT BIT(9) +#define VUL12_MONO_SFT 8 +#define VUL12_MONO_MASK 0x1 +#define VUL12_MONO_MASK_SFT BIT(8) +#define VUL12_WR_SIGN_SFT 6 +#define VUL12_WR_SIGN_MASK 0x1 +#define VUL12_WR_SIGN_MASK_SFT BIT(6) +#define VUL12_NORMAL_MODE_SFT 5 +#define VUL12_NORMAL_MODE_MASK 0x1 +#define VUL12_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL12_HALIGN_SFT 4 +#define VUL12_HALIGN_MASK 0x1 +#define VUL12_HALIGN_MASK_SFT BIT(4) +#define VUL12_HD_MODE_SFT 0 +#define VUL12_HD_MODE_MASK 0x3 +#define VUL12_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL2_CON0 */ +#define VUL2_MODE_SFT 24 +#define VUL2_MODE_MASK 0xf +#define VUL2_MODE_MASK_SFT GENMASK(27, 24) +#define VUL2_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL2_R_MONO_SFT 9 +#define VUL2_R_MONO_MASK 0x1 +#define VUL2_R_MONO_MASK_SFT BIT(9) +#define VUL2_MONO_SFT 8 +#define VUL2_MONO_MASK 0x1 +#define VUL2_MONO_MASK_SFT BIT(8) +#define VUL2_WR_SIGN_SFT 6 +#define VUL2_WR_SIGN_MASK 0x1 +#define VUL2_WR_SIGN_MASK_SFT BIT(6) +#define VUL2_NORMAL_MODE_SFT 5 +#define VUL2_NORMAL_MODE_MASK 0x1 +#define VUL2_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL2_HALIGN_SFT 4 +#define VUL2_HALIGN_MASK 0x1 +#define VUL2_HALIGN_MASK_SFT BIT(4) +#define VUL2_HD_MODE_SFT 0 +#define VUL2_HD_MODE_MASK 0x3 +#define VUL2_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL3_CON0 */ +#define VUL3_MODE_SFT 24 +#define VUL3_MODE_MASK 0xf +#define VUL3_MODE_MASK_SFT GENMASK(27, 24) +#define VUL3_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL3_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL3_R_MONO_SFT 9 +#define VUL3_R_MONO_MASK 0x1 +#define VUL3_R_MONO_MASK_SFT BIT(9) +#define VUL3_MONO_SFT 8 +#define VUL3_MONO_MASK 0x1 +#define VUL3_MONO_MASK_SFT BIT(8) +#define VUL3_WR_SIGN_SFT 6 +#define VUL3_WR_SIGN_MASK 0x1 +#define VUL3_WR_SIGN_MASK_SFT BIT(6) +#define VUL3_NORMAL_MODE_SFT 5 +#define VUL3_NORMAL_MODE_MASK 0x1 +#define VUL3_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL3_HALIGN_SFT 4 +#define VUL3_HALIGN_MASK 0x1 +#define VUL3_HALIGN_MASK_SFT BIT(4) +#define VUL3_HD_MODE_SFT 0 +#define VUL3_HD_MODE_MASK 0x3 +#define VUL3_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL4_CON0 */ +#define VUL4_MODE_SFT 24 +#define VUL4_MODE_MASK 0xf +#define VUL4_MODE_MASK_SFT GENMASK(27, 24) +#define VUL4_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL4_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL4_R_MONO_SFT 9 +#define VUL4_R_MONO_MASK 0x1 +#define VUL4_R_MONO_MASK_SFT BIT(9) +#define VUL4_MONO_SFT 8 +#define VUL4_MONO_MASK 0x1 +#define VUL4_MONO_MASK_SFT BIT(8) +#define VUL4_WR_SIGN_SFT 6 +#define VUL4_WR_SIGN_MASK 0x1 +#define VUL4_WR_SIGN_MASK_SFT BIT(6) +#define VUL4_NORMAL_MODE_SFT 5 +#define VUL4_NORMAL_MODE_MASK 0x1 +#define VUL4_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL4_HALIGN_SFT 4 +#define VUL4_HALIGN_MASK 0x1 +#define VUL4_HALIGN_MASK_SFT BIT(4) +#define VUL4_HD_MODE_SFT 0 +#define VUL4_HD_MODE_MASK 0x3 +#define VUL4_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL5_CON0 */ +#define VUL5_MODE_SFT 24 +#define VUL5_MODE_MASK 0xf +#define VUL5_MODE_MASK_SFT GENMASK(27, 24) +#define VUL5_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL5_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL5_R_MONO_SFT 9 +#define VUL5_R_MONO_MASK 0x1 +#define VUL5_R_MONO_MASK_SFT BIT(9) +#define VUL5_MONO_SFT 8 +#define VUL5_MONO_MASK 0x1 +#define VUL5_MONO_MASK_SFT BIT(8) +#define VUL5_WR_SIGN_SFT 6 +#define VUL5_WR_SIGN_MASK 0x1 +#define VUL5_WR_SIGN_MASK_SFT BIT(6) +#define VUL5_NORMAL_MODE_SFT 5 +#define VUL5_NORMAL_MODE_MASK 0x1 +#define VUL5_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL5_HALIGN_SFT 4 +#define VUL5_HALIGN_MASK 0x1 +#define VUL5_HALIGN_MASK_SFT BIT(4) +#define VUL5_HD_MODE_SFT 0 +#define VUL5_HD_MODE_MASK 0x3 +#define VUL5_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_VUL6_CON0 */ +#define VUL6_MODE_SFT 24 +#define VUL6_MODE_MASK 0xf +#define VUL6_MODE_MASK_SFT GENMASK(27, 24) +#define VUL6_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL6_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define VUL6_R_MONO_SFT 9 +#define VUL6_R_MONO_MASK 0x1 +#define VUL6_R_MONO_MASK_SFT BIT(9) +#define VUL6_MONO_SFT 8 +#define VUL6_MONO_MASK 0x1 +#define VUL6_MONO_MASK_SFT BIT(8) +#define VUL6_WR_SIGN_SFT 6 +#define VUL6_WR_SIGN_MASK 0x1 +#define VUL6_WR_SIGN_MASK_SFT BIT(6) +#define VUL6_NORMAL_MODE_SFT 5 +#define VUL6_NORMAL_MODE_MASK 0x1 +#define VUL6_NORMAL_MODE_MASK_SFT BIT(5) +#define VUL6_HALIGN_SFT 4 +#define VUL6_HALIGN_MASK 0x1 +#define VUL6_HALIGN_MASK_SFT BIT(4) +#define VUL6_HD_MODE_SFT 0 +#define VUL6_HD_MODE_MASK 0x3 +#define VUL6_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DAI_CON0 */ +#define DAI_MODE_SFT 24 +#define DAI_MODE_MASK 0x3 +#define DAI_MODE_MASK_SFT GENMASK(25, 24) +#define DAI_SW_CLEAR_BUF_FULL_SFT 15 +#define DAI_SW_CLEAR_BUF_FULL_MASK 0x1 +#define DAI_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define DAI_DUPLICATE_WR_SFT 10 +#define DAI_DUPLICATE_WR_MASK 0x1 +#define DAI_DUPLICATE_WR_MASK_SFT BIT(10) +#define DAI_MONO_SFT 8 +#define DAI_MONO_MASK 0x1 +#define DAI_MONO_MASK_SFT BIT(8) +#define DAI_WR_SIGN_SFT 6 +#define DAI_WR_SIGN_MASK 0x1 +#define DAI_WR_SIGN_MASK_SFT BIT(6) +#define DAI_NORMAL_MODE_SFT 5 +#define DAI_NORMAL_MODE_MASK 0x1 +#define DAI_NORMAL_MODE_MASK_SFT BIT(5) +#define DAI_HALIGN_SFT 4 +#define DAI_HALIGN_MASK 0x1 +#define DAI_HALIGN_MASK_SFT BIT(4) +#define DAI_HD_MODE_SFT 0 +#define DAI_HD_MODE_MASK 0x3 +#define DAI_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_MOD_DAI_CON0 */ +#define MOD_DAI_MODE_SFT 24 +#define MOD_DAI_MODE_MASK 0x3 +#define MOD_DAI_MODE_MASK_SFT GENMASK(25, 24) +#define MOD_DAI_SW_CLEAR_BUF_FULL_SFT 15 +#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK 0x1 +#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define MOD_DAI_DUPLICATE_WR_SFT 10 +#define MOD_DAI_DUPLICATE_WR_MASK 0x1 +#define MOD_DAI_DUPLICATE_WR_MASK_SFT BIT(10) +#define MOD_DAI_MONO_SFT 8 +#define MOD_DAI_MONO_MASK 0x1 +#define MOD_DAI_MONO_MASK_SFT BIT(8) +#define MOD_DAI_WR_SIGN_SFT 6 +#define MOD_DAI_WR_SIGN_MASK 0x1 +#define MOD_DAI_WR_SIGN_MASK_SFT BIT(6) +#define MOD_DAI_NORMAL_MODE_SFT 5 +#define MOD_DAI_NORMAL_MODE_MASK 0x1 +#define MOD_DAI_NORMAL_MODE_MASK_SFT BIT(5) +#define MOD_DAI_HALIGN_SFT 4 +#define MOD_DAI_HALIGN_MASK 0x1 +#define MOD_DAI_HALIGN_MASK_SFT BIT(4) +#define MOD_DAI_HD_MODE_SFT 0 +#define MOD_DAI_HD_MODE_MASK 0x3 +#define MOD_DAI_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_DAI2_CON0 */ +#define DAI2_MODE_SFT 24 +#define DAI2_MODE_MASK 0xf +#define DAI2_MODE_MASK_SFT GENMASK(27, 24) +#define DAI2_SW_CLEAR_BUF_FULL_SFT 15 +#define DAI2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define DAI2_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15) +#define DAI2_DUPLICATE_WR_SFT 10 +#define DAI2_DUPLICATE_WR_MASK 0x1 +#define DAI2_DUPLICATE_WR_MASK_SFT BIT(10) +#define DAI2_MONO_SFT 8 +#define DAI2_MONO_MASK 0x1 +#define DAI2_MONO_MASK_SFT BIT(8) +#define DAI2_WR_SIGN_SFT 6 +#define DAI2_WR_SIGN_MASK 0x1 +#define DAI2_WR_SIGN_MASK_SFT BIT(6) +#define DAI2_NORMAL_MODE_SFT 5 +#define DAI2_NORMAL_MODE_MASK 0x1 +#define DAI2_NORMAL_MODE_MASK_SFT BIT(5) +#define DAI2_HALIGN_SFT 4 +#define DAI2_HALIGN_MASK 0x1 +#define DAI2_HALIGN_MASK_SFT BIT(4) +#define DAI2_HD_MODE_SFT 0 +#define DAI2_HD_MODE_MASK 0x3 +#define DAI2_HD_MODE_MASK_SFT GENMASK(1, 0) + +/* AFE_MEMIF_CON0 */ +#define CPU_COMPACT_MODE_SFT 2 +#define CPU_COMPACT_MODE_MASK_SFT BIT(2) +#define CPU_HD_ALIGN_SFT 1 +#define CPU_HD_ALIGN_MASK_SFT BIT(1) +#define SYSRAM_SIGN_SFT 0 +#define SYSRAM_SIGN_MASK_SFT BIT(0) + +/* AFE_IRQ_MCU_CON0 */ +#define IRQ31_MCU_ON_SFT 31 +#define IRQ31_MCU_ON_MASK 0x1 +#define IRQ31_MCU_ON_MASK_SFT BIT(31) +#define IRQ26_MCU_ON_SFT 26 +#define IRQ26_MCU_ON_MASK 0x1 +#define IRQ26_MCU_ON_MASK_SFT BIT(26) +#define IRQ25_MCU_ON_SFT 25 +#define IRQ25_MCU_ON_MASK 0x1 +#define IRQ25_MCU_ON_MASK_SFT BIT(25) +#define IRQ24_MCU_ON_SFT 24 +#define IRQ24_MCU_ON_MASK 0x1 +#define IRQ24_MCU_ON_MASK_SFT BIT(24) +#define IRQ23_MCU_ON_SFT 23 +#define IRQ23_MCU_ON_MASK 0x1 +#define IRQ23_MCU_ON_MASK_SFT BIT(23) +#define IRQ22_MCU_ON_SFT 22 +#define IRQ22_MCU_ON_MASK 0x1 +#define IRQ22_MCU_ON_MASK_SFT BIT(22) +#define IRQ21_MCU_ON_SFT 21 +#define IRQ21_MCU_ON_MASK 0x1 +#define IRQ21_MCU_ON_MASK_SFT BIT(21) +#define IRQ20_MCU_ON_SFT 20 +#define IRQ20_MCU_ON_MASK 0x1 +#define IRQ20_MCU_ON_MASK_SFT BIT(20) +#define IRQ19_MCU_ON_SFT 19 +#define IRQ19_MCU_ON_MASK 0x1 +#define IRQ19_MCU_ON_MASK_SFT BIT(19) +#define IRQ18_MCU_ON_SFT 18 +#define IRQ18_MCU_ON_MASK 0x1 +#define IRQ18_MCU_ON_MASK_SFT BIT(18) +#define IRQ17_MCU_ON_SFT 17 +#define IRQ17_MCU_ON_MASK 0x1 +#define IRQ17_MCU_ON_MASK_SFT BIT(17) +#define IRQ16_MCU_ON_SFT 16 +#define IRQ16_MCU_ON_MASK 0x1 +#define IRQ16_MCU_ON_MASK_SFT BIT(16) +#define IRQ15_MCU_ON_SFT 15 +#define IRQ15_MCU_ON_MASK 0x1 +#define IRQ15_MCU_ON_MASK_SFT BIT(15) +#define IRQ14_MCU_ON_SFT 14 +#define IRQ14_MCU_ON_MASK 0x1 +#define IRQ14_MCU_ON_MASK_SFT BIT(14) +#define IRQ13_MCU_ON_SFT 13 +#define IRQ13_MCU_ON_MASK 0x1 +#define IRQ13_MCU_ON_MASK_SFT BIT(13) +#define IRQ12_MCU_ON_SFT 12 +#define IRQ12_MCU_ON_MASK 0x1 +#define IRQ12_MCU_ON_MASK_SFT BIT(12) +#define IRQ11_MCU_ON_SFT 11 +#define IRQ11_MCU_ON_MASK 0x1 +#define IRQ11_MCU_ON_MASK_SFT BIT(11) +#define IRQ10_MCU_ON_SFT 10 +#define IRQ10_MCU_ON_MASK 0x1 +#define IRQ10_MCU_ON_MASK_SFT BIT(10) +#define IRQ9_MCU_ON_SFT 9 +#define IRQ9_MCU_ON_MASK 0x1 +#define IRQ9_MCU_ON_MASK_SFT BIT(9) +#define IRQ8_MCU_ON_SFT 8 +#define IRQ8_MCU_ON_MASK 0x1 +#define IRQ8_MCU_ON_MASK_SFT BIT(8) +#define IRQ7_MCU_ON_SFT 7 +#define IRQ7_MCU_ON_MASK 0x1 +#define IRQ7_MCU_ON_MASK_SFT BIT(7) +#define IRQ6_MCU_ON_SFT 6 +#define IRQ6_MCU_ON_MASK 0x1 +#define IRQ6_MCU_ON_MASK_SFT BIT(6) +#define IRQ5_MCU_ON_SFT 5 +#define IRQ5_MCU_ON_MASK 0x1 +#define IRQ5_MCU_ON_MASK_SFT BIT(5) +#define IRQ4_MCU_ON_SFT 4 +#define IRQ4_MCU_ON_MASK 0x1 +#define IRQ4_MCU_ON_MASK_SFT BIT(4) +#define IRQ3_MCU_ON_SFT 3 +#define IRQ3_MCU_ON_MASK 0x1 +#define IRQ3_MCU_ON_MASK_SFT BIT(3) +#define IRQ2_MCU_ON_SFT 2 +#define IRQ2_MCU_ON_MASK 0x1 +#define IRQ2_MCU_ON_MASK_SFT BIT(2) +#define IRQ1_MCU_ON_SFT 1 +#define IRQ1_MCU_ON_MASK 0x1 +#define IRQ1_MCU_ON_MASK_SFT BIT(1) +#define IRQ0_MCU_ON_SFT 0 +#define IRQ0_MCU_ON_MASK 0x1 +#define IRQ0_MCU_ON_MASK_SFT BIT(0) + +/* AFE_IRQ_MCU_CON1 */ +#define IRQ7_MCU_MODE_SFT 28 +#define IRQ7_MCU_MODE_MASK 0xf +#define IRQ7_MCU_MODE_MASK_SFT GENMASK(31, 28) +#define IRQ6_MCU_MODE_SFT 24 +#define IRQ6_MCU_MODE_MASK 0xf +#define IRQ6_MCU_MODE_MASK_SFT GENMASK(27, 24) +#define IRQ5_MCU_MODE_SFT 20 +#define IRQ5_MCU_MODE_MASK 0xf +#define IRQ5_MCU_MODE_MASK_SFT GENMASK(23, 20) +#define IRQ4_MCU_MODE_SFT 16 +#define IRQ4_MCU_MODE_MASK 0xf +#define IRQ4_MCU_MODE_MASK_SFT GENMASK(19, 16) +#define IRQ3_MCU_MODE_SFT 12 +#define IRQ3_MCU_MODE_MASK 0xf +#define IRQ3_MCU_MODE_MASK_SFT GENMASK(15, 12) +#define IRQ2_MCU_MODE_SFT 8 +#define IRQ2_MCU_MODE_MASK 0xf +#define IRQ2_MCU_MODE_MASK_SFT GENMASK(11, 8) +#define IRQ1_MCU_MODE_SFT 4 +#define IRQ1_MCU_MODE_MASK 0xf +#define IRQ1_MCU_MODE_MASK_SFT GENMASK(7, 4) +#define IRQ0_MCU_MODE_SFT 0 +#define IRQ0_MCU_MODE_MASK 0xf +#define IRQ0_MCU_MODE_MASK_SFT GENMASK(3, 0) + +/* AFE_IRQ_MCU_CON2 */ +#define IRQ15_MCU_MODE_SFT 28 +#define IRQ15_MCU_MODE_MASK 0xf +#define IRQ15_MCU_MODE_MASK_SFT GENMASK(31, 28) +#define IRQ14_MCU_MODE_SFT 24 +#define IRQ14_MCU_MODE_MASK 0xf +#define IRQ14_MCU_MODE_MASK_SFT GENMASK(27, 24) +#define IRQ13_MCU_MODE_SFT 20 +#define IRQ13_MCU_MODE_MASK 0xf +#define IRQ13_MCU_MODE_MASK_SFT GENMASK(23, 20) +#define IRQ12_MCU_MODE_SFT 16 +#define IRQ12_MCU_MODE_MASK 0xf +#define IRQ12_MCU_MODE_MASK_SFT GENMASK(19, 16) +#define IRQ11_MCU_MODE_SFT 12 +#define IRQ11_MCU_MODE_MASK 0xf +#define IRQ11_MCU_MODE_MASK_SFT GENMASK(15, 12) +#define IRQ10_MCU_MODE_SFT 8 +#define IRQ10_MCU_MODE_MASK 0xf +#define IRQ10_MCU_MODE_MASK_SFT GENMASK(11, 8) +#define IRQ9_MCU_MODE_SFT 4 +#define IRQ9_MCU_MODE_MASK 0xf +#define IRQ9_MCU_MODE_MASK_SFT GENMASK(7, 4) +#define IRQ8_MCU_MODE_SFT 0 +#define IRQ8_MCU_MODE_MASK 0xf +#define IRQ8_MCU_MODE_MASK_SFT GENMASK(3, 0) + +/* AFE_IRQ_MCU_CON3 */ +#define IRQ23_MCU_MODE_SFT 28 +#define IRQ23_MCU_MODE_MASK 0xf +#define IRQ23_MCU_MODE_MASK_SFT GENMASK(31, 28) +#define IRQ22_MCU_MODE_SFT 24 +#define IRQ22_MCU_MODE_MASK 0xf +#define IRQ22_MCU_MODE_MASK_SFT GENMASK(27, 24) +#define IRQ21_MCU_MODE_SFT 20 +#define IRQ21_MCU_MODE_MASK 0xf +#define IRQ21_MCU_MODE_MASK_SFT GENMASK(23, 20) +#define IRQ20_MCU_MODE_SFT 16 +#define IRQ20_MCU_MODE_MASK 0xf +#define IRQ20_MCU_MODE_MASK_SFT GENMASK(19, 16) +#define IRQ19_MCU_MODE_SFT 12 +#define IRQ19_MCU_MODE_MASK 0xf +#define IRQ19_MCU_MODE_MASK_SFT GENMASK(15, 12) +#define IRQ18_MCU_MODE_SFT 8 +#define IRQ18_MCU_MODE_MASK 0xf +#define IRQ18_MCU_MODE_MASK_SFT GENMASK(11, 8) +#define IRQ17_MCU_MODE_SFT 4 +#define IRQ17_MCU_MODE_MASK 0xf +#define IRQ17_MCU_MODE_MASK_SFT GENMASK(7, 4) +#define IRQ16_MCU_MODE_SFT 0 +#define IRQ16_MCU_MODE_MASK 0xf +#define IRQ16_MCU_MODE_MASK_SFT GENMASK(3, 0) + +/* AFE_IRQ_MCU_CON4 */ +#define IRQ26_MCU_MODE_SFT 8 +#define IRQ26_MCU_MODE_MASK 0xf +#define IRQ26_MCU_MODE_MASK_SFT GENMASK(11, 8) +#define IRQ25_MCU_MODE_SFT 4 +#define IRQ25_MCU_MODE_MASK 0xf +#define IRQ25_MCU_MODE_MASK_SFT GENMASK(7, 4) +#define IRQ24_MCU_MODE_SFT 0 +#define IRQ24_MCU_MODE_MASK 0xf +#define IRQ24_MCU_MODE_MASK_SFT GENMASK(3, 0) + +/* AFE_IRQ_MCU_CLR */ +#define IRQ31_MCU_CLR_SFT 31 +#define IRQ31_MCU_CLR_MASK_SFT BIT(31) +#define IRQ26_MCU_CLR_SFT 26 +#define IRQ26_MCU_CLR_MASK_SFT BIT(26) +#define IRQ25_MCU_CLR_SFT 25 +#define IRQ25_MCU_CLR_MASK_SFT BIT(25) +#define IRQ24_MCU_CLR_SFT 24 +#define IRQ24_MCU_CLR_MASK_SFT BIT(24) +#define IRQ23_MCU_CLR_SFT 23 +#define IRQ23_MCU_CLR_MASK_SFT BIT(23) +#define IRQ22_MCU_CLR_SFT 22 +#define IRQ22_MCU_CLR_MASK_SFT BIT(22) +#define IRQ21_MCU_CLR_SFT 21 +#define IRQ21_MCU_CLR_MASK_SFT BIT(21) +#define IRQ20_MCU_CLR_SFT 20 +#define IRQ20_MCU_CLR_MASK_SFT BIT(20) +#define IRQ19_MCU_CLR_SFT 19 +#define IRQ19_MCU_CLR_MASK_SFT BIT(19) +#define IRQ18_MCU_CLR_SFT 18 +#define IRQ18_MCU_CLR_MASK_SFT BIT(18) +#define IRQ17_MCU_CLR_SFT 17 +#define IRQ17_MCU_CLR_MASK_SFT BIT(17) +#define IRQ16_MCU_CLR_SFT 16 +#define IRQ16_MCU_CLR_MASK_SFT BIT(16) +#define IRQ15_MCU_CLR_SFT 15 +#define IRQ15_MCU_CLR_MASK_SFT BIT(15) +#define IRQ14_MCU_CLR_SFT 14 +#define IRQ14_MCU_CLR_MASK_SFT BIT(14) +#define IRQ13_MCU_CLR_SFT 13 +#define IRQ13_MCU_CLR_MASK_SFT BIT(13) +#define IRQ12_MCU_CLR_SFT 12 +#define IRQ12_MCU_CLR_MASK_SFT BIT(12) +#define IRQ11_MCU_CLR_SFT 11 +#define IRQ11_MCU_CLR_MASK_SFT BIT(11) +#define IRQ10_MCU_CLR_SFT 10 +#define IRQ10_MCU_CLR_MASK_SFT BIT(10) +#define IRQ9_MCU_CLR_SFT 9 +#define IRQ9_MCU_CLR_MASK_SFT BIT(9) +#define IRQ8_MCU_CLR_SFT 8 +#define IRQ8_MCU_CLR_MASK_SFT BIT(8) +#define IRQ7_MCU_CLR_SFT 7 +#define IRQ7_MCU_CLR_MASK_SFT BIT(7) +#define IRQ6_MCU_CLR_SFT 6 +#define IRQ6_MCU_CLR_MASK_SFT BIT(6) +#define IRQ5_MCU_CLR_SFT 5 +#define IRQ5_MCU_CLR_MASK_SFT BIT(5) +#define IRQ4_MCU_CLR_SFT 4 +#define IRQ4_MCU_CLR_MASK_SFT BIT(4) +#define IRQ3_MCU_CLR_SFT 3 +#define IRQ3_MCU_CLR_MASK_SFT BIT(3) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK_SFT BIT(2) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK_SFT BIT(1) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK_SFT BIT(0) + +/* AFE_IRQ_MCU_EN */ +#define IRQ31_MCU_EN_SFT 31 +#define IRQ30_MCU_EN_SFT 30 +#define IRQ29_MCU_EN_SFT 29 +#define IRQ28_MCU_EN_SFT 28 +#define IRQ27_MCU_EN_SFT 27 +#define IRQ26_MCU_EN_SFT 26 +#define IRQ25_MCU_EN_SFT 25 +#define IRQ24_MCU_EN_SFT 24 +#define IRQ23_MCU_EN_SFT 23 +#define IRQ22_MCU_EN_SFT 22 +#define IRQ21_MCU_EN_SFT 21 +#define IRQ20_MCU_EN_SFT 20 +#define IRQ19_MCU_EN_SFT 19 +#define IRQ18_MCU_EN_SFT 18 +#define IRQ17_MCU_EN_SFT 17 +#define IRQ16_MCU_EN_SFT 16 +#define IRQ15_MCU_EN_SFT 15 +#define IRQ14_MCU_EN_SFT 14 +#define IRQ13_MCU_EN_SFT 13 +#define IRQ12_MCU_EN_SFT 12 +#define IRQ11_MCU_EN_SFT 11 +#define IRQ10_MCU_EN_SFT 10 +#define IRQ9_MCU_EN_SFT 9 +#define IRQ8_MCU_EN_SFT 8 +#define IRQ7_MCU_EN_SFT 7 +#define IRQ6_MCU_EN_SFT 6 +#define IRQ5_MCU_EN_SFT 5 +#define IRQ4_MCU_EN_SFT 4 +#define IRQ3_MCU_EN_SFT 3 +#define IRQ2_MCU_EN_SFT 2 +#define IRQ1_MCU_EN_SFT 1 +#define IRQ0_MCU_EN_SFT 0 + +/* AFE_IRQ_MCU_SCP_EN */ +#define IRQ31_MCU_SCP_EN_SFT 31 +#define IRQ30_MCU_SCP_EN_SFT 30 +#define IRQ29_MCU_SCP_EN_SFT 29 +#define IRQ28_MCU_SCP_EN_SFT 28 +#define IRQ27_MCU_SCP_EN_SFT 27 +#define IRQ26_MCU_SCP_EN_SFT 26 +#define IRQ25_MCU_SCP_EN_SFT 25 +#define IRQ24_MCU_SCP_EN_SFT 24 +#define IRQ23_MCU_SCP_EN_SFT 23 +#define IRQ22_MCU_SCP_EN_SFT 22 +#define IRQ21_MCU_SCP_EN_SFT 21 +#define IRQ20_MCU_SCP_EN_SFT 20 +#define IRQ19_MCU_SCP_EN_SFT 19 +#define IRQ18_MCU_SCP_EN_SFT 18 +#define IRQ17_MCU_SCP_EN_SFT 17 +#define IRQ16_MCU_SCP_EN_SFT 16 +#define IRQ15_MCU_SCP_EN_SFT 15 +#define IRQ14_MCU_SCP_EN_SFT 14 +#define IRQ13_MCU_SCP_EN_SFT 13 +#define IRQ12_MCU_SCP_EN_SFT 12 +#define IRQ11_MCU_SCP_EN_SFT 11 +#define IRQ10_MCU_SCP_EN_SFT 10 +#define IRQ9_MCU_SCP_EN_SFT 9 +#define IRQ8_MCU_SCP_EN_SFT 8 +#define IRQ7_MCU_SCP_EN_SFT 7 +#define IRQ6_MCU_SCP_EN_SFT 6 +#define IRQ5_MCU_SCP_EN_SFT 5 +#define IRQ4_MCU_SCP_EN_SFT 4 +#define IRQ3_MCU_SCP_EN_SFT 3 +#define IRQ2_MCU_SCP_EN_SFT 2 +#define IRQ1_MCU_SCP_EN_SFT 1 +#define IRQ0_MCU_SCP_EN_SFT 0 + +/* AFE_IRQ_MCU_DSP_EN */ +#define IRQ31_MCU_DSP_EN_SFT 31 +#define IRQ30_MCU_DSP_EN_SFT 30 +#define IRQ29_MCU_DSP_EN_SFT 29 +#define IRQ28_MCU_DSP_EN_SFT 28 +#define IRQ27_MCU_DSP_EN_SFT 27 +#define IRQ26_MCU_DSP_EN_SFT 26 +#define IRQ25_MCU_DSP_EN_SFT 25 +#define IRQ24_MCU_DSP_EN_SFT 24 +#define IRQ23_MCU_DSP_EN_SFT 23 +#define IRQ22_MCU_DSP_EN_SFT 22 +#define IRQ21_MCU_DSP_EN_SFT 21 +#define IRQ20_MCU_DSP_EN_SFT 20 +#define IRQ19_MCU_DSP_EN_SFT 19 +#define IRQ18_MCU_DSP_EN_SFT 18 +#define IRQ17_MCU_DSP_EN_SFT 17 +#define IRQ16_MCU_DSP_EN_SFT 16 +#define IRQ15_MCU_DSP_EN_SFT 15 +#define IRQ14_MCU_DSP_EN_SFT 14 +#define IRQ13_MCU_DSP_EN_SFT 13 +#define IRQ12_MCU_DSP_EN_SFT 12 +#define IRQ11_MCU_DSP_EN_SFT 11 +#define IRQ10_MCU_DSP_EN_SFT 10 +#define IRQ9_MCU_DSP_EN_SFT 9 +#define IRQ8_MCU_DSP_EN_SFT 8 +#define IRQ7_MCU_DSP_EN_SFT 7 +#define IRQ6_MCU_DSP_EN_SFT 6 +#define IRQ5_MCU_DSP_EN_SFT 5 +#define IRQ4_MCU_DSP_EN_SFT 4 +#define IRQ3_MCU_DSP_EN_SFT 3 +#define IRQ2_MCU_DSP_EN_SFT 2 +#define IRQ1_MCU_DSP_EN_SFT 1 +#define IRQ0_MCU_DSP_EN_SFT 0 + +/* AFE_AUD_PAD_TOP */ +#define AUD_PAD_TOP_MON_SFT 15 +#define AUD_PAD_TOP_MON_MASK_SFT GENMASK(31, 15) +#define AUD_PAD_TOP_FIFO_RSP_SFT 4 +#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT GENMASK(7, 4) +#define RG_RX_PROTOCOL2_SFT 3 +#define RG_RX_PROTOCOL2_MASK_SFT BIT(3) +#define RESERVDED_01_SFT 1 +#define RESERVDED_01_MASK_SFT GENMASK(2, 1) +#define RG_RX_FIFO_ON_SFT 0 +#define RG_RX_FIFO_ON_MASK_SFT BIT(0) + +/* AFE_ADDA_MTKAIF_SYNCWORD_CFG */ +#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT 23 +#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK_SFT BIT(23) + +/* AFE_ADDA_MTKAIF_RX_CFG0 */ +#define MTKAIF_RXIF_VOICE_MODE_SFT 20 +#define MTKAIF_RXIF_VOICE_MODE_MASK_SFT GENMASK(23, 20) +#define MTKAIF_RXIF_DETECT_ON_SFT 16 +#define MTKAIF_RXIF_DETECT_ON_MASK_SFT BIT(16) +#define MTKAIF_RXIF_DATA_BIT_SFT 8 +#define MTKAIF_RXIF_DATA_BIT_MASK_SFT GENMASK(10, 8) +#define MTKAIF_RXIF_FIFO_RSP_SFT 4 +#define MTKAIF_RXIF_FIFO_RSP_MASK_SFT GENMASK(6, 4) +#define MTKAIF_RXIF_DATA_MODE_SFT 0 +#define MTKAIF_RXIF_DATA_MODE_MASK_SFT BIT(0) + +/* GENERAL_ASRC_MODE */ +#define GENERAL2_ASRCOUT_MODE_SFT 12 +#define GENERAL2_ASRCOUT_MODE_MASK 0xf +#define GENERAL2_ASRCOUT_MODE_MASK_SFT GENMASK(15, 12) +#define GENERAL2_ASRCIN_MODE_SFT 8 +#define GENERAL2_ASRCIN_MODE_MASK 0xf +#define GENERAL2_ASRCIN_MODE_MASK_SFT GENMASK(11, 8) +#define GENERAL1_ASRCOUT_MODE_SFT 4 +#define GENERAL1_ASRCOUT_MODE_MASK 0xf +#define GENERAL1_ASRCOUT_MODE_MASK_SFT GENMASK(7, 4) +#define GENERAL1_ASRCIN_MODE_SFT 0 +#define GENERAL1_ASRCIN_MODE_MASK 0xf +#define GENERAL1_ASRCIN_MODE_MASK_SFT GENMASK(3, 0) + +/* GENERAL_ASRC_EN_ON */ +#define GENERAL2_ASRC_EN_ON_SFT 1 +#define GENERAL2_ASRC_EN_ON_MASK_SFT BIT(1) +#define GENERAL1_ASRC_EN_ON_SFT 0 +#define GENERAL1_ASRC_EN_ON_MASK_SFT BIT(0) + +/* AFE_GENERAL1_ASRC_2CH_CON0 */ +#define G_SRC_CHSET_STR_CLR_SFT 4 +#define G_SRC_CHSET_STR_CLR_MASK_SFT BIT(4) +#define G_SRC_CHSET_ON_SFT 2 +#define G_SRC_CHSET_ON_MASK_SFT BIT(2) +#define G_SRC_COEFF_SRAM_CTRL_SFT 1 +#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT BIT(1) +#define G_SRC_ASM_ON_SFT 0 +#define G_SRC_ASM_ON_MASK_SFT BIT(0) + +/* AFE_GENERAL1_ASRC_2CH_CON3 */ +#define G_SRC_ASM_FREQ_4_SFT 0 +#define G_SRC_ASM_FREQ_4_MASK_SFT GENMASK(23, 0) + +/* AFE_GENERAL1_ASRC_2CH_CON4 */ +#define G_SRC_ASM_FREQ_5_SFT 0 +#define G_SRC_ASM_FREQ_5_MASK_SFT GENMASK(23, 0) + +/* AFE_GENERAL1_ASRC_2CH_CON13 */ +#define G_SRC_COEFF_SRAM_ADR_SFT 0 +#define G_SRC_COEFF_SRAM_ADR_MASK_SFT GENMASK(5, 0) + +/* AFE_GENERAL1_ASRC_2CH_CON2 */ +#define G_SRC_CHSET_O16BIT_SFT 19 +#define G_SRC_CHSET_O16BIT_MASK_SFT BIT(19) +#define G_SRC_CHSET_CLR_IIR_HISTORY_SFT 17 +#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK_SFT BIT(17) +#define G_SRC_CHSET_IS_MONO_SFT 16 +#define G_SRC_CHSET_IS_MONO_MASK_SFT BIT(16) +#define G_SRC_CHSET_IIR_EN_SFT 11 +#define G_SRC_CHSET_IIR_EN_MASK_SFT BIT(11) +#define G_SRC_CHSET_IIR_STAGE_SFT 8 +#define G_SRC_CHSET_IIR_STAGE_MASK_SFT GENMASK(10, 8) +#define G_SRC_CHSET_STR_CLR_RU_SFT 5 +#define G_SRC_CHSET_STR_CLR_RU_MASK_SFT BIT(5) +#define G_SRC_CHSET_ON_SFT 2 +#define G_SRC_CHSET_ON_MASK_SFT BIT(2) +#define G_SRC_COEFF_SRAM_CTRL_SFT 1 +#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT BIT(1) +#define G_SRC_ASM_ON_SFT 0 +#define G_SRC_ASM_ON_MASK_SFT BIT(0) + +/* AFE_ADDA_DL_SDM_DITHER_CON */ +#define AFE_DL_SDM_DITHER_64TAP_EN_SFT 20 +#define AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT BIT(20) +#define AFE_DL_SDM_DITHER_EN_SFT 16 +#define AFE_DL_SDM_DITHER_EN_MASK_SFT BIT(16) +#define AFE_DL_SDM_DITHER_GAIN_SFT 0 +#define AFE_DL_SDM_DITHER_GAIN_MASK_SFT GENMASK(7, 0) + +/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */ +#define SDM_AUTO_RESET_TEST_ON_SFT 31 +#define SDM_AUTO_RESET_TEST_ON_MASK_SFT BIT(31) +#define AFE_DL_USE_NEW_2ND_SDM_SFT 28 +#define AFE_DL_USE_NEW_2ND_SDM_MASK_SFT BIT(28) +#define SDM_AUTO_RESET_COUNT_TH_SFT 0 +#define SDM_AUTO_RESET_COUNT_TH_MASK_SFT GENMASK(23, 0) + +/* AFE_ASRC_2CH_CON0 */ +#define CON0_CHSET_STR_CLR_SFT 4 +#define CON0_CHSET_STR_CLR_MASK_SFT BIT(4) +#define CON0_ASM_ON_SFT 0 +#define CON0_ASM_ON_MASK_SFT BIT(0) + +/* AFE_ASRC_2CH_CON5 */ +#define CALI_EN_SFT 0 +#define CALI_EN_MASK_SFT BIT(0) + +/* FPGA_CFG4 */ +#define IRQ_COUNTER_SFT 3 +#define IRQ_COUNTER_MASK_SFT GENMASK(31, 3) +#define IRQ_CLK_COUNTER_CLEAN_SFT 2 +#define IRQ_CLK_COUNTER_CLEAN_MASK_SFT BIT(2) +#define IRQ_CLK_COUNTER_PAUSE_SFT 1 +#define IRQ_CLK_COUNTER_PAUSE_MASK_SFT BIT(1) +#define IRQ_CLK_COUNTER_ON_SFT 0 +#define IRQ_CLK_COUNTER_ON_MASK_SFT BIT(0) + +/* FPGA_CFG5 */ +#define WR_MSTR_ON_SFT 16 +#define WR_MSTR_ON_MASK_SFT GENMASK(28, 16) +#define WR_AG_SEL_SFT 0 +#define WR_AG_SEL_MASK_SFT GENMASK(12, 0) + +/* FPGA_CFG6 */ +#define WR_MSTR_REQ_REAL_SFT 16 +#define WR_MSTR_REQ_REAL_MASK_SFT GENMASK(28, 16) +#define WR_MSTR_REQ_IN_SFT 0 +#define WR_MSTR_REQ_IN_MASK_SFT GENMASK(12, 0) + +/* FPGA_CFG7 */ +#define MEM1_WDATA_MON0_SFT 0 +#define MEM1_WDATA_MON0_MASK_SFT GENMASK(31, 0) + +/* FPGA_CFG8 */ +#define MEM1_WDATA_MON1_SFT 0 +#define MEM1_WDATA_MON1_MASK_SFT GENMASK(31, 0) + +/* FPGA_CFG9 */ +#define MEM_WE_SFT 31 +#define MEM_WE_MASK_SFT BIT(31) +#define AFE_HREADY_SFT 30 +#define AFE_HREADY_MASK_SFT BIT(30) +#define MEM_WR_REQ_SFT 29 +#define MEM_WR_REQ_MASK_SFT BIT(29) +#define WR_AG_REG_MON_SFT 16 +#define WR_AG_REG_MON_MASK_SFT GENMASK(28, 16) +#define HCLK_CK_SFT 15 +#define HCLK_CK_MASK_SFT BIT(15) +#define MEM_RD_REQ_SFT 14 +#define MEM_RD_REQ_MASK_SFT BIT(14) +#define RD_AG_REQ_MON_SFT 0 +#define RD_AG_REQ_MON_MASK_SFT GENMASK(13, 0) + +/* FPGA_CFG10 */ +#define MEM_BYTE_0_SFT 0 +#define MEM_BYTE_0_MASK_SFT GENMASK(31, 0) + +/* FPGA_CFG11 */ +#define MEM_BYTE_1_SFT 0 +#define MEM_BYTE_1_MASK_SFT GENMASK(31, 0) + +/* FPGA_CFG12 */ +#define RDATA_CNT_SFT 30 +#define RDATA_CNT_MASK_SFT GENMASK(31, 30) +#define MS2_HREADY_SFT 29 +#define MS2_HREADY_MASK_SFT BIT(29) +#define MS1_HREADY_SFT 28 +#define MS1_HREADY_MASK_SFT BIT(28) +#define AG_SEL_SFT 0 +#define AG_SEL_MASK_SFT GENMASK(25, 0) + +/* FPGA_CFG13 */ +#define AFE_ST_SFT 27 +#define AFE_ST_MASK_SFT GENMASK(31, 27) +#define AG_IN_SERVICE_SFT 0 +#define AG_IN_SERVICE_MASK_SFT GENMASK(25, 0) + +/* ETDM_IN1_CON0 */ +#define ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT 0 +#define ETDM_IN1_CON0_REG_ETDM_IN_EN_MASK_SFT BIT(0) +#define ETDM_IN1_CON0_REG_SYNC_MODE_SFT 1 +#define ETDM_IN1_CON0_REG_SYNC_MODE_MASK_SFT BIT(1) +#define ETDM_IN1_CON0_REG_LSB_FIRST_SFT 3 +#define ETDM_IN1_CON0_REG_LSB_FIRST_MASK_SFT BIT(3) +#define ETDM_IN1_CON0_REG_SOFT_RST_SFT 4 +#define ETDM_IN1_CON0_REG_SOFT_RST_MASK_SFT BIT(4) +#define ETDM_IN1_CON0_REG_SLAVE_MODE_SFT 5 +#define ETDM_IN1_CON0_REG_SLAVE_MODE_MASK_SFT BIT(5) +#define ETDM_IN1_CON0_REG_FMT_SFT 6 +#define ETDM_IN1_CON0_REG_FMT_MASK_SFT GENMASK(8, 6) +#define ETDM_IN1_CON0_REG_LRCK_EDGE_SEL_SFT 10 +#define ETDM_IN1_CON0_REG_LRCK_EDGE_SEL_MASK_SFT BIT(10) +#define ETDM_IN1_CON0_REG_BIT_LENGTH_SFT 11 +#define ETDM_IN1_CON0_REG_BIT_LENGTH_MASK_SFT GENMASK(15, 11) +#define ETDM_IN1_CON0_REG_WORD_LENGTH_SFT 16 +#define ETDM_IN1_CON0_REG_WORD_LENGTH_MASK_SFT GENMASK(20, 16) +#define ETDM_IN1_CON0_REG_CH_NUM_SFT 23 +#define ETDM_IN1_CON0_REG_CH_NUM_MASK_SFT GENMASK(27, 23) +#define ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT 28 +#define ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_MASK_SFT GENMASK(31, 28) +#define ETDM_IN1_CON0_REG_VALID_TOGETHER_SFT 31 +#define ETDM_IN1_CON0_REG_VALID_TOGETHER_MASK_SFT BIT(31) +#define ETDM_IN_CON0_CTRL_MASK 0x1f9ff9e2 + +/* ETDM_IN1_CON1 */ +#define ETDM_IN1_CON1_REG_INITIAL_COUNT_SFT 0 +#define ETDM_IN1_CON1_REG_INITIAL_COUNT_MASK_SFT GENMASK(4, 0) +#define ETDM_IN1_CON1_REG_INITIAL_POINT_SFT 5 +#define ETDM_IN1_CON1_REG_INITIAL_POINT_MASK_SFT GENMASK(9, 5) +#define ETDM_IN1_CON1_REG_LRCK_AUTO_OFF_SFT 10 +#define ETDM_IN1_CON1_REG_LRCK_AUTO_OFF_MASK_SFT BIT(10) +#define ETDM_IN1_CON1_REG_BCK_AUTO_OFF_SFT 11 +#define ETDM_IN1_CON1_REG_BCK_AUTO_OFF_MASK_SFT BIT(11) +#define ETDM_IN1_CON1_REG_INITIAL_LRCK_SFT 13 +#define ETDM_IN1_CON1_REG_INITIAL_LRCK_MASK_SFT BIT(13) +#define ETDM_IN1_CON1_REG_LRCK_RESET_SFT 15 +#define ETDM_IN1_CON1_REG_LRCK_RESET_MASK_SFT BIT(15) +#define ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT 16 +#define ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_MASK_SFT BIT(16) +#define ETDM_IN1_CON1_REG_OUTPUT_CR_EN_SFT 18 +#define ETDM_IN1_CON1_REG_OUTPUT_CR_EN_MASK_SFT BIT(18) +#define ETDM_IN1_CON1_REG_LR_ALIGN_SFT 19 +#define ETDM_IN1_CON1_REG_LR_ALIGN_MASK_SFT BIT(19) +#define ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT 20 +#define ETDM_IN1_CON1_REG_LRCK_WIDTH_MASK_SFT GENMASK(29, 20) +#define ETDM_IN1_CON1_REG_DIRECT_INPUT_MASTER_BCK_SFT 30 +#define ETDM_IN1_CON1_REG_DIRECT_INPUT_MASTER_BCK_MASK_SFT BIT(30) +#define ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT 31 +#define ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_MASK_SFT BIT(31) +#define ETDM_IN_CON1_CTRL_MASK 0xbff10000 + +/* ETDM_IN1_CON2 */ +#define ETDM_IN1_CON2_REG_UPDATE_POINT_SFT 0 +#define ETDM_IN1_CON2_REG_UPDATE_POINT_MASK_SFT GENMASK(4, 0) +#define ETDM_IN1_CON2_REG_UPDATE_GAP_SFT 5 +#define ETDM_IN1_CON2_REG_UPDATE_GAP_MASK_SFT GENMASK(9, 5) +#define ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT 10 +#define ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_MASK_SFT GENMASK(12, 10) +#define ETDM_IN1_CON2_REG_AGENT_USE_ETDM_BCK_SFT 13 +#define ETDM_IN1_CON2_REG_AGENT_USE_ETDM_BCK_MASK_SFT BIT(13) +#define ETDM_IN1_CON2_REG_CK_EN_SEL_AUTO_SFT 14 +#define ETDM_IN1_CON2_REG_CK_EN_SEL_AUTO_MASK_SFT BIT(14) +#define ETDM_IN1_CON2_REG_MULTI_IP_ONE_DATA_CH_NUM_SFT 15 +#define ETDM_IN1_CON2_REG_MULTI_IP_ONE_DATA_CH_NUM_MASK_SFT GENMASK(19, 15) +#define ETDM_IN1_CON2_REG_MASK_AUTO_SFT 20 +#define ETDM_IN1_CON2_REG_MASK_AUTO_MASK_SFT BIT(20) +#define ETDM_IN1_CON2_REG_MASK_NUM_SFT 21 +#define ETDM_IN1_CON2_REG_MASK_NUM_MASK_SFT GENMASK(25, 21) +#define ETDM_IN1_CON2_REG_UPDATE_POINT_AUTO_SFT 26 +#define ETDM_IN1_CON2_REG_UPDATE_POINT_AUTO_MASK_SFT BIT(26) +#define ETDM_IN1_CON2_REG_SDATA_DELAY_0P5T_EN_SFT 27 +#define ETDM_IN1_CON2_REG_SDATA_DELAY_0P5T_EN_MASK_SFT BIT(27) +#define ETDM_IN1_CON2_REG_SDATA_DELAY_BCK_INV_SFT 28 +#define ETDM_IN1_CON2_REG_SDATA_DELAY_BCK_INV_MASK_SFT BIT(28) +#define ETDM_IN1_CON2_REG_LRCK_DELAY_0P5T_EN_SFT 29 +#define ETDM_IN1_CON2_REG_LRCK_DELAY_0P5T_EN_MASK_SFT BIT(29) +#define ETDM_IN1_CON2_REG_LRCK_DELAY_BCK_INV_SFT 30 +#define ETDM_IN1_CON2_REG_LRCK_DELAY_BCK_INV_MASK_SFT BIT(30) +#define ETDM_IN1_CON2_REG_MULTI_IP_MODE_SFT 31 +#define ETDM_IN1_CON2_REG_MULTI_IP_MODE_MASK_SFT BIT(31) +#define ETDM_IN_CON2_CTRL_MASK 0x800f8000 +#define ETDM_IN_CON2_MULTI_IP_CH(x) (((x) - 1) << 15) +#define ETDM_IN_CON2_MULTI_IP_2CH_MODE BIT(31) + +/* ETDM_IN1_CON3 */ +#define ETDM_IN1_CON3_REG_DISABLE_OUT_0_SFT 0 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_0_MASK_SFT BIT(0) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_1_SFT 1 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_1_MASK_SFT BIT(1) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_2_SFT 2 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_2_MASK_SFT BIT(2) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_3_SFT 3 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_3_MASK_SFT BIT(3) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_4_SFT 4 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_4_MASK_SFT BIT(4) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_5_SFT 5 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_5_MASK_SFT BIT(5) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_6_SFT 6 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_6_MASK_SFT BIT(6) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_7_SFT 7 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_7_MASK_SFT BIT(7) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_8_SFT 8 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_8_MASK_SFT BIT(8) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_9_SFT 9 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_9_MASK_SFT BIT(9) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_10_SFT 10 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_10_MASK_SFT BIT(10) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_11_SFT 11 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_11_MASK_SFT BIT(11) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_12_SFT 12 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_12_MASK_SFT BIT(12) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_13_SFT 13 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_13_MASK_SFT BIT(13) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_14_SFT 14 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_14_MASK_SFT BIT(14) +#define ETDM_IN1_CON3_REG_DISABLE_OUT_15_SFT 15 +#define ETDM_IN1_CON3_REG_DISABLE_OUT_15_MASK_SFT BIT(15) +#define ETDM_IN1_CON3_REG_RJ_DATA_RIGHT_ALIGN_SFT 16 +#define ETDM_IN1_CON3_REG_RJ_DATA_RIGHT_ALIGN_MASK_SFT BIT(16) +#define ETDM_IN1_CON3_REG_MONITOR_SEL_SFT 17 +#define ETDM_IN1_CON3_REG_MONITOR_SEL_MASK_SFT GENMASK(18, 17) +#define ETDM_IN1_CON3_REG_CNT_UPPER_LIMIT_SFT 19 +#define ETDM_IN1_CON3_REG_CNT_UPPER_LIMIT_MASK_SFT GENMASK(24, 19) +#define ETDM_IN1_CON3_REG_COMPACT_SAMPLE_END_DIS_SFT 25 +#define ETDM_IN1_CON3_REG_COMPACT_SAMPLE_END_DIS_MASK_SFT BIT(25) +#define ETDM_IN1_CON3_REG_FS_TIMING_SEL_SFT 26 +#define ETDM_IN1_CON3_REG_FS_TIMING_SEL_MASK_SFT GENMASK(30, 26) +#define ETDM_IN1_CON3_REG_SAMPLE_END_MODE_SFT 31 +#define ETDM_IN1_CON3_REG_SAMPLE_END_MODE_MASK_SFT BIT(31) +#define ETDM_IN_CON3_CTRL_MASK (0x7c000000) +#define ETDM_IN_CON3_FS(x) (((x) & 0x1f) << 26) + +/* ETDM_IN1_CON4 */ +#define ETDM_IN1_CON4_REG_DSD_MODE_SFT 0 +#define ETDM_IN1_CON4_REG_DSD_MODE_MASK_SFT GENMASK(5, 0) +#define ETDM_IN1_CON4_REG_DSD_REPACK_AUTO_MODE_SFT 8 +#define ETDM_IN1_CON4_REG_DSD_REPACK_AUTO_MODE_MASK_SFT BIT(8) +#define ETDM_IN1_CON4_REG_REPACK_WORD_LENGTH_SFT 9 +#define ETDM_IN1_CON4_REG_REPACK_WORD_LENGTH_MASK_SFT GENMASK(10, 9) +#define ETDM_IN1_CON4_REG_ASYNC_RESET_SFT 11 +#define ETDM_IN1_CON4_REG_ASYNC_RESET_MASK_SFT BIT(11) +#define ETDM_IN1_CON4_REG_DSD_CHNUM_SFT 12 +#define ETDM_IN1_CON4_REG_DSD_CHNUM_MASK_SFT GENMASK(15, 12) +#define ETDM_IN1_CON4_REG_SLAVE_BCK_INV_SFT 16 +#define ETDM_IN1_CON4_REG_SLAVE_BCK_INV_MASK_SFT BIT(16) +#define ETDM_IN1_CON4_REG_SLAVE_LRCK_INV_SFT 17 +#define ETDM_IN1_CON4_REG_SLAVE_LRCK_INV_MASK_SFT BIT(17) +#define ETDM_IN1_CON4_REG_MASTER_BCK_INV_SFT 18 +#define ETDM_IN1_CON4_REG_MASTER_BCK_INV_MASK_SFT BIT(18) +#define ETDM_IN1_CON4_REG_MASTER_LRCK_INV_SFT 19 +#define ETDM_IN1_CON4_REG_MASTER_LRCK_INV_MASK_SFT BIT(19) +#define ETDM_IN1_CON4_REG_RELATCH_1X_EN_SEL_SFT 20 +#define ETDM_IN1_CON4_REG_RELATCH_1X_EN_SEL_MASK_SFT GENMASK(24, 20) +#define ETDM_IN1_CON4_REG_SAMPLE_END_POINT_SFT 25 +#define ETDM_IN1_CON4_REG_SAMPLE_END_POINT_MASK_SFT GENMASK(29, 25) +#define ETDM_IN1_CON4_REG_WAIT_LAST_SAMPLE_SFT 30 +#define ETDM_IN1_CON4_REG_WAIT_LAST_SAMPLE_MASK_SFT BIT(30) +#define ETDM_IN1_CON4_REG_MASTER_BCK_FORCE_ON_SFT 31 +#define ETDM_IN1_CON4_REG_MASTER_BCK_FORCE_ON_MASK_SFT BIT(31) +#define ETDM_IN_CON4_CTRL_MASK 0x1ff0000 +#define ETDM_IN_CON4_FS(x) (((x) & 0x1f) << 20) +#define ETDM_IN_CON4_CON0_MASTER_LRCK_INV BIT(19) +#define ETDM_IN_CON4_CON0_MASTER_BCK_INV BIT(18) +#define ETDM_IN_CON4_CON0_SLAVE_LRCK_INV BIT(17) +#define ETDM_IN_CON4_CON0_SLAVE_BCK_INV BIT(16) + +/* ETDM_IN1_CON5 */ +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_0_SFT 0 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_0_MASK_SFT BIT(0) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_1_SFT 1 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_1_MASK_SFT BIT(1) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_2_SFT 2 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_2_MASK_SFT BIT(2) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_3_SFT 3 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_3_MASK_SFT BIT(3) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_4_SFT 4 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_4_MASK_SFT BIT(4) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_5_SFT 5 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_5_MASK_SFT BIT(5) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_6_SFT 6 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_6_MASK_SFT BIT(6) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_7_SFT 7 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_7_MASK_SFT BIT(7) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_8_SFT 8 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_8_MASK_SFT BIT(8) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_9_SFT 9 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_9_MASK_SFT BIT(9) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_10_SFT 10 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_10_MASK_SFT BIT(10) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_11_SFT 11 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_11_MASK_SFT BIT(11) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_12_SFT 12 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_12_MASK_SFT BIT(12) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_13_SFT 13 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_13_MASK_SFT BIT(13) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_14_SFT 14 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_14_MASK_SFT BIT(14) +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_15_SFT 15 +#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_15_MASK_SFT BIT(15) +#define ETDM_IN1_CON5_REG_LR_SWAP_0_SFT 16 +#define ETDM_IN1_CON5_REG_LR_SWAP_0_MASK_SFT BIT(16) +#define ETDM_IN1_CON5_REG_LR_SWAP_1_SFT 17 +#define ETDM_IN1_CON5_REG_LR_SWAP_1_MASK_SFT BIT(17) +#define ETDM_IN1_CON5_REG_LR_SWAP_2_SFT 18 +#define ETDM_IN1_CON5_REG_LR_SWAP_2_MASK_SFT BIT(18) +#define ETDM_IN1_CON5_REG_LR_SWAP_3_SFT 19 +#define ETDM_IN1_CON5_REG_LR_SWAP_3_MASK_SFT BIT(19) +#define ETDM_IN1_CON5_REG_LR_SWAP_4_SFT 20 +#define ETDM_IN1_CON5_REG_LR_SWAP_4_MASK_SFT BIT(20) +#define ETDM_IN1_CON5_REG_LR_SWAP_5_SFT 21 +#define ETDM_IN1_CON5_REG_LR_SWAP_5_MASK_SFT BIT(21) +#define ETDM_IN1_CON5_REG_LR_SWAP_6_SFT 22 +#define ETDM_IN1_CON5_REG_LR_SWAP_6_MASK_SFT BIT(22) +#define ETDM_IN1_CON5_REG_LR_SWAP_7_SFT 23 +#define ETDM_IN1_CON5_REG_LR_SWAP_7_MASK_SFT BIT(23) +#define ETDM_IN1_CON5_REG_LR_SWAP_8_SFT 24 +#define ETDM_IN1_CON5_REG_LR_SWAP_8_MASK_SFT BIT(24) +#define ETDM_IN1_CON5_REG_LR_SWAP_9_SFT 25 +#define ETDM_IN1_CON5_REG_LR_SWAP_9_MASK_SFT BIT(25) +#define ETDM_IN1_CON5_REG_LR_SWAP_10_SFT 26 +#define ETDM_IN1_CON5_REG_LR_SWAP_10_MASK_SFT BIT(26) +#define ETDM_IN1_CON5_REG_LR_SWAP_11_SFT 27 +#define ETDM_IN1_CON5_REG_LR_SWAP_11_MASK_SFT BIT(27) +#define ETDM_IN1_CON5_REG_LR_SWAP_12_SFT 28 +#define ETDM_IN1_CON5_REG_LR_SWAP_12_MASK_SFT BIT(28) +#define ETDM_IN1_CON5_REG_LR_SWAP_13_SFT 29 +#define ETDM_IN1_CON5_REG_LR_SWAP_13_MASK_SFT BIT(29) +#define ETDM_IN1_CON5_REG_LR_SWAP_14_SFT 30 +#define ETDM_IN1_CON5_REG_LR_SWAP_14_MASK_SFT BIT(30) +#define ETDM_IN1_CON5_REG_LR_SWAP_15_SFT 31 +#define ETDM_IN1_CON5_REG_LR_SWAP_15_MASK_SFT BIT(31) + +/* ETDM_IN1_CON6 */ +#define ETDM_IN1_CON6_LCH_DATA_REG_SFT 0 +#define ETDM_IN1_CON6_LCH_DATA_REG_MASK_SFT GENMASK(31, 0) + +/* ETDM_IN1_CON7 */ +#define ETDM_IN1_CON7_RCH_DATA_REG_SFT 0 +#define ETDM_IN1_CON7_RCH_DATA_REG_MASK_SFT GENMASK(31, 0) + +/* ETDM_IN1_CON8 */ +#define ETDM_IN1_CON8_REG_AFIFO_THRESHOLD_SFT 29 +#define ETDM_IN1_CON8_REG_AFIFO_THRESHOLD_MASK_SFT GENMASK(30, 29) +#define ETDM_IN1_CON8_REG_CK_EN_SEL_MANUAL_SFT 16 +#define ETDM_IN1_CON8_REG_CK_EN_SEL_MANUAL_MASK_SFT GENMASK(25, 16) +#define ETDM_IN1_CON8_REG_AFIFO_SW_RESET_SFT 15 +#define ETDM_IN1_CON8_REG_AFIFO_SW_RESET_MASK_SFT BIT(15) +#define ETDM_IN1_CON8_REG_AFIFO_RESET_SEL_SFT 14 +#define ETDM_IN1_CON8_REG_AFIFO_RESET_SEL_MASK_SFT BIT(14) +#define ETDM_IN1_CON8_REG_AFIFO_AUTO_RESET_DIS_SFT 9 +#define ETDM_IN1_CON8_REG_AFIFO_AUTO_RESET_DIS_MASK_SFT BIT(9) +#define ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT 8 +#define ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_MASK_SFT BIT(8) +#define ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT 5 +#define ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_MASK_SFT GENMASK(7, 5) +#define ETDM_IN1_CON8_REG_AFIFO_MODE_SFT 0 +#define ETDM_IN1_CON8_REG_AFIFO_MODE_MASK_SFT GENMASK(4, 0) +#define ETDM_IN_CON8_FS(x) (((x) & 0x1f) << 0) +#define ETDM_IN_CON8_CTRL_MASK 0x13f + +#define AUDIO_TOP_CON0 0x0000 +#define AUDIO_TOP_CON1 0x0004 +#define AUDIO_TOP_CON2 0x0008 +#define AUDIO_TOP_CON3 0x000c +#define AFE_DAC_CON0 0x0010 +#define AFE_I2S_CON 0x0018 +#define AFE_CONN0 0x0020 +#define AFE_CONN1 0x0024 +#define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002c +#define AFE_CONN4 0x0030 +#define AFE_I2S_CON1 0x0034 +#define AFE_I2S_CON2 0x0038 +#define AFE_I2S_CON3 0x0040 +#define AFE_CONN5 0x0044 +#define AFE_CONN_24BIT 0x0048 +#define AFE_DL1_CON0 0x004c +#define AFE_DL1_BASE_MSB 0x0050 +#define AFE_DL1_BASE 0x0054 +#define AFE_DL1_CUR_MSB 0x0058 +#define AFE_DL1_CUR 0x005c +#define AFE_DL1_END_MSB 0x0060 +#define AFE_DL1_END 0x0064 +#define AFE_DL2_CON0 0x0068 +#define AFE_DL2_BASE_MSB 0x006c +#define AFE_DL2_BASE 0x0070 +#define AFE_DL2_CUR_MSB 0x0074 +#define AFE_DL2_CUR 0x0078 +#define AFE_DL2_END_MSB 0x007c +#define AFE_DL2_END 0x0080 +#define AFE_DL3_CON0 0x0084 +#define AFE_DL3_BASE_MSB 0x0088 +#define AFE_DL3_BASE 0x008c +#define AFE_DL3_CUR_MSB 0x0090 +#define AFE_DL3_CUR 0x0094 +#define AFE_DL3_END_MSB 0x0098 +#define AFE_DL3_END 0x009c +#define AFE_CONN6 0x00bc +#define AFE_DL4_CON0 0x00cc +#define AFE_DL4_BASE_MSB 0x00d0 +#define AFE_DL4_BASE 0x00d4 +#define AFE_DL4_CUR_MSB 0x00d8 +#define AFE_DL4_CUR 0x00dc +#define AFE_DL4_END_MSB 0x00e0 +#define AFE_DL4_END 0x00e4 +#define AFE_DL12_CON0 0x00e8 +#define AFE_DL12_BASE_MSB 0x00ec +#define AFE_DL12_BASE 0x00f0 +#define AFE_DL12_CUR_MSB 0x00f4 +#define AFE_DL12_CUR 0x00f8 +#define AFE_DL12_END_MSB 0x00fc +#define AFE_DL12_END 0x0100 +#define AFE_ADDA_DL_SRC2_CON0 0x0108 +#define AFE_ADDA_DL_SRC2_CON1 0x010c +#define AFE_ADDA_UL_SRC_CON0 0x0114 +#define AFE_ADDA_UL_SRC_CON1 0x0118 +#define AFE_ADDA_TOP_CON0 0x0120 +#define AFE_ADDA_UL_DL_CON0 0x0124 +#define AFE_ADDA_SRC_DEBUG 0x012c +#define AFE_ADDA_SRC_DEBUG_MON0 0x0130 +#define AFE_ADDA_SRC_DEBUG_MON1 0x0134 +#define AFE_ADDA_UL_SRC_MON0 0x0148 +#define AFE_ADDA_UL_SRC_MON1 0x014c +#define AFE_SECURE_CON0 0x0150 +#define AFE_SRAM_BOUND 0x0154 +#define AFE_SECURE_CON1 0x0158 +#define AFE_SECURE_CONN0 0x015c +#define AFE_VUL_CON0 0x0170 +#define AFE_VUL_BASE_MSB 0x0174 +#define AFE_VUL_BASE 0x0178 +#define AFE_VUL_CUR_MSB 0x017c +#define AFE_VUL_CUR 0x0180 +#define AFE_VUL_END_MSB 0x0184 +#define AFE_VUL_END 0x0188 +#define AFE_SIDETONE_DEBUG 0x01d0 +#define AFE_SIDETONE_MON 0x01d4 +#define AFE_SINEGEN_CON2 0x01dc +#define AFE_SIDETONE_CON0 0x01e0 +#define AFE_SIDETONE_COEFF 0x01e4 +#define AFE_SIDETONE_CON1 0x01e8 +#define AFE_SIDETONE_GAIN 0x01ec +#define AFE_SINEGEN_CON0 0x01f0 +#define AFE_TOP_CON0 0x0200 +#define AFE_VUL2_CON0 0x020c +#define AFE_VUL2_BASE_MSB 0x0210 +#define AFE_VUL2_BASE 0x0214 +#define AFE_VUL2_CUR_MSB 0x0218 +#define AFE_VUL2_CUR 0x021c +#define AFE_VUL2_END_MSB 0x0220 +#define AFE_VUL2_END 0x0224 +#define AFE_VUL3_CON0 0x0228 +#define AFE_VUL3_BASE_MSB 0x022c +#define AFE_VUL3_BASE 0x0230 +#define AFE_VUL3_CUR_MSB 0x0234 +#define AFE_VUL3_CUR 0x0238 +#define AFE_VUL3_END_MSB 0x023c +#define AFE_VUL3_END 0x0240 +#define AFE_BUSY 0x0244 +#define AFE_BUS_CFG 0x0250 +#define AFE_ADDA_PREDIS_CON0 0x0260 +#define AFE_ADDA_PREDIS_CON1 0x0264 +#define AFE_I2S_MON 0x027c +#define AFE_ADDA_IIR_COEF_02_01 0x0290 +#define AFE_ADDA_IIR_COEF_04_03 0x0294 +#define AFE_ADDA_IIR_COEF_06_05 0x0298 +#define AFE_ADDA_IIR_COEF_08_07 0x029c +#define AFE_ADDA_IIR_COEF_10_09 0x02a0 +#define AFE_IRQ_MCU_CON1 0x02e4 +#define AFE_IRQ_MCU_CON2 0x02e8 +#define AFE_DAC_MON 0x02ec +#define AFE_IRQ_MCU_CON3 0x02f0 +#define AFE_IRQ_MCU_CON4 0x02f4 +#define AFE_IRQ_MCU_CNT0 0x0300 +#define AFE_IRQ_MCU_CNT6 0x0304 +#define AFE_IRQ_MCU_CNT8 0x0308 +#define AFE_IRQ_MCU_DSP2_EN 0x030c +#define AFE_IRQ0_MCU_CNT_MON 0x0310 +#define AFE_IRQ6_MCU_CNT_MON 0x0314 +#define AFE_VUL4_CON0 0x0358 +#define AFE_VUL4_BASE_MSB 0x035c +#define AFE_VUL4_BASE 0x0360 +#define AFE_VUL4_CUR_MSB 0x0364 +#define AFE_VUL4_CUR 0x0368 +#define AFE_VUL4_END_MSB 0x036c +#define AFE_VUL4_END 0x0370 +#define AFE_VUL12_CON0 0x0374 +#define AFE_VUL12_BASE_MSB 0x0378 +#define AFE_VUL12_BASE 0x037c +#define AFE_VUL12_CUR_MSB 0x0380 +#define AFE_VUL12_CUR 0x0384 +#define AFE_VUL12_END_MSB 0x0388 +#define AFE_VUL12_END 0x038c +#define AFE_IRQ3_MCU_CNT_MON 0x0398 +#define AFE_IRQ4_MCU_CNT_MON 0x039c +#define AFE_IRQ_MCU_CON0 0x03a0 +#define AFE_IRQ_MCU_STATUS 0x03a4 +#define AFE_IRQ_MCU_CLR 0x03a8 +#define AFE_IRQ_MCU_CNT1 0x03ac +#define AFE_IRQ_MCU_CNT2 0x03b0 +#define AFE_IRQ_MCU_EN 0x03b4 +#define AFE_IRQ_MCU_MON2 0x03b8 +#define AFE_IRQ_MCU_CNT5 0x03bc +#define AFE_IRQ1_MCU_CNT_MON 0x03c0 +#define AFE_IRQ2_MCU_CNT_MON 0x03c4 +#define AFE_IRQ5_MCU_CNT_MON 0x03cc +#define AFE_IRQ_MCU_DSP_EN 0x03d0 +#define AFE_IRQ_MCU_SCP_EN 0x03d4 +#define AFE_IRQ_MCU_CNT7 0x03dc +#define AFE_IRQ7_MCU_CNT_MON 0x03e0 +#define AFE_IRQ_MCU_CNT3 0x03e4 +#define AFE_IRQ_MCU_CNT4 0x03e8 +#define AFE_IRQ_MCU_CNT11 0x03ec +#define AFE_APLL1_TUNER_CFG 0x03f0 +#define AFE_APLL2_TUNER_CFG 0x03f4 +#define AFE_IRQ_MCU_MISS_CLR 0x03f8 +#define AFE_CONN33 0x0408 +#define AFE_IRQ_MCU_CNT12 0x040c +#define AFE_GAIN1_CON0 0x0410 +#define AFE_GAIN1_CON1 0x0414 +#define AFE_GAIN1_CON2 0x0418 +#define AFE_GAIN1_CON3 0x041c +#define AFE_CONN7 0x0420 +#define AFE_GAIN1_CUR 0x0424 +#define AFE_GAIN2_CON0 0x0428 +#define AFE_GAIN2_CON1 0x042c +#define AFE_GAIN2_CON2 0x0430 +#define AFE_GAIN2_CON3 0x0434 +#define AFE_CONN8 0x0438 +#define AFE_GAIN2_CUR 0x043c +#define AFE_CONN9 0x0440 +#define AFE_CONN10 0x0444 +#define AFE_CONN11 0x0448 +#define AFE_CONN12 0x044c +#define AFE_CONN13 0x0450 +#define AFE_CONN14 0x0454 +#define AFE_CONN15 0x0458 +#define AFE_CONN16 0x045c +#define AFE_CONN17 0x0460 +#define AFE_CONN18 0x0464 +#define AFE_CONN19 0x0468 +#define AFE_CONN20 0x046c +#define AFE_CONN21 0x0470 +#define AFE_CONN22 0x0474 +#define AFE_CONN23 0x0478 +#define AFE_CONN24 0x047c +#define AFE_CONN_RS 0x0494 +#define AFE_CONN_DI 0x0498 +#define AFE_CONN25 0x04b0 +#define AFE_CONN26 0x04b4 +#define AFE_CONN27 0x04b8 +#define AFE_CONN28 0x04bc +#define AFE_CONN29 0x04c0 +#define AFE_CONN30 0x04c4 +#define AFE_CONN31 0x04c8 +#define AFE_CONN32 0x04cc +#define AFE_SRAM_DELSEL_CON1 0x04f4 +#define AFE_CONN56 0x0500 +#define AFE_CONN57 0x0504 +#define AFE_CONN58 0x0508 +#define AFE_CONN59 0x050c +#define AFE_CONN56_1 0x0510 +#define AFE_CONN57_1 0x0514 +#define AFE_CONN58_1 0x0518 +#define AFE_CONN59_1 0x051c +#define PCM_INTF_CON1 0x0530 +#define PCM_INTF_CON2 0x0538 +#define PCM2_INTF_CON 0x053c +#define AFE_CM1_CON 0x0550 +#define AFE_CONN34 0x0580 +#define FPGA_CFG0 0x05b0 +#define FPGA_CFG1 0x05b4 +#define FPGA_CFG2 0x05c0 +#define FPGA_CFG3 0x05c4 +#define AUDIO_TOP_DBG_CON 0x05c8 +#define AUDIO_TOP_DBG_MON0 0x05cc +#define AUDIO_TOP_DBG_MON1 0x05d0 +#define AFE_IRQ8_MCU_CNT_MON 0x05e4 +#define AFE_IRQ11_MCU_CNT_MON 0x05e8 +#define AFE_IRQ12_MCU_CNT_MON 0x05ec +#define AFE_IRQ_MCU_CNT9 0x0600 +#define AFE_IRQ_MCU_CNT10 0x0604 +#define AFE_IRQ_MCU_CNT13 0x0608 +#define AFE_IRQ_MCU_CNT14 0x060c +#define AFE_IRQ_MCU_CNT15 0x0610 +#define AFE_IRQ_MCU_CNT16 0x0614 +#define AFE_IRQ_MCU_CNT17 0x0618 +#define AFE_IRQ_MCU_CNT18 0x061c +#define AFE_IRQ_MCU_CNT19 0x0620 +#define AFE_IRQ_MCU_CNT20 0x0624 +#define AFE_IRQ_MCU_CNT21 0x0628 +#define AFE_IRQ_MCU_CNT22 0x062c +#define AFE_IRQ_MCU_CNT23 0x0630 +#define AFE_IRQ_MCU_CNT24 0x0634 +#define AFE_IRQ_MCU_CNT25 0x0638 +#define AFE_IRQ_MCU_CNT26 0x063c +#define AFE_IRQ9_MCU_CNT_MON 0x0660 +#define AFE_IRQ10_MCU_CNT_MON 0x0664 +#define AFE_IRQ13_MCU_CNT_MON 0x0668 +#define AFE_IRQ14_MCU_CNT_MON 0x066c +#define AFE_IRQ15_MCU_CNT_MON 0x0670 +#define AFE_IRQ16_MCU_CNT_MON 0x0674 +#define AFE_IRQ17_MCU_CNT_MON 0x0678 +#define AFE_IRQ18_MCU_CNT_MON 0x067c +#define AFE_IRQ19_MCU_CNT_MON 0x0680 +#define AFE_IRQ20_MCU_CNT_MON 0x0684 +#define AFE_IRQ21_MCU_CNT_MON 0x0688 +#define AFE_IRQ22_MCU_CNT_MON 0x068c +#define AFE_IRQ23_MCU_CNT_MON 0x0690 +#define AFE_IRQ24_MCU_CNT_MON 0x0694 +#define AFE_IRQ25_MCU_CNT_MON 0x0698 +#define AFE_IRQ26_MCU_CNT_MON 0x069c +#define AFE_IRQ31_MCU_CNT_MON 0x06a0 +#define AFE_GENERAL_REG0 0x0800 +#define AFE_GENERAL_REG1 0x0804 +#define AFE_GENERAL_REG2 0x0808 +#define AFE_GENERAL_REG3 0x080c +#define AFE_GENERAL_REG4 0x0810 +#define AFE_GENERAL_REG5 0x0814 +#define AFE_GENERAL_REG6 0x0818 +#define AFE_GENERAL_REG7 0x081c +#define AFE_GENERAL_REG8 0x0820 +#define AFE_GENERAL_REG9 0x0824 +#define AFE_GENERAL_REG10 0x0828 +#define AFE_GENERAL_REG11 0x082c +#define AFE_GENERAL_REG12 0x0830 +#define AFE_GENERAL_REG13 0x0834 +#define AFE_GENERAL_REG14 0x0838 +#define AFE_GENERAL_REG15 0x083c +#define AFE_CBIP_CFG0 0x0840 +#define AFE_CBIP_MON0 0x0844 +#define AFE_CBIP_SLV_MUX_MON0 0x0848 +#define AFE_CBIP_SLV_DECODER_MON0 0x084c +#define AFE_ADDA6_MTKAIF_MON0 0x0854 +#define AFE_ADDA6_MTKAIF_MON1 0x0858 +#define AFE_AWB_CON0 0x085c +#define AFE_AWB_BASE_MSB 0x0860 +#define AFE_AWB_BASE 0x0864 +#define AFE_AWB_CUR_MSB 0x0868 +#define AFE_AWB_CUR 0x086c +#define AFE_AWB_END_MSB 0x0870 +#define AFE_AWB_END 0x0874 +#define AFE_AWB2_CON0 0x0878 +#define AFE_AWB2_BASE_MSB 0x087c +#define AFE_AWB2_BASE 0x0880 +#define AFE_AWB2_CUR_MSB 0x0884 +#define AFE_AWB2_CUR 0x0888 +#define AFE_AWB2_END_MSB 0x088c +#define AFE_AWB2_END 0x0890 +#define AFE_DAI_CON0 0x0894 +#define AFE_DAI_BASE_MSB 0x0898 +#define AFE_DAI_BASE 0x089c +#define AFE_DAI_CUR_MSB 0x08a0 +#define AFE_DAI_CUR 0x08a4 +#define AFE_DAI_END_MSB 0x08a8 +#define AFE_DAI_END 0x08ac +#define AFE_DAI2_CON0 0x08b0 +#define AFE_DAI2_BASE_MSB 0x08b4 +#define AFE_DAI2_BASE 0x08b8 +#define AFE_DAI2_CUR_MSB 0x08bc +#define AFE_DAI2_CUR 0x08c0 +#define AFE_DAI2_END_MSB 0x08c4 +#define AFE_DAI2_END 0x08c8 +#define AFE_MEMIF_CON0 0x08cc +#define AFE_CONN0_1 0x0900 +#define AFE_CONN1_1 0x0904 +#define AFE_CONN2_1 0x0908 +#define AFE_CONN3_1 0x090c +#define AFE_CONN4_1 0x0910 +#define AFE_CONN5_1 0x0914 +#define AFE_CONN6_1 0x0918 +#define AFE_CONN7_1 0x091c +#define AFE_CONN8_1 0x0920 +#define AFE_CONN9_1 0x0924 +#define AFE_CONN10_1 0x0928 +#define AFE_CONN11_1 0x092c +#define AFE_CONN12_1 0x0930 +#define AFE_CONN13_1 0x0934 +#define AFE_CONN14_1 0x0938 +#define AFE_CONN15_1 0x093c +#define AFE_CONN16_1 0x0940 +#define AFE_CONN17_1 0x0944 +#define AFE_CONN18_1 0x0948 +#define AFE_CONN19_1 0x094c +#define AFE_CONN20_1 0x0950 +#define AFE_CONN21_1 0x0954 +#define AFE_CONN22_1 0x0958 +#define AFE_CONN23_1 0x095c +#define AFE_CONN24_1 0x0960 +#define AFE_CONN25_1 0x0964 +#define AFE_CONN26_1 0x0968 +#define AFE_CONN27_1 0x096c +#define AFE_CONN28_1 0x0970 +#define AFE_CONN29_1 0x0974 +#define AFE_CONN30_1 0x0978 +#define AFE_CONN31_1 0x097c +#define AFE_CONN32_1 0x0980 +#define AFE_CONN33_1 0x0984 +#define AFE_CONN34_1 0x0988 +#define AFE_CONN_RS_1 0x098c +#define AFE_CONN_DI_1 0x0990 +#define AFE_CONN_24BIT_1 0x0994 +#define AFE_CONN_REG 0x0998 +#define AFE_CONN35 0x09a0 +#define AFE_CONN36 0x09a4 +#define AFE_CONN37 0x09a8 +#define AFE_CONN38 0x09ac +#define AFE_CONN35_1 0x09b0 +#define AFE_CONN36_1 0x09b4 +#define AFE_CONN37_1 0x09b8 +#define AFE_CONN38_1 0x09bc +#define AFE_CONN39 0x09c0 +#define AFE_CONN40 0x09c4 +#define AFE_CONN41 0x09c8 +#define AFE_CONN42 0x09cc +#define AFE_CONN39_1 0x09e0 +#define AFE_CONN40_1 0x09e4 +#define AFE_CONN41_1 0x09e8 +#define AFE_CONN42_1 0x09ec +#define AFE_I2S_CON4 0x09f8 +#define AFE_CONN60 0x0a64 +#define AFE_CONN61 0x0a68 +#define AFE_CONN62 0x0a6c +#define AFE_CONN63 0x0a70 +#define AFE_CONN64 0x0a74 +#define AFE_CONN65 0x0a78 +#define AFE_CONN66 0x0a7c +#define AFE_ADDA6_TOP_CON0 0x0a80 +#define AFE_ADDA6_UL_SRC_CON0 0x0a84 +#define AFE_ADDA6_UL_SRC_CON1 0x0a88 +#define AFE_ADDA6_SRC_DEBUG 0x0a8c +#define AFE_ADDA6_SRC_DEBUG_MON0 0x0a90 +#define AFE_ADDA6_ULCF_CFG_02_01 0x0aa0 +#define AFE_ADDA6_ULCF_CFG_04_03 0x0aa4 +#define AFE_ADDA6_ULCF_CFG_06_05 0x0aa8 +#define AFE_ADDA6_ULCF_CFG_08_07 0x0aac +#define AFE_ADDA6_ULCF_CFG_10_09 0x0ab0 +#define AFE_ADDA6_ULCF_CFG_12_11 0x0ab4 +#define AFE_ADDA6_ULCF_CFG_14_13 0x0ab8 +#define AFE_ADDA6_ULCF_CFG_16_15 0x0abc +#define AFE_ADDA6_ULCF_CFG_18_17 0x0ac0 +#define AFE_ADDA6_ULCF_CFG_20_19 0x0ac4 +#define AFE_ADDA6_ULCF_CFG_22_21 0x0ac8 +#define AFE_ADDA6_ULCF_CFG_24_23 0x0acc +#define AFE_ADDA6_ULCF_CFG_26_25 0x0ad0 +#define AFE_ADDA6_ULCF_CFG_28_27 0x0ad4 +#define AFE_ADDA6_ULCF_CFG_30_29 0x0ad8 +#define AFE_ADD6A_UL_SRC_MON0 0x0ae4 +#define AFE_ADDA6_UL_SRC_MON1 0x0ae8 +#define AFE_CONN43 0x0af8 +#define AFE_CONN43_1 0x0afc +#define AFE_MOD_DAI_CON0 0x0b00 +#define AFE_MOD_DAI_BASE_MSB 0x0b04 +#define AFE_MOD_DAI_BASE 0x0b08 +#define AFE_MOD_DAI_CUR_MSB 0x0b0c +#define AFE_MOD_DAI_CUR 0x0b10 +#define AFE_MOD_DAI_END_MSB 0x0b14 +#define AFE_MOD_DAI_END 0x0b18 +#define AFE_AWB_RCH_MON 0x0b70 +#define AFE_AWB_LCH_MON 0x0b74 +#define AFE_VUL_RCH_MON 0x0b78 +#define AFE_VUL_LCH_MON 0x0b7c +#define AFE_VUL12_RCH_MON 0x0b80 +#define AFE_VUL12_LCH_MON 0x0b84 +#define AFE_VUL2_RCH_MON 0x0b88 +#define AFE_VUL2_LCH_MON 0x0b8c +#define AFE_DAI_DATA_MON 0x0b90 +#define AFE_MOD_DAI_DATA_MON 0x0b94 +#define AFE_DAI2_DATA_MON 0x0b98 +#define AFE_AWB2_RCH_MON 0x0b9c +#define AFE_AWB2_LCH_MON 0x0ba0 +#define AFE_VUL3_RCH_MON 0x0ba4 +#define AFE_VUL3_LCH_MON 0x0ba8 +#define AFE_VUL4_RCH_MON 0x0bac +#define AFE_VUL4_LCH_MON 0x0bb0 +#define AFE_VUL5_RCH_MON 0x0bb4 +#define AFE_VUL5_LCH_MON 0x0bb8 +#define AFE_VUL6_RCH_MON 0x0bbc +#define AFE_VUL6_LCH_MON 0x0bc0 +#define AFE_DL1_RCH_MON 0x0bc4 +#define AFE_DL1_LCH_MON 0x0bc8 +#define AFE_DL2_RCH_MON 0x0bcc +#define AFE_DL2_LCH_MON 0x0bd0 +#define AFE_DL12_RCH1_MON 0x0bd4 +#define AFE_DL12_LCH1_MON 0x0bd8 +#define AFE_DL12_RCH2_MON 0x0bdc +#define AFE_DL12_LCH2_MON 0x0be0 +#define AFE_DL3_RCH_MON 0x0be4 +#define AFE_DL3_LCH_MON 0x0be8 +#define AFE_DL4_RCH_MON 0x0bec +#define AFE_DL4_LCH_MON 0x0bf0 +#define AFE_DL5_RCH_MON 0x0bf4 +#define AFE_DL5_LCH_MON 0x0bf8 +#define AFE_DL6_RCH_MON 0x0bfc +#define AFE_DL6_LCH_MON 0x0c00 +#define AFE_DL7_RCH_MON 0x0c04 +#define AFE_DL7_LCH_MON 0x0c08 +#define AFE_DL8_RCH_MON 0x0c0c +#define AFE_DL8_LCH_MON 0x0c10 +#define AFE_VUL5_CON0 0x0c14 +#define AFE_VUL5_BASE_MSB 0x0c18 +#define AFE_VUL5_BASE 0x0c1c +#define AFE_VUL5_CUR_MSB 0x0c20 +#define AFE_VUL5_CUR 0x0c24 +#define AFE_VUL5_END_MSB 0x0c28 +#define AFE_VUL5_END 0x0c2c +#define AFE_VUL6_CON0 0x0c30 +#define AFE_VUL6_BASE_MSB 0x0c34 +#define AFE_VUL6_BASE 0x0c38 +#define AFE_VUL6_CUR_MSB 0x0c3c +#define AFE_VUL6_CUR 0x0c40 +#define AFE_VUL6_END_MSB 0x0c44 +#define AFE_VUL6_END 0x0c48 +#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x0c50 +#define AFE_ADDA_DL_SDM_TEST 0x0c54 +#define AFE_ADDA_DL_DC_COMP_CFG0 0x0c58 +#define AFE_ADDA_DL_DC_COMP_CFG1 0x0c5c +#define AFE_ADDA_DL_SDM_FIFO_MON 0x0c60 +#define AFE_ADDA_DL_SRC_LCH_MON 0x0c64 +#define AFE_ADDA_DL_SRC_RCH_MON 0x0c68 +#define AFE_ADDA_DL_SDM_OUT_MON 0x0c6c +#define AFE_ADDA_DL_SDM_DITHER_CON 0x0c70 +#define AFE_ADDA_DL_SDM_AUTO_RESET_CON 0x0c74 +#define AFE_CONNSYS_I2S_CON 0x0c78 +#define AFE_CONNSYS_I2S_MON 0x0c7c +#define AFE_ASRC_2CH_CON0 0x0c80 +#define AFE_ASRC_2CH_CON1 0x0c84 +#define AFE_ASRC_2CH_CON2 0x0c88 +#define AFE_ASRC_2CH_CON3 0x0c8c +#define AFE_ASRC_2CH_CON4 0x0c90 +#define AFE_ASRC_2CH_CON5 0x0c94 +#define AFE_ASRC_2CH_CON6 0x0c98 +#define AFE_ASRC_2CH_CON7 0x0c9c +#define AFE_ASRC_2CH_CON8 0x0ca0 +#define AFE_ASRC_2CH_CON9 0x0ca4 +#define AFE_ASRC_2CH_CON10 0x0ca8 +#define AFE_ASRC_2CH_CON12 0x0cb0 +#define AFE_ASRC_2CH_CON13 0x0cb4 +#define AFE_ADDA6_IIR_COEF_02_01 0x0ce0 +#define AFE_ADDA6_IIR_COEF_04_03 0x0ce4 +#define AFE_ADDA6_IIR_COEF_06_05 0x0ce8 +#define AFE_ADDA6_IIR_COEF_08_07 0x0cec +#define AFE_ADDA6_IIR_COEF_10_09 0x0cf0 +#define AFE_CONN67 0x0cf4 +#define AFE_CONN68 0x0cf8 +#define AFE_CONN69 0x0cfc +#define AFE_SE_PROT_SIDEBAND 0x0d38 +#define AFE_SE_DOMAIN_SIDEBAND0 0x0d3c +#define AFE_ADDA_PREDIS_CON2 0x0d40 +#define AFE_ADDA_PREDIS_CON3 0x0d44 +#define AFE_SE_DOMAIN_SIDEBAND1 0x0d54 +#define AFE_SE_DOMAIN_SIDEBAND2 0x0d58 +#define AFE_SE_DOMAIN_SIDEBAND3 0x0d5c +#define AFE_CONN44 0x0d70 +#define AFE_CONN45 0x0d74 +#define AFE_CONN46 0x0d78 +#define AFE_CONN47 0x0d7c +#define AFE_CONN44_1 0x0d80 +#define AFE_CONN45_1 0x0d84 +#define AFE_CONN46_1 0x0d88 +#define AFE_CONN47_1 0x0d8c +#define AFE_HD_ENGEN_ENABLE 0x0dd0 +#define AFE_ADDA_DL_NLE_FIFO_MON 0x0dfc +#define AFE_ADDA_MTKAIF_CFG0 0x0e00 +#define AFE_CONN67_1 0x0e04 +#define AFE_CONN68_1 0x0e08 +#define AFE_CONN69_1 0x0e0c +#define AFE_ADDA_MTKAIF_SYNCWORD_CFG 0x0e14 +#define AFE_ADDA_MTKAIF_RX_CFG0 0x0e20 +#define AFE_ADDA_MTKAIF_RX_CFG1 0x0e24 +#define AFE_ADDA_MTKAIF_RX_CFG2 0x0e28 +#define AFE_ADDA_MTKAIF_MON0 0x0e34 +#define AFE_ADDA_MTKAIF_MON1 0x0e38 +#define AFE_AUD_PAD_TOP 0x0e40 +#define AFE_DL_NLE_R_CFG0 0x0e44 +#define AFE_DL_NLE_R_CFG1 0x0e48 +#define AFE_DL_NLE_L_CFG0 0x0e4c +#define AFE_DL_NLE_L_CFG1 0x0e50 +#define AFE_DL_NLE_R_MON0 0x0e54 +#define AFE_DL_NLE_R_MON1 0x0e58 +#define AFE_DL_NLE_R_MON2 0x0e5c +#define AFE_DL_NLE_L_MON0 0x0e60 +#define AFE_DL_NLE_L_MON1 0x0e64 +#define AFE_DL_NLE_L_MON2 0x0e68 +#define AFE_DL_NLE_GAIN_CFG0 0x0e6c +#define AFE_ADDA6_MTKAIF_CFG0 0x0e70 +#define AFE_ADDA6_MTKAIF_RX_CFG0 0x0e74 +#define AFE_ADDA6_MTKAIF_RX_CFG1 0x0e78 +#define AFE_ADDA6_MTKAIF_RX_CFG2 0x0e7c +#define AFE_GENERAL1_ASRC_2CH_CON0 0x0e80 +#define AFE_GENERAL1_ASRC_2CH_CON1 0x0e84 +#define AFE_GENERAL1_ASRC_2CH_CON2 0x0e88 +#define AFE_GENERAL1_ASRC_2CH_CON3 0x0e8c +#define AFE_GENERAL1_ASRC_2CH_CON4 0x0e90 +#define AFE_GENERAL1_ASRC_2CH_CON5 0x0e94 +#define AFE_GENERAL1_ASRC_2CH_CON6 0x0e98 +#define AFE_GENERAL1_ASRC_2CH_CON7 0x0e9c +#define AFE_GENERAL1_ASRC_2CH_CON8 0x0ea0 +#define AFE_GENERAL1_ASRC_2CH_CON9 0x0ea4 +#define AFE_GENERAL1_ASRC_2CH_CON10 0x0ea8 +#define AFE_GENERAL1_ASRC_2CH_CON12 0x0eb0 +#define AFE_GENERAL1_ASRC_2CH_CON13 0x0eb4 +#define GENERAL_ASRC_MODE 0x0eb8 +#define GENERAL_ASRC_EN_ON 0x0ebc +#define AFE_CONN48 0x0ec0 +#define AFE_CONN49 0x0ec4 +#define AFE_CONN50 0x0ec8 +#define AFE_CONN51 0x0ecc +#define AFE_CONN52 0x0ed0 +#define AFE_CONN53 0x0ed4 +#define AFE_CONN54 0x0ed8 +#define AFE_CONN55 0x0edc +#define AFE_CONN48_1 0x0ee0 +#define AFE_CONN49_1 0x0ee4 +#define AFE_CONN50_1 0x0ee8 +#define AFE_CONN51_1 0x0eec +#define AFE_CONN52_1 0x0ef0 +#define AFE_CONN53_1 0x0ef4 +#define AFE_CONN54_1 0x0ef8 +#define AFE_CONN55_1 0x0efc +#define AFE_GENERAL2_ASRC_2CH_CON0 0x0f00 +#define AFE_GENERAL2_ASRC_2CH_CON1 0x0f04 +#define AFE_GENERAL2_ASRC_2CH_CON2 0x0f08 +#define AFE_GENERAL2_ASRC_2CH_CON3 0x0f0c +#define AFE_GENERAL2_ASRC_2CH_CON4 0x0f10 +#define AFE_GENERAL2_ASRC_2CH_CON5 0x0f14 +#define AFE_GENERAL2_ASRC_2CH_CON6 0x0f18 +#define AFE_GENERAL2_ASRC_2CH_CON7 0x0f1c +#define AFE_GENERAL2_ASRC_2CH_CON8 0x0f20 +#define AFE_GENERAL2_ASRC_2CH_CON9 0x0f24 +#define AFE_GENERAL2_ASRC_2CH_CON10 0x0f28 +#define AFE_GENERAL2_ASRC_2CH_CON12 0x0f30 +#define AFE_GENERAL2_ASRC_2CH_CON13 0x0f34 +#define AFE_DL5_CON0 0x0f4c +#define AFE_DL5_BASE_MSB 0x0f50 +#define AFE_DL5_BASE 0x0f54 +#define AFE_DL5_CUR_MSB 0x0f58 +#define AFE_DL5_CUR 0x0f5c +#define AFE_DL5_END_MSB 0x0f60 +#define AFE_DL5_END 0x0f64 +#define AFE_DL6_CON0 0x0f68 +#define AFE_DL6_BASE_MSB 0x0f6c +#define AFE_DL6_BASE 0x0f70 +#define AFE_DL6_CUR_MSB 0x0f74 +#define AFE_DL6_CUR 0x0f78 +#define AFE_DL6_END_MSB 0x0f7c +#define AFE_DL6_END 0x0f80 +#define AFE_DL7_CON0 0x0f84 +#define AFE_DL7_BASE_MSB 0x0f88 +#define AFE_DL7_BASE 0x0f8c +#define AFE_DL7_CUR_MSB 0x0f90 +#define AFE_DL7_CUR 0x0f94 +#define AFE_DL7_END_MSB 0x0f98 +#define AFE_DL7_END 0x0f9c +#define AFE_DL8_CON0 0x0fa0 +#define AFE_DL8_BASE_MSB 0x0fa4 +#define AFE_DL8_BASE 0x0fa8 +#define AFE_DL8_CUR_MSB 0x0fac +#define AFE_DL8_CUR 0x0fb0 +#define AFE_DL8_END_MSB 0x0fb4 +#define AFE_DL8_END 0x0fb8 +#define AFE_SE_SECURE_CON 0x1004 +#define AFE_PROT_SIDEBAND_MON 0x1008 +#define AFE_DOMAIN_SIDEBAND0_MON 0x100c +#define AFE_DOMAIN_SIDEBAND1_MON 0x1010 +#define AFE_DOMAIN_SIDEBAND2_MON 0x1014 +#define AFE_DOMAIN_SIDEBAND3_MON 0x1018 +#define AFE_SECURE_MASK_CONN0 0x1020 +#define AFE_SECURE_MASK_CONN1 0x1024 +#define AFE_SECURE_MASK_CONN2 0x1028 +#define AFE_SECURE_MASK_CONN3 0x102c +#define AFE_SECURE_MASK_CONN4 0x1030 +#define AFE_SECURE_MASK_CONN5 0x1034 +#define AFE_SECURE_MASK_CONN6 0x1038 +#define AFE_SECURE_MASK_CONN7 0x103c +#define AFE_SECURE_MASK_CONN8 0x1040 +#define AFE_SECURE_MASK_CONN9 0x1044 +#define AFE_SECURE_MASK_CONN10 0x1048 +#define AFE_SECURE_MASK_CONN11 0x104c +#define AFE_SECURE_MASK_CONN12 0x1050 +#define AFE_SECURE_MASK_CONN13 0x1054 +#define AFE_SECURE_MASK_CONN14 0x1058 +#define AFE_SECURE_MASK_CONN15 0x105c +#define AFE_SECURE_MASK_CONN16 0x1060 +#define AFE_SECURE_MASK_CONN17 0x1064 +#define AFE_SECURE_MASK_CONN18 0x1068 +#define AFE_SECURE_MASK_CONN19 0x106c +#define AFE_SECURE_MASK_CONN20 0x1070 +#define AFE_SECURE_MASK_CONN21 0x1074 +#define AFE_SECURE_MASK_CONN22 0x1078 +#define AFE_SECURE_MASK_CONN23 0x107c +#define AFE_SECURE_MASK_CONN24 0x1080 +#define AFE_SECURE_MASK_CONN25 0x1084 +#define AFE_SECURE_MASK_CONN26 0x1088 +#define AFE_SECURE_MASK_CONN27 0x108c +#define AFE_SECURE_MASK_CONN28 0x1090 +#define AFE_SECURE_MASK_CONN29 0x1094 +#define AFE_SECURE_MASK_CONN30 0x1098 +#define AFE_SECURE_MASK_CONN31 0x109c +#define AFE_SECURE_MASK_CONN32 0x10a0 +#define AFE_SECURE_MASK_CONN33 0x10a4 +#define AFE_SECURE_MASK_CONN34 0x10a8 +#define AFE_SECURE_MASK_CONN35 0x10ac +#define AFE_SECURE_MASK_CONN36 0x10b0 +#define AFE_SECURE_MASK_CONN37 0x10b4 +#define AFE_SECURE_MASK_CONN38 0x10b8 +#define AFE_SECURE_MASK_CONN39 0x10bc +#define AFE_SECURE_MASK_CONN40 0x10c0 +#define AFE_SECURE_MASK_CONN41 0x10c4 +#define AFE_SECURE_MASK_CONN42 0x10c8 +#define AFE_SECURE_MASK_CONN43 0x10cc +#define AFE_SECURE_MASK_CONN44 0x10d0 +#define AFE_SECURE_MASK_CONN45 0x10d4 +#define AFE_SECURE_MASK_CONN46 0x10d8 +#define AFE_SECURE_MASK_CONN47 0x10dc +#define AFE_SECURE_MASK_CONN48 0x10e0 +#define AFE_SECURE_MASK_CONN49 0x10e4 +#define AFE_SECURE_MASK_CONN50 0x10e8 +#define AFE_SECURE_MASK_CONN51 0x10ec +#define AFE_SECURE_MASK_CONN52 0x10f0 +#define AFE_SECURE_MASK_CONN53 0x10f4 +#define AFE_SECURE_MASK_CONN54 0x10f8 +#define AFE_SECURE_MASK_CONN55 0x10fc +#define AFE_SECURE_MASK_CONN56 0x1100 +#define AFE_SECURE_MASK_CONN57 0x1104 +#define AFE_SECURE_MASK_CONN0_1 0x1108 +#define AFE_SECURE_MASK_CONN1_1 0x110c +#define AFE_SECURE_MASK_CONN2_1 0x1110 +#define AFE_SECURE_MASK_CONN3_1 0x1114 +#define AFE_SECURE_MASK_CONN4_1 0x1118 +#define AFE_SECURE_MASK_CONN5_1 0x111c +#define AFE_SECURE_MASK_CONN6_1 0x1120 +#define AFE_SECURE_MASK_CONN7_1 0x1124 +#define AFE_SECURE_MASK_CONN8_1 0x1128 +#define AFE_SECURE_MASK_CONN9_1 0x112c +#define AFE_SECURE_MASK_CONN10_1 0x1130 +#define AFE_SECURE_MASK_CONN11_1 0x1134 +#define AFE_SECURE_MASK_CONN12_1 0x1138 +#define AFE_SECURE_MASK_CONN13_1 0x113c +#define AFE_SECURE_MASK_CONN14_1 0x1140 +#define AFE_SECURE_MASK_CONN15_1 0x1144 +#define AFE_SECURE_MASK_CONN16_1 0x1148 +#define AFE_SECURE_MASK_CONN17_1 0x114c +#define AFE_SECURE_MASK_CONN18_1 0x1150 +#define AFE_SECURE_MASK_CONN19_1 0x1154 +#define AFE_SECURE_MASK_CONN20_1 0x1158 +#define AFE_SECURE_MASK_CONN21_1 0x115c +#define AFE_SECURE_MASK_CONN22_1 0x1160 +#define AFE_SECURE_MASK_CONN23_1 0x1164 +#define AFE_SECURE_MASK_CONN24_1 0x1168 +#define AFE_SECURE_MASK_CONN25_1 0x116c +#define AFE_SECURE_MASK_CONN26_1 0x1170 +#define AFE_SECURE_MASK_CONN27_1 0x1174 +#define AFE_SECURE_MASK_CONN28_1 0x1178 +#define AFE_SECURE_MASK_CONN29_1 0x117c +#define AFE_SECURE_MASK_CONN30_1 0x1180 +#define AFE_SECURE_MASK_CONN31_1 0x1184 +#define AFE_SECURE_MASK_CONN32_1 0x1188 +#define AFE_SECURE_MASK_CONN33_1 0x118c +#define AFE_SECURE_MASK_CONN34_1 0x1190 +#define AFE_SECURE_MASK_CONN35_1 0x1194 +#define AFE_SECURE_MASK_CONN36_1 0x1198 +#define AFE_SECURE_MASK_CONN37_1 0x119c +#define AFE_SECURE_MASK_CONN38_1 0x11a0 +#define AFE_SECURE_MASK_CONN39_1 0x11a4 +#define AFE_SECURE_MASK_CONN40_1 0x11a8 +#define AFE_SECURE_MASK_CONN41_1 0x11ac +#define AFE_SECURE_MASK_CONN42_1 0x11b0 +#define AFE_SECURE_MASK_CONN43_1 0x11b4 +#define AFE_SECURE_MASK_CONN44_1 0x11b8 +#define AFE_SECURE_MASK_CONN45_1 0x11bc +#define AFE_SECURE_MASK_CONN46_1 0x11c0 +#define AFE_SECURE_MASK_CONN47_1 0x11c4 +#define AFE_SECURE_MASK_CONN48_1 0x11c8 +#define AFE_SECURE_MASK_CONN49_1 0x11cc +#define AFE_SECURE_MASK_CONN50_1 0x11d0 +#define AFE_SECURE_MASK_CONN51_1 0x11d4 +#define AFE_SECURE_MASK_CONN52_1 0x11d8 +#define AFE_SECURE_MASK_CONN53_1 0x11dc +#define AFE_SECURE_MASK_CONN54_1 0x11e0 +#define AFE_SECURE_MASK_CONN55_1 0x11e4 +#define AFE_SECURE_MASK_CONN56_1 0x11e8 +#define AFE_CONN60_1 0x11f0 +#define AFE_CONN61_1 0x11f4 +#define AFE_CONN62_1 0x11f8 +#define AFE_CONN63_1 0x11fc +#define AFE_CONN64_1 0x1220 +#define AFE_CONN65_1 0x1224 +#define AFE_CONN66_1 0x1228 +#define FPGA_CFG4 0x1230 +#define FPGA_CFG5 0x1234 +#define FPGA_CFG6 0x1238 +#define FPGA_CFG7 0x123c +#define FPGA_CFG8 0x1240 +#define FPGA_CFG9 0x1244 +#define FPGA_CFG10 0x1248 +#define FPGA_CFG11 0x124c +#define FPGA_CFG12 0x1250 +#define FPGA_CFG13 0x1254 +#define ETDM_IN1_CON0 0x1430 +#define ETDM_IN1_CON1 0x1434 +#define ETDM_IN1_CON2 0x1438 +#define ETDM_IN1_CON3 0x143c +#define ETDM_IN1_CON4 0x1440 +#define ETDM_IN1_CON5 0x1444 +#define ETDM_IN1_CON6 0x1448 +#define ETDM_IN1_CON7 0x144c +#define ETDM_IN1_CON8 0x1450 +#define ETDM_OUT1_CON0 0x1454 +#define ETDM_OUT1_CON1 0x1458 +#define ETDM_OUT1_CON2 0x145c +#define ETDM_OUT1_CON3 0x1460 +#define ETDM_OUT1_CON4 0x1464 +#define ETDM_OUT1_CON5 0x1468 +#define ETDM_OUT1_CON6 0x146c +#define ETDM_OUT1_CON7 0x1470 +#define ETDM_OUT1_CON8 0x1474 +#define ETDM_IN1_MON 0x1478 +#define ETDM_OUT1_MON 0x147c +#define ETDM_0_3_COWORK_CON0 0x18b0 +#define ETDM_0_3_COWORK_CON1 0x18b4 +#define ETDM_0_3_COWORK_CON3 0x18bc + +#define AFE_MAX_REGISTER ETDM_0_3_COWORK_CON3 + +#define AFE_IRQ_STATUS_BITS 0x87FFFFFF +#define AFE_IRQ_CNT_SHIFT 0 +#define AFE_IRQ_CNT_MASK 0x3ffff +#endif diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c index efd5cc364a35..2ee3872c83c3 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c @@ -284,7 +284,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe, { struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id); unsigned long flags; - int ret = 0; + int ret; if (!cfg) return -EINVAL; @@ -308,7 +308,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe, spin_unlock_irqrestore(&cfg->ctrl_lock, flags); - return ret; + return 0; } static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe, @@ -316,7 +316,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe, { struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id); unsigned long flags; - int ret = 0; + int ret; if (!cfg) return -EINVAL; @@ -338,7 +338,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe, if (ret) return ret; - return ret; + return 0; } int mt8195_afe_get_mclk_source_clk_id(int sel) diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index c02c10da3600..c2e268054773 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2172,11 +2172,11 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: etdm_data->slave_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: etdm_data->slave_mode = false; break; default: diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c index 12644ded83d5..caceb0deb467 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c @@ -266,11 +266,11 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: pcmif_priv->slave_mode = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: pcmif_priv->slave_mode = 0; break; default: diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index 67729de41a73..a0dd914c8ed1 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -229,7 +229,7 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int skew; /* Only CPU Master / Codec Slave supported ATM */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) return -EINVAL; if (inv == SND_SOC_DAIFMT_NB_IF || diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index e076ced30025..c040c83637e0 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -119,19 +119,19 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: if (!iface->mclk) { dev_err(dai->dev, "cpu clock master: mclk missing\n"); return -ENODEV; } break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BP_FC: + case SND_SOC_DAIFMT_BC_FP: dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n"); fallthrough; default: @@ -326,8 +326,8 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - if ((iface->fmt & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBS_CFS) { + if ((iface->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_BP_FP) { ret = axg_tdm_iface_set_sclk(dai, params); if (ret) return ret; diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c index 2870cfad813a..80c5ed196961 100644 --- a/sound/soc/meson/meson-codec-glue.c +++ b/sound/soc/meson/meson-codec-glue.c @@ -13,7 +13,7 @@ static struct snd_soc_dapm_widget * meson_codec_glue_get_input(struct snd_soc_dapm_widget *w) { - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *in; snd_soc_dapm_widget_for_each_source_path(w, p) { diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 7afe1a1acc56..467b0f2ce0bb 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -358,8 +358,8 @@ static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) * Saif internally could be slave when working on EXTMASTER mode. * We just hide this to machine driver. */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: if (saif->id == saif->master_id) scr &= ~BM_SAIF_CTRL_SLAVE_MODE; else diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 9433cc927755..b791a2ba5ce5 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -91,13 +91,13 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BC_FC); if (ret < 0) return ret; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_BP_FP); if (ret < 0) return ret; @@ -129,14 +129,14 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream, /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BC_FC); if (ret < 0) return ret; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) return ret; diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 7e39210a0b38..382e9d8608a3 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -171,11 +171,11 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai, sspa->sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH; sspa->ctrl = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: sspa->sp |= SSPA_SP_MSL; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 7f13a35e9cc1..0f504a9f4983 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -372,10 +372,10 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, { struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -432,14 +432,14 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv) sscr1 |= SSCR1_RxTresh(8) | SSCR1_TxTresh(7); - switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -484,9 +484,9 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv) pxa_ssp_write_reg(ssp, SSCR1, sscr1); pxa_ssp_write_reg(ssp, SSPSP, sspsp); - switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BC_FP: scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR; pxa_ssp_write_reg(ssp, SSCR1, scfr); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 746e6ec9198b..ffcf44e4dc8c 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -129,11 +129,11 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: pxa_i2s.master = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: pxa_i2s.master = 0; break; default: diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index b0a4f7ca2751..e54b8961112f 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -172,7 +172,7 @@ static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai)); } diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 98c0efa1d0fe..01dac32c50fd 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -732,10 +732,10 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, intf_cfg->cfg.sd_line_idx = module->sd_line_idx; switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_INTERNAL; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* CPU is slave */ intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_EXTERNAL; break; diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 72c5719f1d25..01f383888b62 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -90,7 +90,7 @@ struct q6adm_session_map_node_v5 { static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx, int copp_idx) { - struct q6copp *c = NULL; + struct q6copp *c; struct q6copp *ret = NULL; unsigned long flags; @@ -180,7 +180,7 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data) u32 status; u16 copp_id; u16 reserved; - } __packed * open = data->payload; + } __packed *open = data->payload; copp = q6adm_find_copp(adm, port_idx, copp_idx); if (!copp) @@ -299,7 +299,7 @@ static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm, int channel_mode, int bit_width, int app_type) { - struct q6copp *c = NULL; + struct q6copp *c; struct q6copp *ret = NULL; unsigned long flags; diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 625724852a7f..919e326b9462 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -1328,11 +1328,11 @@ int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg) pcfg->i2s_cfg.bit_width = cfg->bit_width; pcfg->i2s_cfg.data_format = AFE_LINEAR_PCM_DATA; - switch (cfg->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* CPU is slave */ pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL; break; diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index efccb5c0b3e0..f5f7c64b23a2 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -155,7 +155,7 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) } snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_BC_FC | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S); diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 61fda790f375..d8d35563af00 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -316,8 +316,8 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) static int sdm845_snd_startup(struct snd_pcm_substream *substream) { - unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; - unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + unsigned int fmt = SND_SOC_DAIFMT_BP_FP; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); @@ -356,7 +356,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(cpu_dai, fmt); break; diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 6e1184c8b672..ce4a5713386a 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -96,8 +96,8 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int sm8250_snd_startup(struct snd_pcm_substream *substream) { - unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; - unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + unsigned int fmt = SND_SOC_DAIFMT_BP_FP; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index bcdeddeba80c..0c6bd9a019db 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -169,7 +169,7 @@ static struct snd_soc_card snd_soc_card_rk = { static int snd_rk_mc_probe(struct platform_device *pdev) { - int ret = 0; + int ret; struct snd_soc_card *card = &snd_soc_card_rk; struct device_node *np = pdev->dev.of_node; struct rk_drvdata *machine; @@ -253,7 +253,7 @@ static int snd_rk_mc_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, ret, "Soc register card failed\n"); - return ret; + return 0; } static const struct of_device_id rockchip_sound_of_match[] = { diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 99a128a666fb..be051e48b97b 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -261,13 +261,13 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, pm_runtime_get_sync(cpu_dai->dev); mask = I2S_CKR_MSS_MASK; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* Set source clock in Master mode */ val = I2S_CKR_MSS_MASTER; i2s->is_master_mode = true; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: val = I2S_CKR_MSS_SLAVE; i2s->is_master_mode = false; break; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 98700e75b82a..48b3ecfa58b4 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -411,12 +411,12 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai, } mask = I2S_CKR_MSS_MASK; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: val = I2S_CKR_MSS_MASTER; i2s_tdm->is_master_mode = true; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: val = I2S_CKR_MSS_SLAVE; i2s_tdm->is_master_mode = false; break; diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index bb0cf4244e00..edee02d7f100 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -628,8 +628,10 @@ static int aries_audio_probe(struct platform_device *pdev) return -EINVAL; codec = of_get_child_by_name(dev->of_node, "codec"); - if (!codec) - return -EINVAL; + if (!codec) { + ret = -EINVAL; + goto out; + } for_each_card_prelinks(card, i, dai_link) { dai_link->codecs->of_node = of_parse_phandle(codec, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 70c827162be4..fdd9561c6a9f 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -671,11 +671,11 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: tmp |= mod_slave; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: /* * Set default source clock in Master mode, only when the * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 4c4dfde0568f..c2eb3534bfcc 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -340,8 +340,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, goto exit; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* Nothing to do, Master by default */ break; default: diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index de66cc422e6e..1bec72246ed0 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -252,12 +252,12 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("hw_params r: IISMOD: %x \n", iismod); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: i2s->master = 0; iismod |= S3C2412_IISMOD_SLAVE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: i2s->master = 1; iismod &= ~S3C2412_IISMOD_SLAVE; break; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 0f46304eaa4f..4082ad7cbcc1 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -169,11 +169,11 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params r: IISMOD: %x \n", iismod); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_CFC: iismod |= S3C2410_IISMOD_SLAVE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: iismod &= ~S3C2410_IISMOD_SLAVE; break; default: diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 02372109c251..da342da03880 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -216,7 +216,7 @@ static int snow_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); - return ret; + return 0; } static int snow_remove(struct platform_device *pdev) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index e9a1eb6bdf66..f3edc2e3d9d7 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1646,10 +1646,10 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) int ret; /* set clock master audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: fsi->clk_master = 1; /* cpu is master */ break; default: diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index eb762ab94d3e..a4180dc5a59b 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -756,10 +756,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* set clock master for audio interface */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: rdai->clk_master = 0; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: rdai->clk_master = 1; /* cpu is master */ break; default: diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index e392de7a262e..beaf1a8d6da1 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -767,7 +767,7 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: break; default: dev_err(ssi->dev, "Codec should be clk and frame consumer\n"); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 15b01bcefca5..bf7a3c69920a 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -291,16 +291,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_BP_FC: ssicr |= CR_SCK_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: ssicr |= CR_SWS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: ssicr |= CR_SWS_MASTER | CR_SCK_MASTER; break; default: diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index 4158f5aacfd3..285ab4c9c716 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -197,6 +197,12 @@ int snd_soc_card_late_probe(struct snd_soc_card *card) return 0; } +void snd_soc_card_fixup_controls(struct snd_soc_card *card) +{ + if (card->fixup_controls) + card->fixup_controls(card); +} + int snd_soc_card_remove(struct snd_soc_card *card) { int ret = 0; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9574f86dd4de..57f7105c12b7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1214,7 +1214,6 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; - unsigned int inv_dai_fmt; unsigned int i; int ret; @@ -1227,18 +1226,11 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, return ret; } - /* - * Flip the polarity for the "CPU" end of a CODEC<->CODEC link - */ - inv_dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt); + /* Flip the polarity for the "CPU" end of link */ + dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt); for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - unsigned int fmt = dai_fmt; - - if (snd_soc_component_is_codec(cpu_dai->component)) - fmt = inv_dai_fmt; - - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); if (ret != 0 && ret != -ENOTSUPP) return ret; } @@ -2074,6 +2066,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) goto probe_end; snd_soc_dapm_new_widgets(card); + snd_soc_card_fixup_controls(card); ret = snd_card_register(card->snd_card); if (ret < 0) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 6078afe335f8..d530e8c2b77b 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -208,8 +208,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { int ret = -ENOTSUPP; - if (dai->driver->ops && - dai->driver->ops->set_fmt) + if (dai->driver->ops && dai->driver->ops->set_fmt) ret = dai->driver->ops->set_fmt(dai, fmt); return soc_dai_ret(dai, ret); diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index d867f449d82d..bd88de056358 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -14,7 +14,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> -#include <linux/delay.h> #include <linux/pm.h> #include <linux/bitops.h> #include <linux/ctype.h> @@ -177,20 +176,28 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int platform_max; - - if (!mc->platform_max) - mc->platform_max = mc->max; - platform_max = mc->platform_max; - - if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else + const char *vol_string = NULL; + int max; + + max = uinfo->value.integer.max = mc->max - mc->min; + if (mc->platform_max && mc->platform_max < max) + max = mc->platform_max; + + if (max == 1) { + /* Even two value controls ending in Volume should always be integer */ + vol_string = strstr(kcontrol->id.name, " Volume"); + if (vol_string && !strcmp(vol_string, " Volume")) + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + } else { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + } uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = platform_max - mc->min; + uinfo->value.integer.max = max; + return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_volsw); @@ -203,7 +210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); * Callback to provide information about a single mixer control, or a double * mixer control that spans 2 registers of the SX TLV type. SX TLV controls * have a range that represents both positive and negative values either side - * of zero but without a sign bit. + * of zero but without a sign bit. min is the minimum register value, max is + * the number of steps. * * Returns 0 for success. */ @@ -212,12 +220,21 @@ int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + int max; - snd_soc_info_volsw(kcontrol, uinfo); - /* Max represents the number of levels in an SX control not the - * maximum value, so add the minimum value back on - */ - uinfo->value.integer.max += mc->min; + if (mc->platform_max) + max = mc->platform_max; + else + max = mc->max; + + if (max == 1 && !strstr(kcontrol->id.name, " Volume")) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max; return 0; } diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 4542868cd730..e90f173d067c 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -252,6 +252,13 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. +# Supported IPC versions +config SND_SOC_SOF_IPC3 + bool + +config SND_SOC_SOF_INTEL_IPC4 + bool + source "sound/soc/sof/amd/Kconfig" source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 92b5e83601be..9a74ed116ed9 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,10 +1,18 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\ - ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o\ - ipc3-dtrace.o\ - ipc4.o ipc4-loader.o + control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o + +# IPC implementations +ifneq ($(CONFIG_SND_SOC_SOF_IPC3),) +snd-sof-objs += ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\ + ipc3-dtrace.o +endif +ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),) +snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o +endif + +# SOF client support ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),) snd-sof-objs += sof-client.o endif diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 085232e04582..190c85d57047 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -17,6 +17,7 @@ if SND_SOC_SOF_AMD_TOPLEVEL config SND_SOC_SOF_AMD_COMMON tristate select SND_SOC_SOF + select SND_SOC_SOF_IPC3 select SND_SOC_SOF_PCI_DEV select SND_AMD_ACP_CONFIG select SND_SOC_ACPI if ACPI diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 40fbf11facba..56cefd4a84fc 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -46,12 +46,14 @@ #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C #define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACP_SOFT_RESET 0x1000 +#define ACP_CONTROL 0x1004 #define ACP_I2S_PIN_CONFIG 0x1400 /* Registers from ACP_PGFSM block */ #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420 +#define ACP_CLKMUX_SEL 0x1424 /* Registers from ACP_INTR block */ #define ACP_EXTERNAL_INTR_ENB 0x1800 diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 0c272573df97..c40d2900dd36 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -413,10 +413,46 @@ static int acp_init(struct snd_sof_dev *sdev) dev_err(sdev->dev, "ACP power on failed\n"); return ret; } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01); /* Reset */ return acp_reset(sdev); } +int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + int ret; + + ret = acp_reset(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Reset failed\n"); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00); + + return 0; +} +EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); + +int amd_sof_acp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = acp_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Init failed\n"); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03); + + ret = acp_memory_init(sdev); + + return ret; +} +EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); + int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 291b44c54bcc..4c42b8fd6abf 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -216,6 +216,10 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct sof_ipc_dma_trace_params_ext *dtrace_params); int acp_sof_trace_release(struct snd_sof_dev *sdev); +/* PM Callbacks */ +int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state); +int amd_sof_acp_resume(struct snd_sof_dev *sdev); + struct sof_amd_acp_desc { unsigned int host_bridge_id; }; diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index d5d9bcc2c997..3a7fed25a226 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -49,6 +49,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = { static const struct sof_dev_desc renoir_desc = { .machines = snd_soc_acpi_amd_sof_machines, + .use_acpi_target_states = true, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -166,6 +167,9 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = { .id_table = rn_pci_ids, .probe = acp_pci_rn_probe, .remove = acp_pci_rn_remove, + .driver = { + .pm = &sof_pci_pm, + }, }; module_pci_driver(snd_sof_pci_amd_rn_driver); diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 70190365328c..9261c8bc2236 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -173,6 +173,10 @@ struct snd_sof_dsp_ops sof_renoir_ops = { /* Trace Logger */ .trace_init = acp_sof_trace_init, .trace_release = acp_sof_trace_release, + + /* PM */ + .suspend = amd_sof_acp_suspend, + .resume = amd_sof_acp_resume, }; EXPORT_SYMBOL(sof_renoir_ops); diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 53719c04658f..c99b5e6c026c 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ret = snd_sof_probe(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); - return ret; + goto probe_err; } sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); @@ -317,6 +317,8 @@ dbg_err: snd_sof_free_debug(sdev); dsp_err: snd_sof_remove(sdev); +probe_err: + sof_ops_free(sdev); /* all resources freed, update state to match */ sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); @@ -374,6 +376,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data) { + sof_ops_free(sdev); dev_err(dev, "error: missing mandatory ops\n"); return -EINVAL; } @@ -457,6 +460,8 @@ int snd_sof_device_remove(struct device *dev) snd_sof_remove(sdev); } + sof_ops_free(sdev); + /* release firmware */ snd_sof_fw_unload(sdev); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index cf1271eb29b2..c5d797e97c02 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -428,7 +428,7 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev) } } -void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg) { if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) || sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) { @@ -441,8 +441,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) /* dump vital information to the logs */ snd_sof_ipc_dump(sdev); - snd_sof_dsp_dbg_dump(sdev, "Firmware exception", - SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); sof_fw_trace_fw_crashed(sdev); } EXPORT_SYMBOL(snd_sof_handle_fw_exception); diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 9b8d5bb1e449..cc6e695f913a 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -15,6 +15,7 @@ config SND_SOC_SOF_IMX_COMMON tristate select SND_SOC_SOF_OF_DEV select SND_SOC_SOF + select SND_SOC_SOF_IPC3 select SND_SOC_SOF_XTENSA select SND_SOC_SOF_COMPRESS help diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 0def2aa5581d..3f54678e810b 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -40,6 +40,7 @@ if SND_SOC_SOF_ACPI config SND_SOC_SOF_BAYTRAIL tristate "SOF support for Baytrail, Braswell and Cherrytrail" default SND_SOC_SOF_ACPI + select SND_SOC_SOF_IPC3 select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_INTEL_ATOM_HIFI_EP select SND_SOC_SOF_ACPI_DEV @@ -60,6 +61,7 @@ config SND_SOC_SOF_BAYTRAIL config SND_SOC_SOF_BROADWELL tristate "SOF support for Broadwell" default SND_SOC_SOF_ACPI + select SND_SOC_SOF_IPC3 select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_INTEL_HIFI_EP_IPC select SND_SOC_SOF_ACPI_DEV @@ -85,6 +87,7 @@ config SND_SOC_SOF_MERRIFIELD tristate "SOF support for Tangier/Merrifield" default SND_SOC_SOF_PCI select SND_SOC_SOF_PCI_DEV + select SND_SOC_SOF_IPC3 select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help This adds support for Sound Open Firmware for Intel(R) platforms @@ -95,6 +98,8 @@ config SND_SOC_SOF_MERRIFIELD config SND_SOC_SOF_INTEL_APL tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_IPC3 + select SND_SOC_SOF_INTEL_IPC4 config SND_SOC_SOF_APOLLOLAKE tristate "SOF support for Apollolake" @@ -120,6 +125,8 @@ config SND_SOC_SOF_INTEL_CNL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_IPC3 + select SND_SOC_SOF_INTEL_IPC4 config SND_SOC_SOF_CANNONLAKE tristate "SOF support for Cannonlake" @@ -154,6 +161,8 @@ config SND_SOC_SOF_INTEL_ICL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_IPC3 + select SND_SOC_SOF_INTEL_IPC4 config SND_SOC_SOF_ICELAKE tristate "SOF support for Icelake" @@ -179,6 +188,8 @@ config SND_SOC_SOF_INTEL_TGL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_IPC3 + select SND_SOC_SOF_INTEL_IPC4 config SND_SOC_SOF_TIGERLAKE tristate "SOF support for Tigerlake" @@ -210,6 +221,22 @@ config SND_SOC_SOF_ALDERLAKE Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_MTL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_INTEL_IPC4 + +config SND_SOC_SOF_METEORLAKE + tristate "SOF support for Meteorlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_MTL + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Meteorlake processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index b9d51dc39ffa..a079159bb2f0 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -6,7 +6,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ - apl.o cnl.o tgl.o icl.o hda-common-ops.o + apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o snd-sof-intel-hda-objs := hda-codec.o @@ -24,9 +24,11 @@ snd-sof-pci-intel-apl-objs := pci-apl.o snd-sof-pci-intel-cnl-objs := pci-cnl.o snd-sof-pci-intel-icl-objs := pci-icl.o snd-sof-pci-intel-tgl-objs := pci-tgl.o +snd-sof-pci-intel-mtl-objs := pci-mtl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_APL) += snd-sof-pci-intel-apl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 0cea280a6d2d..084c245a9522 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -101,6 +101,7 @@ const struct sof_intel_dsp_desc apl_chip_info = { .ssp_base_offset = APL_SSP_BASE_OFFSET, .quirks = SOF_INTEL_PROCEN_FMT_QUIRK, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS, }; EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index cd6e5f8a5eb4..ccf46fcd6c9a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -401,6 +401,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_1_8, }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -430,6 +431,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 9823230d2ef4..ed74a1f264e8 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -10,10 +10,23 @@ #include <sound/pcm_params.h> #include <sound/hdaudio_ext.h> +#include <sound/intel-nhlt.h> +#include <sound/sof/ipc4/header.h> +#include <uapi/sound/sof/header.h> +#include "../ipc4-priv.h" +#include "../ipc4-topology.h" #include "../sof-priv.h" #include "../sof-audio.h" #include "hda.h" +/* + * The default method is to fetch NHLT from BIOS. With this parameter set + * it is possible to override that with NHLT in the SOF topology manifest. + */ +static bool hda_use_tplg_nhlt; +module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); +MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hda_pipe_params { @@ -257,7 +270,6 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd) struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); int ret; - dev_dbg(cpu_dai->dev, "%s: cmd=%d\n", __func__, cmd); if (!hext_stream) return 0; @@ -369,8 +381,7 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) return ret; } -static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream); @@ -382,7 +393,7 @@ static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream, if (hext_stream && hext_stream->link_prepared) return 0; - dev_dbg(sdev->dev, "%s: prepare stream dir %d\n", __func__, substream->stream); + dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream); ret = hda_link_dma_prepare(substream); if (ret < 0) @@ -408,13 +419,15 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, struct snd_soc_dapm_widget *w; int ret; + dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, + dai->name, substream->stream); + ret = hda_link_dma_trigger(substream, cmd); if (ret < 0) return ret; w = snd_soc_dai_get_widget(dai, substream->stream); - dev_dbg(dai->dev, "%s: cmd=%d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -438,6 +451,91 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, return 0; } +/* + * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes + * (over IPC channel) and DMA state change (direct host register changes). + */ +static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + struct snd_soc_pcm_runtime *rtd; + struct snd_sof_widget *swidget; + struct snd_soc_dapm_widget *w; + struct snd_soc_dai *codec_dai; + struct hdac_stream *hstream; + struct snd_soc_dai *cpu_dai; + int ret; + + dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, + dai->name, substream->stream); + + hstream = substream->runtime->private_data; + rtd = asoc_substream_to_rtd(substream); + cpu_dai = asoc_rtd_to_cpu(rtd, 0); + codec_dai = asoc_rtd_to_codec(rtd, 0); + + w = snd_soc_dai_get_widget(dai, substream->stream); + swidget = w->dobj.private; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_hdac_ext_link_stream_start(hext_stream); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + { + struct snd_sof_widget *pipe_widget = swidget->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + + pipeline->state = SOF_IPC4_PIPE_PAUSED; + + snd_hdac_ext_link_stream_clear(hext_stream); + + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_RESET); + if (ret < 0) + return ret; + + pipeline->state = SOF_IPC4_PIPE_RESET; + + ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false); + if (ret < 0) { + dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); + return ret; + } + break; + } + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + { + struct snd_sof_widget *pipe_widget = swidget->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + + pipeline->state = SOF_IPC4_PIPE_PAUSED; + + snd_hdac_ext_link_stream_clear(hext_stream); + break; + } + default: + dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd); + return -EINVAL; + } + + return 0; +} + static int hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -454,7 +552,7 @@ static const struct snd_soc_dai_ops ipc3_hda_dai_ops = { .hw_params = hda_dai_hw_params, .hw_free = hda_dai_hw_free, .trigger = ipc3_hda_dai_trigger, - .prepare = ipc3_hda_dai_prepare, + .prepare = hda_dai_prepare, }; static int hda_dai_suspend(struct hdac_bus *bus) @@ -497,6 +595,14 @@ static int hda_dai_suspend(struct hdac_bus *bus) return 0; } + +static const struct snd_soc_dai_ops ipc4_hda_dai_ops = { + .hw_params = hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = ipc4_hda_dai_trigger, + .prepare = hda_dai_prepare, +}; + #endif /* only one flag used so far to harden hw_params/hw_free/trigger/prepare */ @@ -608,6 +714,59 @@ static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = { .shutdown = ssp_dai_shutdown, }; +static int ipc4_be_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + struct snd_sof_widget *swidget; + struct snd_soc_dapm_widget *w; + struct snd_sof_dev *sdev; + int ret; + + w = snd_soc_dai_get_widget(dai, substream->stream); + swidget = w->dobj.private; + pipe_widget = swidget->pipe_widget; + pipeline = pipe_widget->private; + sdev = snd_soc_component_get_drvdata(swidget->scomp); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_PAUSED; + + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_RESET); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_RESET; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_PAUSED; + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops ipc4_dmic_dai_ops = { + .trigger = ipc4_be_dai_trigger, +}; + +static const struct snd_soc_dai_ops ipc4_ssp_dai_ops = { + .trigger = ipc4_be_dai_trigger, +}; + void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { int i; @@ -627,11 +786,48 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) #endif } break; + case SOF_INTEL_IPC4: + { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "DMIC")) { + ops->drv[i].ops = &ipc4_dmic_dai_ops; + continue; + } + if (strstr(ops->drv[i].name, "SSP")) { + ops->drv[i].ops = &ipc4_ssp_dai_ops; + continue; + } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + if (strstr(ops->drv[i].name, "iDisp") || + strstr(ops->drv[i].name, "Analog") || + strstr(ops->drv[i].name, "Digital")) + ops->drv[i].ops = &ipc4_hda_dai_ops; +#endif + } + + if (!hda_use_tplg_nhlt) + ipc4_data->nhlt = intel_nhlt_init(sdev->dev); + + break; + } default: break; } } +void hda_ops_free(struct snd_sof_dev *sdev) +{ + if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + + if (!hda_use_tplg_nhlt) + intel_nhlt_free(ipc4_data->nhlt); + } +} +EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); + /* * common dai driver for skl+ platforms. * some products who use this DAI array only physically have a subset of diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e24eea725acb..2afaee91b982 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -743,7 +743,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) if (hlink->ref_count) { ret = snd_hdac_ext_bus_link_power_up(hlink); if (ret < 0) { - dev_dbg(sdev->dev, + dev_err(sdev->dev, "error %d in %s: failed to power up links", ret, __func__); return ret; @@ -871,7 +871,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) /* no link can be powered in s0ix state */ ret = snd_hdac_ext_bus_link_power_down_all(bus); if (ret < 0) { - dev_dbg(sdev->dev, + dev_err(sdev->dev, "error %d in %s: failed to power down links", ret, __func__); return ret; @@ -940,13 +940,7 @@ void hda_dsp_d0i3_work(struct work_struct *work) int hda_dsp_core_get(struct snd_sof_dev *sdev, int core) { - struct sof_ipc_pm_core_config pm_core_config = { - .hdr = { - .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, - .size = sizeof(pm_core_config), - }, - .enable_mask = sdev->enabled_cores_mask | BIT(core), - }; + const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; int ret, ret1; /* power up core */ @@ -961,9 +955,12 @@ int hda_dsp_core_get(struct snd_sof_dev *sdev, int core) if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE) return 0; + /* No need to continue the set_core_state ops is not available */ + if (!pm_ops->set_core_state) + return 0; + /* Now notify DSP for secondary cores */ - ret = sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config), - &pm_core_config, sizeof(pm_core_config)); + ret = pm_ops->set_core_state(sdev, core, true); if (ret < 0) { dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n", core, ret); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 145d483bd129..819b3b08c655 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -99,7 +99,7 @@ out_put: * power on all host managed cores and only unstall/run the boot core to boot the * DSP then turn off all non boot cores (if any) is powered on. */ -static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) +int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -369,9 +369,15 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) static int hda_dsp_boot_imr(struct snd_sof_dev *sdev) { + const struct sof_intel_dsp_desc *chip_info; int ret; - ret = cl_dsp_init(sdev, 0, true); + chip_info = get_chip_info(sdev->pdata); + if (chip_info->cl_init) + ret = chip_info->cl_init(sdev, 0, true); + else + ret = -EINVAL; + if (!ret) hda_sdw_process_wakeen(sdev); @@ -431,7 +437,10 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) "Attempting iteration %d of Core En/ROM load...\n", i); hda->boot_iteration = i + 1; - ret = cl_dsp_init(sdev, hext_stream->hstream.stream_tag, false); + if (chip_info->cl_init) + ret = chip_info->cl_init(sdev, hext_stream->hstream.stream_tag, false); + else + ret = -EINVAL; /* don't retry anymore if successful */ if (!ret) @@ -530,7 +539,8 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) /* Check if IMR boot is usable */ if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) && - sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT) + (sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT || + sdev->pdata->ipc_type == SOF_INTEL_IPC4)) hdev->imrboot_supported = true; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index d95ae17e81cc..4531e1ee5ed0 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -116,13 +116,13 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, int remain, ioc; period_bytes = hstream->period_bytes; - dev_dbg(sdev->dev, "%s: period_bytes:0x%x\n", __func__, period_bytes); + dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); if (!period_bytes) period_bytes = hstream->bufsize; periods = hstream->bufsize / period_bytes; - dev_dbg(sdev->dev, "%s: periods:%d\n", __func__, periods); + dev_dbg(sdev->dev, "periods:%d\n", periods); remain = hstream->bufsize % period_bytes; if (remain) @@ -271,7 +271,7 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN); if (!found) { - dev_dbg(sdev->dev, "%s: stream_tag %d not opened!\n", + dev_err(sdev->dev, "%s: stream_tag %d not opened!\n", __func__, stream_tag); return -ENODEV; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 06476ffe96d7..dc713c20ba1d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -605,6 +605,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int direction); int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_ext_stream *hext_stream); +int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); #define HDA_CL_STREAM_FORMAT 0x40 /* pre and post fw run ops */ @@ -716,6 +717,8 @@ extern struct snd_sof_dsp_ops sof_tgl_ops; int sof_tgl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_icl_ops; int sof_icl_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_mtl_ops; +int sof_mtl_ops_init(struct snd_sof_dev *sdev); extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; @@ -725,6 +728,7 @@ extern const struct sof_intel_dsp_desc tglh_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; +extern const struct sof_intel_dsp_desc mtl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) @@ -767,6 +771,7 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_f extern int sof_hda_position_quirk; void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops); +void hda_ops_free(struct snd_sof_dev *sdev); /* IPC4 */ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context); diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index f19517dffd62..4e37b7fe0627 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -152,6 +152,7 @@ const struct sof_intel_dsp_desc icl_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c new file mode 100644 index 000000000000..3a043589c12b --- /dev/null +++ b/sound/soc/sof/intel/mtl.c @@ -0,0 +1,799 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> +// + +/* + * Hardware interface for audio DSP on Meteorlake. + */ + +#include <linux/firmware.h> +#include <sound/sof/ipc4/header.h> +#include "../ipc4-priv.h" +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" +#include "mtl.h" + +static const struct snd_sof_debugfs_map mtl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static void mtl_ipc_host_done(struct snd_sof_dev *sdev) +{ + /* + * clear busy interrupt to tell dsp controller this interrupt has been accepted, + * not trigger it again + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR, + MTL_DSP_REG_HFIPCXTDR_BUSY, MTL_DSP_REG_HFIPCXTDR_BUSY); + /* + * clear busy bit to ack dsp the msg has been processed and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA, + MTL_DSP_REG_HFIPCXTDA_BUSY, 0); +} + +static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg from DSP, and processed it, + * don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA, + MTL_DSP_REG_HFIPCXIDA_DONE, MTL_DSP_REG_HFIPCXIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL, + MTL_DSP_REG_HFIPCXCTL_DONE, MTL_DSP_REG_HFIPCXCTL_DONE); +} + +/* Check if an IPC IRQ occurred */ +static bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev) +{ + u32 irq_status; + u32 hfintipptr; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS); + + dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); + + if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_IPC)) + return true; + + return false; +} + +/* Check if an SDW IRQ occurred */ +static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + u32 irq_status; + u32 hfintipptr; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS); + + if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_SDW)) + return true; + + return false; +} + +static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc4_msg *msg_data = msg->msg_data; + + /* send the message via mailbox */ + if (msg_data->data_size) + sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, + msg_data->data_size); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY, + msg_data->extension); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR, + msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY); + + return 0; +} + +static void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* enable IPC DONE and BUSY interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, + MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE); +} + +static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* disable IPC DONE and BUSY interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0); +} + +static int mtl_enable_interrupts(struct snd_sof_dev *sdev) +{ + u32 hfintipptr; + u32 irqinten; + u32 host_ipc; + u32 hipcie; + int ret; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + + /* Enable Host IPC and SOUNDWIRE */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, + MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, + MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK); + + /* check if operation was successful */ + host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; + irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, + (irqinten & host_ipc) == host_ipc, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n"); + return ret; + } + + /* Set Host IPC interrupt enable */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, + MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK); + + /* check if operation was successful */ + host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, + (hipcie & host_ipc) == host_ipc, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n"); + return ret; + } + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, + MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK); + host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, + (hipcie & host_ipc) == host_ipc, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n"); + + return ret; +} + +static int mtl_disable_interrupts(struct snd_sof_dev *sdev) +{ + u32 hfintipptr; + u32 irqinten; + u32 host_ipc; + u32 hipcie; + int ret1; + int ret; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + + /* Disable Host IPC and SOUNDWIRE */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, + MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0); + + /* check if operation was successful */ + host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; + irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, + (irqinten & host_ipc) == 0, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + /* Continue to disable other interrupts when error happens */ + if (ret < 0) + dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n"); + + /* Set Host IPC interrupt disable */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, + MTL_DSP_REG_HfHIPCIE_IE_MASK, 0); + + /* check if operation was successful */ + host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE); + ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, + (hipcie & host_ipc) == 0, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret1 < 0) { + dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n"); + if (!ret) + ret = ret1; + } + + /* Set SoundWire IPC interrupt disable */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, + MTL_DSP_REG_HfSNDWIE_IE_MASK, 0); + host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE); + ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, + (hipcie & host_ipc) == 0, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret1 < 0) { + dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n"); + if (!ret) + ret = ret1; + } + + return ret; +} + +/* pre fw run operations */ +static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + u32 dsphfpwrsts; + u32 dsphfdsscs; + u32 cpa; + u32 pgs; + int ret; + + /* Set the DSP subsystem power on */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, + MTL_HFDSSCS_SPA_MASK, MTL_HFDSSCS_SPA_MASK); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_HFDSSCS_CPA_MASK; + dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, + (dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable DSP subsystem\n"); + return ret; + } + + /* Power up gated-DSP-0 domain in order to access the DSP shim register block. */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL, + MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG); + + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK; + dsphfpwrsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFPWRSTS); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts, + (dsphfpwrsts & pgs) == pgs, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "failed to power up gated DSP domain\n"); + + /* make sure SoundWire is not power-gated */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, MTL_HFPWRCTL, + MTL_HfPWRCTL_WPIOXPG(1), MTL_HfPWRCTL_WPIOXPG(1)); + return ret; +} + +static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + int ret; + + if (sdev->first_boot) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + ret = hda_sdw_startup(sdev); + if (ret < 0) { + dev_err(sdev->dev, "could not startup SoundWire links\n"); + return ret; + } + + /* Check if IMR boot is usable */ + if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) + hdev->imrboot_supported = true; + } + + hda_sdw_int_enable(sdev, true); + return 0; +} + +static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +{ + char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; + u32 romdbgsts; + u32 romdbgerr; + u32 fwsts; + u32 fwlec; + + fwsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_STS); + fwlec = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_ERROR); + romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY); + romdbgerr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY_ERROR); + + dev_err(sdev->dev, "ROM status: %#x, ROM error: %#x\n", fwsts, fwlec); + dev_err(sdev->dev, "ROM debug status: %#x, ROM debug error: %#x\n", romdbgsts, + romdbgerr); + romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY + 0x8 * 3); + dev_printk(level, sdev->dev, "ROM feature bit%s enabled\n", + romdbgsts & BIT(24) ? "" : " not"); +} + +static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev) +{ + int val; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE); + if (val != U32_MAX && val & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) + return true; + + return false; +} + +static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core) +{ + unsigned int cpa; + u32 dspcxctl; + int ret; + + /* Only the primary core can be powered up by the host */ + if (core != SOF_DSP_PRIMARY_CORE || mtl_dsp_primary_core_is_enabled(sdev)) + return 0; + + /* Program the owner of the IP & shim registers (10: Host CPU) */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, + MTL_DSP2CXCTL_PRIMARY_CORE_OSEL, + 0x2 << MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT); + + /* enable SPA bit */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, + MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, + MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK; + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl, + (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n", + __func__); + return ret; + } + + /* did core power up ? */ + dspcxctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE); + if ((dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) + != MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) { + dev_err(sdev->dev, "power up core failed core %d adspcs %#x\n", + core, dspcxctl); + ret = -EIO; + } + + return ret; +} + +static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core) +{ + u32 dspcxctl; + int ret; + + /* Only the primary core can be powered down by the host */ + if (core != SOF_DSP_PRIMARY_CORE || !mtl_dsp_primary_core_is_enabled(sdev)) + return 0; + + /* disable SPA bit */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, + MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl, + !(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); + if (ret < 0) + dev_err(sdev->dev, "failed to power down primary core\n"); + + return ret; +} + +static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + unsigned int status; + u32 ipc_hdr; + int ret; + + /* step 1: purge FW request */ + ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL; + if (!imr_boot) + ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr); + + /* step 2: power up primary core */ + ret = mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE); + if (ret < 0) { + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "dsp core 0/1 power up failed\n"); + goto err; + } + + dev_dbg(sdev->dev, "Primary core power up successful\n"); + + /* step 3: wait for IPC DONE bit from ROM */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status, + ((status & chip->ipc_ack_mask) == chip->ipc_ack_mask), + HDA_DSP_REG_POLL_INTERVAL_US, MTL_DSP_PURGE_TIMEOUT_US); + if (ret < 0) { + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "timeout waiting for purge IPC done\n"); + goto err; + } + + /* set DONE bit to clear the reply IPC message */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask, + chip->ipc_ack_mask); + + /* step 4: enable interrupts */ + ret = mtl_enable_interrupts(sdev); + if (ret < 0) { + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__); + goto err; + } + + mtl_enable_ipc_interrupts(sdev); + + /* + * ACE workaround: don't wait for ROM INIT. + * The platform cannot catch ROM_INIT_DONE because of a very short + * timing window. Follow the recommendations and skip this part. + */ + + return 0; + +err: + snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0); + mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); + return ret; +} + +static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) +{ + struct sof_ipc4_msg notification_data = {{ 0 }}; + struct snd_sof_dev *sdev = context; + bool ipc_irq = false; + u32 hipcida; + u32 hipctdr; + + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA); + + /* reply message from DSP */ + if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) { + /* DSP received the message */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL, + MTL_DSP_REG_HFIPCXCTL_DONE, 0); + + mtl_ipc_dsp_done(sdev); + + ipc_irq = true; + } + + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); + if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) { + /* Message from DSP (reply or notification) */ + u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY); + u32 primary = hipctdr & MTL_DSP_REG_HFIPCXTDR_MSG_MASK; + + /* + * ACE fw sends a new fw ipc message to host to + * notify the status of the last host ipc message + */ + if (primary & SOF_IPC4_MSG_DIR_MASK) { + /* Reply received */ + struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; + + data->primary = primary; + data->extension = extension; + + spin_lock_irq(&sdev->ipc_lock); + + snd_sof_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, data->primary); + + spin_unlock_irq(&sdev->ipc_lock); + } else { + /* Notification received */ + notification_data.primary = primary; + notification_data.extension = extension; + + sdev->ipc->msg.rx_data = ¬ification_data; + snd_sof_ipc_msgs_rx(sdev); + sdev->ipc->msg.rx_data = NULL; + } + + mtl_ipc_host_done(sdev); + + ipc_irq = true; + } + + if (!ipc_irq) { + /* This interrupt is not shared so no need to return IRQ_NONE. */ + dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); + } + + return IRQ_HANDLED; +} + +static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MTL_DSP_MBOX_UPLINK_OFFSET; +} + +static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MTL_SRAM_WINDOW_OFFSET(id); +} + +static int mtl_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); +#endif + u32 dsphfdsscs; + u32 cpa; + int ret; + int i; + + mtl_disable_ipc_interrupts(sdev); + ret = mtl_disable_interrupts(sdev); + if (ret) + return ret; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + hda_codec_jack_wake_enable(sdev, runtime_suspend); + /* power down all hda link */ + snd_hdac_ext_bus_link_power_down_all(bus); +#endif + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL, + MTL_HFPWRCTL_WPDSPHPXPG, 0); + + /* Set the DSP subsystem power down */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, + MTL_HFDSSCS_SPA_MASK, 0); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_HFDSSCS_CPA_MASK; + dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, + (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "failed to disable DSP subsystem\n"); + + /* reset ref counts for all cores */ + for (i = 0; i < chip->cores_num; i++) + sdev->dsp_core_ref_count[i] = 0; + + /* TODO: need to reset controller? */ + + /* display codec can be powered off after link reset */ + hda_codec_i915_display_power(sdev, false); + + return 0; +} + +static int mtl_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = target_state, + .substate = target_state == SOF_DSP_PM_D0 ? + SOF_HDA_DSP_PM_D0I3 : 0, + }; + int ret; + + ret = mtl_suspend(sdev, false); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int mtl_dsp_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D3, + }; + int ret; + + ret = mtl_suspend(sdev, true); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int mtl_resume(struct snd_sof_dev *sdev, bool runtime_resume) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_link *hlink = NULL; +#endif + + /* display codec must be powered before link reset */ + hda_codec_i915_display_power(sdev, true); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* check jack status */ + if (runtime_resume) { + hda_codec_jack_wake_enable(sdev, false); + if (sdev->system_suspend_target == SOF_SUSPEND_NONE) + hda_codec_jack_check(sdev); + } + + /* turn off the links that were off before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (!hlink->ref_count) + snd_hdac_ext_bus_link_power_down(hlink); + } + + /* check dma status and clean up CORB/RIRB buffers */ + if (!bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); +#endif + + return 0; +} + +static int mtl_dsp_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + .substate = SOF_HDA_DSP_PM_D0I0, + }; + int ret; + + ret = mtl_resume(sdev, false); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int mtl_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + }; + int ret; + + ret = mtl_resume(sdev, true); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static void mtl_ipc_dump(struct snd_sof_dev *sdev) +{ + u32 hipcctl; + u32 hipcida; + u32 hipctdr; + + /* read IPC status */ + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); + + /* dump the IPC regs */ + /* TODO: parse the raw msg */ + dev_err(sdev->dev, + "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", + hipcida, hipctdr, hipcctl); +} + +/* Meteorlake ops */ +struct snd_sof_dsp_ops sof_mtl_ops; +EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +int sof_mtl_ops_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data; + + /* common defaults */ + memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + + /* shutdown */ + sof_mtl_ops.shutdown = hda_dsp_shutdown; + + /* doorbell */ + sof_mtl_ops.irq_thread = mtl_ipc_irq_thread; + + /* ipc */ + sof_mtl_ops.send_msg = mtl_ipc_send_msg; + sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; + sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; + + /* debug */ + sof_mtl_ops.debug_map = mtl_dsp_debugfs; + sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs); + sof_mtl_ops.dbg_dump = mtl_dsp_dump; + sof_mtl_ops.ipc_dump = mtl_ipc_dump; + + /* pre/post fw run */ + sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run; + sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run; + + /* parse platform specific extended manifest */ + sof_mtl_ops.parse_platform_ext_manifest = NULL; + + /* dsp core get/put */ + /* TODO: add core_get and core_put */ + + /* PM */ + sof_mtl_ops.suspend = mtl_dsp_suspend; + sof_mtl_ops.resume = mtl_dsp_resume; + sof_mtl_ops.runtime_suspend = mtl_dsp_runtime_suspend; + sof_mtl_ops.runtime_resume = mtl_dsp_runtime_resume; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + + /* set DAI ops */ + hda_set_dai_drv_ops(sdev, &sof_mtl_ops); + + return 0; +}; +EXPORT_SYMBOL_NS(sof_mtl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc mtl_chip_info = { + .cores_num = 3, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = MTL_DSP_ROM_STS, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, + .sdw_shim_base = SDW_SHIM_BASE_ACE, + .sdw_alh_base = SDW_ALH_BASE_ACE, + .check_sdw_irq = mtl_dsp_check_sdw_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .hw_ip_version = SOF_INTEL_ACE_1_0, +}; +EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h new file mode 100644 index 000000000000..788bf0e3ea87 --- /dev/null +++ b/sound/soc/sof/intel/mtl.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2020-2022 Intel Corporation. All rights reserved. + */ + +/* DSP Registers */ +#define MTL_HFDSSCS 0x1000 +#define MTL_HFDSSCS_SPA_MASK BIT(16) +#define MTL_HFDSSCS_CPA_MASK BIT(24) +#define MTL_HFSNDWIE 0x114C +#define MTL_HFPWRCTL 0x1D18 +#define MTL_HfPWRCTL_WPIOXPG(x) BIT((x) + 8) +#define MTL_HFPWRCTL_WPDSPHPXPG BIT(0) +#define MTL_HFPWRSTS 0x1D1C +#define MTL_HFPWRSTS_DSPHPXPGS_MASK BIT(0) +#define MTL_HFINTIPPTR 0x1108 +#define MTL_IRQ_INTEN_L_HOST_IPC_MASK BIT(0) +#define MTL_IRQ_INTEN_L_SOUNDWIRE_MASK BIT(6) +#define MTL_HFINTIPPTR_PTR_MASK GENMASK(20, 0) + +#define MTL_DSP2CXCAP_PRIMARY_CORE 0x178D00 +#define MTL_DSP2CXCTL_PRIMARY_CORE 0x178D04 +#define MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK BIT(0) +#define MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK BIT(8) +#define MTL_DSP2CXCTL_PRIMARY_CORE_OSEL GENMASK(25, 24) +#define MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT 24 + +/* IPC Registers */ +#define MTL_DSP_REG_HFIPCXTDR 0x73200 +#define MTL_DSP_REG_HFIPCXTDR_BUSY BIT(31) +#define MTL_DSP_REG_HFIPCXTDR_MSG_MASK GENMASK(30, 0) +#define MTL_DSP_REG_HFIPCXTDA 0x73204 +#define MTL_DSP_REG_HFIPCXTDA_BUSY BIT(31) +#define MTL_DSP_REG_HFIPCXIDR 0x73210 +#define MTL_DSP_REG_HFIPCXIDR_BUSY BIT(31) +#define MTL_DSP_REG_HFIPCXIDR_MSG_MASK GENMASK(30, 0) +#define MTL_DSP_REG_HFIPCXIDA 0x73214 +#define MTL_DSP_REG_HFIPCXIDA_DONE BIT(31) +#define MTL_DSP_REG_HFIPCXIDA_MSG_MASK GENMASK(30, 0) +#define MTL_DSP_REG_HFIPCXCTL 0x73228 +#define MTL_DSP_REG_HFIPCXCTL_BUSY BIT(0) +#define MTL_DSP_REG_HFIPCXCTL_DONE BIT(1) +#define MTL_DSP_REG_HFIPCXTDDY 0x73300 +#define MTL_DSP_REG_HFIPCXIDDY 0x73380 +#define MTL_DSP_REG_HfHIPCIE 0x1140 +#define MTL_DSP_REG_HfHIPCIE_IE_MASK BIT(0) +#define MTL_DSP_REG_HfSNDWIE 0x114C +#define MTL_DSP_REG_HfSNDWIE_IE_MASK GENMASK(3, 0) + +#define MTL_DSP_IRQSTS 0x20 +#define MTL_DSP_IRQSTS_IPC BIT(0) +#define MTL_DSP_IRQSTS_SDW BIT(6) + +#define MTL_DSP_PURGE_TIMEOUT_US 20000000 /* 20s */ +#define MTL_DSP_REG_POLL_INTERVAL_US 10 /* 10 us */ + +/* Memory windows */ +#define MTL_SRAM_WINDOW_OFFSET(x) (0x180000 + 0x8000 * (x)) + +#define MTL_DSP_MBOX_UPLINK_OFFSET (MTL_SRAM_WINDOW_OFFSET(0) + 0x1000) +#define MTL_DSP_MBOX_UPLINK_SIZE 0x1000 +#define MTL_DSP_MBOX_DOWNLINK_OFFSET MTL_SRAM_WINDOW_OFFSET(1) +#define MTL_DSP_MBOX_DOWNLINK_SIZE 0x1000 + +/* FW registers */ +#define MTL_DSP_ROM_STS MTL_SRAM_WINDOW_OFFSET(0) /* ROM status */ +#define MTL_DSP_ROM_ERROR (MTL_SRAM_WINDOW_OFFSET(0) + 0x4) /* ROM error code */ + +#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* ROM debug status */ +#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* ROM debug error code */ +#define MTL_DSP_REG_HfIMRIS1 0x162088 +#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) + diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 2de3658eb817..998e219011f0 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -44,6 +44,7 @@ static const struct sof_dev_desc bxt_desc = { .nocodec_tplg_filename = "sof-apl-nocodec.tplg", .ops = &sof_apl_ops, .ops_init = sof_apl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc glk_desc = { diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index 87e587aef9c9..c797356f7028 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -73,6 +73,7 @@ static const struct sof_dev_desc cfl_desc = { .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .ops_init = sof_cnl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc cml_desc = { diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 1c7f16ce531e..48f24f8ace26 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -45,6 +45,7 @@ static const struct sof_dev_desc icl_desc = { .nocodec_tplg_filename = "sof-icl-nocodec.tplg", .ops = &sof_icl_ops, .ops_init = sof_icl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc jsl_desc = { diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c new file mode 100644 index 000000000000..899b00d53d64 --- /dev/null +++ b/sound/soc/sof/intel/pci-mtl.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2022 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" +#include "mtl.h" + +static const struct sof_dev_desc mtl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_mtl_machines, + .alt_machines = snd_soc_acpi_intel_mtl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &mtl_chip_info, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/sof-ace-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "dsp_basefw.bin", + }, + .nocodec_tplg_filename = "sof-mtl-nocodec.tplg", + .ops = &sof_mtl_ops, + .ops_init = sof_mtl_ops_init, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0x7E28), /* MTL */ + .driver_data = (unsigned long)&mtl_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_mtl_driver = { + .name = "sof-audio-pci-intel-mtl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_mtl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 58a9bd92a237..ccc44ba3ad94 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -73,6 +73,7 @@ static const struct sof_dev_desc tglh_desc = { .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_tgl_ops, .ops_init = sof_tgl_ops_init, + .ops_free = hda_ops_free, }; static const struct sof_dev_desc ehl_desc = { diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 1fd7b485d821..638159bee864 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -20,6 +20,7 @@ enum sof_intel_hw_ip_version { SOF_INTEL_CAVS_1_8, /* CannonLake, CometLake, CoffeeLake */ SOF_INTEL_CAVS_2_0, /* IceLake, JasperLake */ SOF_INTEL_CAVS_2_5, /* TigerLake, AlderLake */ + SOF_INTEL_ACE_1_0, /* MeteorLake */ }; /* @@ -185,6 +186,7 @@ struct sof_intel_dsp_desc { enum sof_intel_hw_ip_version hw_ip_version; bool (*check_sdw_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); + int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); }; extern struct snd_sof_dsp_ops sof_tng_ops; diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 1ddc492f1b13..6dfb4786c782 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -24,40 +24,30 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = { static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core) { - struct sof_ipc_pm_core_config pm_core_config = { - .hdr = { - .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, - .size = sizeof(pm_core_config), - }, - .enable_mask = sdev->enabled_cores_mask | BIT(core), - }; + const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; /* power up primary core if not already powered up and return */ if (core == SOF_DSP_PRIMARY_CORE) return hda_dsp_enable_core(sdev, BIT(core)); - /* notify DSP for secondary cores */ - return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config), - &pm_core_config, sizeof(pm_core_config)); + if (pm_ops->set_core_state) + return pm_ops->set_core_state(sdev, core, true); + + return 0; } static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core) { - struct sof_ipc_pm_core_config pm_core_config = { - .hdr = { - .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, - .size = sizeof(pm_core_config), - }, - .enable_mask = sdev->enabled_cores_mask & ~BIT(core), - }; + const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; /* power down primary core and return */ if (core == SOF_DSP_PRIMARY_CORE) return hda_dsp_core_reset_power_down(sdev, BIT(core)); - /* notify DSP for secondary cores */ - return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config), - &pm_core_config, sizeof(pm_core_config)); + if (pm_ops->set_core_state) + return pm_ops->set_core_state(sdev, core, false); + + return 0; } /* Tigerlake ops */ @@ -137,6 +127,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -159,6 +150,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -181,6 +173,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -203,6 +196,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .sdw_alh_base = SDW_ALH_BASE, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, + .cl_init = cl_dsp_init, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index c5aef5fc056b..6ed3f9b6a0c4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -155,12 +155,22 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) init_waitqueue_head(&msg->waitq); - /* - * Use IPC3 ops as it is the only available version now. With the addition of new IPC - * versions, this will need to be modified to use the selected version at runtime. - */ - ipc->ops = &ipc3_ops; - ops = ipc->ops; + switch (sdev->pdata->ipc_type) { +#if defined(CONFIG_SND_SOC_SOF_IPC3) + case SOF_IPC: + ops = &ipc3_ops; + break; +#endif +#if defined(CONFIG_SND_SOC_SOF_INTEL_IPC4) + case SOF_INTEL_IPC4: + ops = &ipc4_ops; + break; +#endif + default: + dev_err(sdev->dev, "Not supported IPC version: %d\n", + sdev->pdata->ipc_type); + return NULL; + } /* check for mandatory ops */ if (!ops->tx_msg || !ops->rx_msg || !ops->set_get_data || !ops->get_reply) { @@ -190,6 +200,8 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) return NULL; } + ipc->ops = ops; + return ipc; } EXPORT_SYMBOL(snd_sof_ipc_init); diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c index b4e1343f9138..b815b0244d9e 100644 --- a/sound/soc/sof/ipc3-dtrace.c +++ b/sound/soc/sof/ipc3-dtrace.c @@ -18,6 +18,7 @@ enum sof_dtrace_state { SOF_DTRACE_DISABLED, SOF_DTRACE_STOPPED, + SOF_DTRACE_INITIALIZING, SOF_DTRACE_ENABLED, }; @@ -32,6 +33,15 @@ struct sof_dtrace_priv { enum sof_dtrace_state dtrace_state; }; +static bool trace_pos_update_expected(struct sof_dtrace_priv *priv) +{ + if (priv->dtrace_state == SOF_DTRACE_ENABLED || + priv->dtrace_state == SOF_DTRACE_INITIALIZING) + return true; + + return false; +} + static int trace_filter_append_elem(struct snd_sof_dev *sdev, u32 key, u32 value, struct sof_ipc_trace_filter_elem *elem_list, int capacity, int *counter) @@ -157,9 +167,8 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems, msg->elem_cnt = num_elems; memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems)); - ret = pm_runtime_get_sync(sdev->dev); + ret = pm_runtime_resume_and_get(sdev->dev); if (ret < 0 && ret != -EACCES) { - pm_runtime_put_noidle(sdev->dev); dev_err(sdev->dev, "enabling device failed: %d\n", ret); goto error; } @@ -242,6 +251,21 @@ static int debugfs_create_trace_filter(struct snd_sof_dev *sdev) return 0; } +static bool sof_dtrace_set_host_offset(struct sof_dtrace_priv *priv, u32 new_offset) +{ + u32 host_offset = READ_ONCE(priv->host_offset); + + if (host_offset != new_offset) { + /* This is a bit paranoid and unlikely that it is needed */ + u32 ret = cmpxchg(&priv->host_offset, host_offset, new_offset); + + if (ret == host_offset) + return true; + } + + return false; +} + static size_t sof_dtrace_avail(struct snd_sof_dev *sdev, loff_t pos, size_t buffer_size) { @@ -274,7 +298,7 @@ static size_t sof_wait_dtrace_avail(struct snd_sof_dev *sdev, loff_t pos, if (ret) return ret; - if (priv->dtrace_state != SOF_DTRACE_ENABLED && priv->dtrace_draining) { + if (priv->dtrace_draining && !trace_pos_update_expected(priv)) { /* * tracing has ended and all traces have been * read by client, return EOF @@ -328,6 +352,10 @@ static ssize_t dfsentry_dtrace_read(struct file *file, char __user *buffer, return -EIO; } + /* no new trace data */ + if (!avail) + return 0; + /* make sure count is <= avail */ if (count > avail) count = avail; @@ -358,7 +386,7 @@ static int dfsentry_dtrace_release(struct inode *inode, struct file *file) /* avoid duplicate traces at next open */ if (priv->dtrace_state != SOF_DTRACE_ENABLED) - priv->host_offset = 0; + sof_dtrace_set_host_offset(priv, 0); return 0; } @@ -434,7 +462,7 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev) params.buffer.pages = priv->dma_trace_pages; params.stream_tag = 0; - priv->host_offset = 0; + sof_dtrace_set_host_offset(priv, 0); priv->dtrace_draining = false; ret = sof_dtrace_host_init(sdev, &priv->dmatb, ¶ms); @@ -442,9 +470,10 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev) dev_err(sdev->dev, "Host dtrace init failed: %d\n", ret); return ret; } - dev_dbg(sdev->dev, "%s: stream_tag: %d\n", __func__, params.stream_tag); + dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag); /* send IPC to the DSP */ + priv->dtrace_state = SOF_DTRACE_INITIALIZING; ret = sof_ipc_tx_message(sdev->ipc, ¶ms, sizeof(params), &ipc_reply, sizeof(ipc_reply)); if (ret < 0) { dev_err(sdev->dev, "can't set params for DMA for trace %d\n", ret); @@ -452,17 +481,18 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev) } start: + priv->dtrace_state = SOF_DTRACE_ENABLED; + ret = sof_dtrace_host_trigger(sdev, SNDRV_PCM_TRIGGER_START); if (ret < 0) { dev_err(sdev->dev, "Host dtrace trigger start failed: %d\n", ret); goto trace_release; } - priv->dtrace_state = SOF_DTRACE_ENABLED; - return 0; trace_release: + priv->dtrace_state = SOF_DTRACE_DISABLED; sof_dtrace_host_release(sdev); return ret; } @@ -514,8 +544,7 @@ static int ipc3_dtrace_init(struct snd_sof_dev *sdev) goto table_err; priv->dma_trace_pages = ret; - dev_dbg(sdev->dev, "%s: dma_trace_pages: %d\n", __func__, - priv->dma_trace_pages); + dev_dbg(sdev->dev, "dma_trace_pages: %d\n", priv->dma_trace_pages); if (sdev->first_boot) { ret = debugfs_create_dtrace(sdev); @@ -546,11 +575,9 @@ int ipc3_dtrace_posn_update(struct snd_sof_dev *sdev, if (!sdev->fw_trace_is_supported) return 0; - if (priv->dtrace_state == SOF_DTRACE_ENABLED && - priv->host_offset != posn->host_offset) { - priv->host_offset = posn->host_offset; + if (trace_pos_update_expected(priv) && + sof_dtrace_set_host_offset(priv, posn->host_offset)) wake_up(&priv->trace_sleep); - } if (posn->overflow != 0) dev_err(sdev->dev, diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c index f3c741b49519..c573e7593808 100644 --- a/sound/soc/sof/ipc3-loader.c +++ b/sound/soc/sof/ipc3-loader.c @@ -75,13 +75,12 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev, elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header); elems_counter = elems_size / sizeof(struct sof_config_elem); - dev_dbg(sdev->dev, "%s can hold up to %d config elements\n", - __func__, elems_counter); + dev_dbg(sdev->dev, "manifest can hold up to %d config elements\n", elems_counter); for (i = 0; i < elems_counter; ++i) { elem = &config->elems[i]; - dev_dbg(sdev->dev, "%s get index %d token %d val %d\n", - __func__, i, elem->token, elem->value); + dev_dbg(sdev->dev, "get index %d token %d val %d\n", + i, elem->token, elem->value); switch (elem->token) { case SOF_EXT_MAN_CONFIG_EMPTY: /* unused memory space is zero filled - mapped to EMPTY elements */ @@ -323,10 +322,10 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev) header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset); load_module = sof_ops(sdev)->load_module; if (!load_module) { - dev_dbg(sdev->dev, "%s: Using generic module loading\n", __func__); + dev_dbg(sdev->dev, "Using generic module loading\n"); load_module = sof_ipc3_parse_module_memcpy; } else { - dev_dbg(sdev->dev, "%s: Using custom module loading\n", __func__); + dev_dbg(sdev->dev, "Using custom module loading\n"); } /* parse each module */ diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index c8774a891d6f..b97e63d3724a 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -344,10 +344,10 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min, channels->max); break; case SOF_DAI_AMD_DMIC: - rate->min = private->dai_config->acpdmic.fsync_rate; - rate->max = private->dai_config->acpdmic.fsync_rate; - channels->min = private->dai_config->acpdmic.tdm_slots; - channels->max = private->dai_config->acpdmic.tdm_slots; + rate->min = private->dai_config->acpdmic.pdm_rate; + rate->max = private->dai_config->acpdmic.pdm_rate; + channels->min = private->dai_config->acpdmic.pdm_ch; + channels->max = private->dai_config->acpdmic.pdm_ch; dev_dbg(component->dev, "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 10740c55294d..99b62fe7a95c 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -17,6 +17,9 @@ /* Full volume for default values */ #define VOL_ZERO_DB BIT(VOLUME_FWL) +/* size of tplg ABI in bytes */ +#define SOF_IPC3_TPLG_ABI_SIZE 3 + struct sof_widget_data { int ctrl_type; int ipc_cmd; @@ -263,6 +266,16 @@ static const struct sof_topology_token afe_tokens[] = { offsetof(struct sof_ipc_dai_mtk_afe_params, format)}, }; +/* ACPDMIC */ +static const struct sof_topology_token acpdmic_tokens[] = { + {SOF_TKN_AMD_ACPDMIC_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)}, + {SOF_TKN_AMD_ACPDMIC_CH, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)}, +}; + /* Core tokens */ static const struct sof_topology_token core_tokens[] = { {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -297,6 +310,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)}, [SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)}, [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)}, + [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)}, }; /** @@ -1117,20 +1131,22 @@ static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_so struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; struct sof_dai_private_data *private = dai->private; u32 size = sizeof(*config); + int ret; /* handle master/slave and inverted clocks */ sof_dai_set_format(hw_config, config); - /* init IPC */ - memset(&config->acpdmic, 0, sizeof(config->acpdmic)); config->hdr.size = size; - config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + /* parse the required set of ACPDMIC tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n", - config->dai_index, config->acpdmic.tdm_slots, - config->acpdmic.fsync_rate); + config->dai_index, config->acpdmic.pdm_ch, + config->acpdmic.pdm_rate); dai->number_configs = 1; dai->current_config = 0; @@ -1436,8 +1452,8 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) if (ret < 0) goto free; - dev_dbg(scomp->dev, "%s dai %s: type %d index %d\n", - __func__, swidget->widget->name, comp_dai->type, comp_dai->dai_index); + dev_dbg(scomp->dev, "dai %s: type %d index %d\n", + swidget->widget->name, comp_dai->type, comp_dai->dai_index); sof_dbg_comp_config(scomp, &comp_dai->config); /* now update DAI config */ @@ -2302,6 +2318,50 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da return -EINVAL; } +static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index, + struct snd_soc_tplg_manifest *man) +{ + u32 size = le32_to_cpu(man->priv.size); + u32 abi_version; + + /* backward compatible with tplg without ABI info */ + if (!size) { + dev_dbg(scomp->dev, "No topology ABI info\n"); + return 0; + } + + if (size != SOF_IPC3_TPLG_ABI_SIZE) { + dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", + __func__, size); + return -EINVAL; + } + + dev_info(scomp->dev, + "Topology: ABI %d:%d:%d Kernel ABI %hhu:%hhu:%hhu\n", + man->priv.data[0], man->priv.data[1], man->priv.data[2], + SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); + + abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]); + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) { + dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__); + return -EINVAL; + } + + if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) { + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) { + dev_warn(scomp->dev, "%s: Topology ABI is more recent than kernel\n", + __func__); + } else { + dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", + __func__); + return -EINVAL; + } + } + + return 0; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -2412,4 +2472,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = { .dai_get_clk = sof_ipc3_dai_get_clk, .set_up_all_pipelines = sof_ipc3_set_up_all_pipelines, .tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines, + .parse_manifest = sof_ipc3_parse_manifest, }; diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index dff5feaad370..1fb132b477bf 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -147,6 +147,8 @@ static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) case SOF_IPC_TRACE_DMA_PARAMS: str2 = "DMA_PARAMS"; break; case SOF_IPC_TRACE_DMA_POSITION: + if (!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) + return; str2 = "DMA_POSITION"; break; case SOF_IPC_TRACE_DMA_PARAMS_EXT: str2 = "DMA_PARAMS_EXT"; break; @@ -290,7 +292,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) dev_err(sdev->dev, "ipc tx timed out for %#x (msg/reply size: %d/%zu)\n", hdr->cmd, hdr->size, msg->reply_size); - snd_sof_handle_fw_exception(ipc->sdev); + snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout"); ret = -ETIMEDOUT; } else { ret = msg->reply_error; @@ -299,7 +301,8 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) "ipc tx error for %#x (msg/reply size: %d/%zu): %d\n", hdr->cmd, hdr->size, msg->reply_size, ret); } else { - ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); + if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS)) + ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); if (msg->reply_size) /* copy the data returned from DSP */ memcpy(reply_data, msg->reply_data, @@ -1037,6 +1040,23 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev) ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd); } +static int sof_ipc3_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on) +{ + struct sof_ipc_pm_core_config core_cfg = { + .hdr.size = sizeof(core_cfg), + .hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, + }; + struct sof_ipc_reply reply; + + if (on) + core_cfg.enable_mask = sdev->enabled_cores_mask | BIT(core_idx); + else + core_cfg.enable_mask = sdev->enabled_cores_mask & ~BIT(core_idx); + + return sof_ipc3_tx_msg(sdev, &core_cfg, sizeof(core_cfg), + &reply, sizeof(reply), false); +} + static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx = { @@ -1063,6 +1083,7 @@ static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev) static const struct sof_ipc_pm_ops ipc3_pm_ops = { .ctx_save = sof_ipc3_ctx_save, .ctx_restore = sof_ipc3_ctx_restore, + .set_core_state = sof_ipc3_set_core_state, }; const struct sof_ipc_ops ipc3_ops = { diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c new file mode 100644 index 000000000000..0d5a578c3496 --- /dev/null +++ b/sound/soc/sof/ipc4-control.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// + +#include "sof-priv.h" +#include "sof-audio.h" +#include "ipc4-priv.h" +#include "ipc4-topology.h" + +static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set) +{ + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_ops *iops = sdev->ipc->ops; + struct sof_ipc4_msg *msg = &cdata->msg; + struct snd_sof_widget *swidget; + bool widget_found = false; + + /* find widget associated with the control */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->comp_id == scontrol->comp_id) { + widget_found = true; + break; + } + } + + if (!widget_found) { + dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name); + return -ENOENT; + } + + /* + * Volatile controls should always be part of static pipelines and the widget use_count + * would always be > 0 in this case. For the others, just return the cached value if the + * widget is not set up. + */ + if (!swidget->use_count) + return 0; + + msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; + msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); + + return iops->set_get_data(sdev, msg, msg->data_size, set); +} + +static int +sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, + struct snd_sof_control *scontrol) +{ + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct sof_ipc4_gain *gain = swidget->private; + struct sof_ipc4_msg *msg = &cdata->msg; + struct sof_ipc4_gain_data data; + bool all_channels_equal = true; + u32 value; + int ret, i; + + /* check if all channel values are equal */ + value = cdata->chanv[0].value; + for (i = 1; i < scontrol->num_channels; i++) { + if (cdata->chanv[i].value != value) { + all_channels_equal = false; + break; + } + } + + /* + * notify DSP with a single IPC message if all channel values are equal. Otherwise send + * a separate IPC for each channel. + */ + for (i = 0; i < scontrol->num_channels; i++) { + if (all_channels_equal) { + data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; + data.init_val = cdata->chanv[0].value; + } else { + data.channels = cdata->chanv[i].channel; + data.init_val = cdata->chanv[i].value; + } + + /* set curve type and duration from topology */ + data.curve_duration = gain->data.curve_duration; + data.curve_type = gain->data.curve_type; + + msg->data_ptr = &data; + msg->data_size = sizeof(data); + + ret = sof_ipc4_set_get_kcontrol_data(scontrol, true); + msg->data_ptr = NULL; + msg->data_size = 0; + if (ret < 0) { + dev_err(sdev->dev, "Failed to set volume update for %s\n", + scontrol->name); + return ret; + } + + if (all_channels_equal) + break; + } + + return 0; +} + +static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + unsigned int channels = scontrol->num_channels; + struct snd_sof_widget *swidget; + bool widget_found = false; + bool change = false; + unsigned int i; + int ret; + + /* update each channel */ + for (i = 0; i < channels; i++) { + u32 value = mixer_to_ipc(ucontrol->value.integer.value[i], + scontrol->volume_table, scontrol->max + 1); + + change = change || (value != cdata->chanv[i].value); + cdata->chanv[i].channel = i; + cdata->chanv[i].value = value; + } + + if (!pm_runtime_active(scomp->dev)) + return change; + + /* find widget associated with the control */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->comp_id == scontrol->comp_id) { + widget_found = true; + break; + } + } + + if (!widget_found) { + dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name); + return false; + } + + ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol); + if (ret < 0) + return false; + + return change; +} + +static int sof_ipc4_volume_get(struct snd_sof_control *scontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + unsigned int channels = scontrol->num_channels; + unsigned int i; + + for (i = 0; i < channels; i++) + ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value, + scontrol->volume_table, + scontrol->max + 1); + + return 0; +} + +/* set up all controls for the widget */ +static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) +{ + struct snd_sof_control *scontrol; + int ret; + + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) + if (scontrol->comp_id == swidget->comp_id) { + ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol); + if (ret < 0) { + dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n", + __func__, scontrol->comp_id, swidget->widget->name); + return ret; + } + } + + return 0; +} + +static int +sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size) +{ + int i; + + /* init the volume table */ + scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); + if (!scontrol->volume_table) + return -ENOMEM; + + /* populate the volume table */ + for (i = 0; i < size ; i++) { + u32 val = vol_compute_gain(i, tlv); + u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */ + + scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ? + SOF_IPC4_VOL_ZERO_DB : q31val; + } + + return 0; +} + +const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = { + .volume_put = sof_ipc4_volume_put, + .volume_get = sof_ipc4_volume_get, + .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup, + .set_up_volume_table = sof_ipc4_set_up_volume_table, +}; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c new file mode 100644 index 000000000000..6a702f9dc065 --- /dev/null +++ b/sound/soc/sof/ipc4-pcm.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// + +#include <sound/pcm_params.h> +#include <sound/sof/ipc4/header.h> +#include "sof-audio.h" +#include "sof-priv.h" +#include "ipc4-priv.h" +#include "ipc4-topology.h" + +int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state) +{ + struct sof_ipc4_msg msg = {{ 0 }}; + u32 primary; + + dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state); + + primary = state; + primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id); + primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); + primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); + + msg.primary = primary; + + return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); +} +EXPORT_SYMBOL(sof_ipc4_set_pipeline_state); + +static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int state) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_sof_widget *pipeline_widget; + struct snd_soc_dapm_widget_list *list; + struct snd_soc_dapm_widget *widget; + struct sof_ipc4_pipeline *pipeline; + struct snd_sof_widget *swidget; + struct snd_sof_pcm *spcm; + int ret = 0; + int num_widgets; + + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + list = spcm->stream[substream->stream].list; + + for_each_dapm_widgets(list, num_widgets, widget) { + swidget = widget->dobj.private; + + if (!swidget) + continue; + + /* + * set pipeline state for both FE and BE pipelines for RUNNING state. + * For PAUSE/RESET, set the pipeline state only for the FE pipeline. + */ + switch (state) { + case SOF_IPC4_PIPE_PAUSED: + case SOF_IPC4_PIPE_RESET: + if (!WIDGET_IS_AIF(swidget->id)) + continue; + break; + default: + break; + } + + /* find pipeline widget for the pipeline that this widget belongs to */ + pipeline_widget = swidget->pipe_widget; + pipeline = (struct sof_ipc4_pipeline *)pipeline_widget->private; + + if (pipeline->state == state) + continue; + + /* first set the pipeline to PAUSED state */ + if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) { + dev_err(sdev->dev, "failed to pause pipeline %d\n", + swidget->pipeline_id); + return ret; + } + } + + pipeline->state = SOF_IPC4_PIPE_PAUSED; + + if (pipeline->state == state) + continue; + + /* then set the final state */ + ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, state); + if (ret < 0) { + dev_err(sdev->dev, "failed to set state %d for pipeline %d\n", + state, swidget->pipeline_id); + break; + } + + pipeline->state = state; + } + + return ret; +} + +static int sof_ipc4_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + int state; + + /* determine the pipeline state */ + switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + state = SOF_IPC4_PIPE_PAUSED; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + state = SOF_IPC4_PIPE_RUNNING; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + state = SOF_IPC4_PIPE_PAUSED; + break; + default: + dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd); + return -EINVAL; + } + + /* set the pipeline state */ + return sof_ipc4_trigger_pipelines(component, substream, state); +} + +static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET); +} + +static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, + struct snd_pcm_hw_params *params) +{ + struct snd_sof_dai_link *slink; + struct snd_sof_dai *dai; + bool dai_link_found = false; + int i; + + list_for_each_entry(slink, &sdev->dai_link_list, list) { + if (!strcmp(slink->link->name, link_name)) { + dai_link_found = true; + break; + } + } + + if (!dai_link_found) + return; + + for (i = 0; i < slink->num_hw_configs; i++) { + struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; + + if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) { + /* set current config for all DAI's with matching name */ + list_for_each_entry(dai, &sdev->dai_list, list) + if (!strcmp(slink->link->name, dai->name)) + dai->current_config = le32_to_cpu(hw_config->id); + break; + } + } +} + +static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); + struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct sof_ipc4_copier *ipc4_copier; + struct snd_soc_dpcm *dpcm; + + if (!dai) { + dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, + rtd->dai_link->name); + return -EINVAL; + } + + ipc4_copier = dai->private; + if (!ipc4_copier) { + dev_err(component->dev, "%s: No private data found for DAI %s\n", + __func__, rtd->dai_link->name); + return -EINVAL; + } + + /* always set BE format to 32-bits for both playback and capture */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + + /* + * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required + * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI + * pipeline gets triggered and the pipeline widgets are freed. + */ + for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { + struct snd_soc_pcm_runtime *fe = dpcm->fe; + + fe->dai_link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE; + } + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_SSP: + ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); + break; + default: + break; + } + + return 0; +} + +const struct sof_ipc_pcm_ops ipc4_pcm_ops = { + .trigger = sof_ipc4_pcm_trigger, + .hw_free = sof_ipc4_pcm_hw_free, + .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup, +}; diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 2b71d5675933..9492fe1796c2 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -18,11 +18,13 @@ * @manifest_fw_hdr_offset: FW header offset in the manifest * @num_fw_modules : Number of modules in base FW * @fw_modules: Array of base FW modules + * @nhlt: NHLT table either from the BIOS or the topology manifest */ struct sof_ipc4_fw_data { u32 manifest_fw_hdr_offset; int num_fw_modules; void *fw_modules; + void *nhlt; }; /** @@ -40,5 +42,10 @@ struct sof_ipc4_fw_module { }; extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops; +extern const struct sof_ipc_tplg_ops ipc4_tplg_ops; +extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops; +extern const struct sof_ipc_pcm_ops ipc4_pcm_ops; + +int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state); #endif diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c new file mode 100644 index 000000000000..34f805431f2e --- /dev/null +++ b/sound/soc/sof/ipc4-topology.c @@ -0,0 +1,1760 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// +#include <uapi/sound/sof/tokens.h> +#include <sound/pcm_params.h> +#include <sound/sof/ext_manifest4.h> +#include <sound/intel-nhlt.h> +#include "sof-priv.h" +#include "sof-audio.h" +#include "ipc4-priv.h" +#include "ipc4-topology.h" +#include "ops.h" + +#define SOF_IPC4_GAIN_PARAM_ID 0 +#define SOF_IPC4_TPLG_ABI_SIZE 6 + +static DEFINE_IDA(alh_group_ida); + +static const struct sof_topology_token ipc4_sched_tokens[] = { + {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_pipeline, lp_mode)} +}; + +static const struct sof_topology_token pipeline_tokens[] = { + {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, +}; + +static const struct sof_topology_token ipc4_comp_tokens[] = { + {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_base_module_cfg, cpc)}, + {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, +}; + +static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = { + {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_base_module_cfg, ibs)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_base_module_cfg, obs)}, +}; + +static const struct sof_topology_token ipc4_in_audio_format_tokens[] = { + {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, bit_depth)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, ch_map)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, ch_cfg)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, +}; + +static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { + {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, bit_depth)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, ch_map)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, ch_cfg)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, +}; + +static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = { + {SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, +}; + +static const struct sof_topology_token ipc4_copier_tokens[] = { + {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, +}; + +static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = { + {SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + 0}, +}; + +static const struct sof_topology_token dai_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc4_copier, dai_type)}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_copier, dai_index)}, +}; + +/* Component extended tokens */ +static const struct sof_topology_token comp_ext_tokens[] = { + {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, + offsetof(struct snd_sof_widget, uuid)}, +}; + +static const struct sof_topology_token gain_tokens[] = { + {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)}, + {SOF_TKN_GAIN_RAMP_DURATION, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_gain_data, curve_duration)}, + {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, +}; + +static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { + [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, + [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, + [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens, + ARRAY_SIZE(ipc4_sched_tokens)}, + [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens, + ARRAY_SIZE(comp_ext_tokens)}, + [SOF_COMP_TOKENS] = {"IPC4 Component tokens", + ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)}, + [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens", + ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)}, + [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens", + ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)}, + [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens", + ipc4_audio_format_buffer_size_tokens, + ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)}, + [SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens", + ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)}, + [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, + ARRAY_SIZE(ipc4_copier_tokens)}, + [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", + ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, + [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, +}; + +static void sof_ipc4_dbg_audio_format(struct device *dev, + struct sof_ipc4_audio_format *format, + size_t object_size, int num_format) +{ + struct sof_ipc4_audio_format *fmt; + void *ptr = format; + int i; + + for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) { + fmt = ptr; + dev_dbg(dev, + " #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n", + i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, + fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg); + } +} + +/** + * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples + * @scomp: pointer to pointer to SOC component + * @swidget: pointer to struct snd_sof_widget containing tuples + * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in + * @has_out_format: true if available_fmt contains output format + * + * Return: 0 if successful + */ +static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, + struct snd_sof_widget *swidget, + struct sof_ipc4_available_audio_format *available_fmt, + bool has_out_format) +{ + struct sof_ipc4_base_module_cfg *base_config; + struct sof_ipc4_audio_format *out_format; + int audio_fmt_num = 0; + int ret, i; + + ret = sof_update_ipc_object(scomp, &audio_fmt_num, + SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(audio_fmt_num), 1); + if (ret || audio_fmt_num <= 0) { + dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num); + return -EINVAL; + } + available_fmt->audio_fmt_num = audio_fmt_num; + + dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num); + + base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL); + if (!base_config) + return -ENOMEM; + + /* set cpc and is_pages for all base_cfg */ + for (i = 0; i < available_fmt->audio_fmt_num; i++) { + ret = sof_update_ipc_object(scomp, &base_config[i], + SOF_COMP_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*base_config), 1); + if (ret) { + dev_err(scomp->dev, "parse comp tokens failed %d\n", ret); + goto err_in; + } + } + + /* copy the ibs/obs for each base_cfg */ + ret = sof_update_ipc_object(scomp, base_config, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*base_config), + available_fmt->audio_fmt_num); + if (ret) { + dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret); + goto err_in; + } + + for (i = 0; i < available_fmt->audio_fmt_num; i++) + dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i, + base_config[i].ibs, base_config[i].obs, + base_config[i].cpc, base_config[i].is_pages); + + ret = sof_update_ipc_object(scomp, &base_config->audio_fmt, + SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*base_config), + available_fmt->audio_fmt_num); + if (ret) { + dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret); + goto err_in; + } + + dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt, + sizeof(*base_config), + available_fmt->audio_fmt_num); + + available_fmt->base_config = base_config; + + if (!has_out_format) + return 0; + + out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL); + if (!out_format) { + ret = -ENOMEM; + goto err_in; + } + + ret = sof_update_ipc_object(scomp, out_format, + SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*out_format), + available_fmt->audio_fmt_num); + + if (ret) { + dev_err(scomp->dev, "parse output audio_fmt tokens failed\n"); + goto err_out; + } + + available_fmt->out_audio_fmt = out_format; + dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format), + available_fmt->audio_fmt_num); + + return 0; + +err_out: + kfree(out_format); +err_in: + kfree(base_config); + + return ret; +} + +static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget) +{ + kfree(swidget->private); +} + +static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules; + int i; + + if (!fw_modules) { + dev_err(sdev->dev, "no fw_module information\n"); + return -EINVAL; + } + + /* set module info */ + for (i = 0; i < ipc4_data->num_fw_modules; i++) { + if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) { + swidget->module_info = &fw_modules[i]; + return 0; + } + } + + dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n", + swidget->widget->name, &swidget->uuid); + return -EINVAL; +} + +static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) +{ + struct sof_ipc4_fw_module *fw_module; + int ret; + + ret = sof_ipc4_widget_set_module_info(swidget); + if (ret) + return ret; + + fw_module = swidget->module_info; + + msg->primary = fw_module->man4_module_entry.id; + msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE); + msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + + msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id); + msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); + + return 0; +} + +static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_available_audio_format *available_fmt; + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc4_copier *ipc4_copier; + int node_type = 0; + int ret, i; + + ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); + if (!ipc4_copier) + return -ENOMEM; + + swidget->private = ipc4_copier; + available_fmt = &ipc4_copier->available_fmt; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true); + if (ret) + goto free_copier; + + available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), + GFP_KERNEL); + if (!available_fmt->dma_buffer_size) { + ret = -ENOMEM; + goto free_copier; + } + + ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, + SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(u32), + available_fmt->audio_fmt_num); + if (ret) { + dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", + swidget->widget->name); + goto err; + } + + dev_dbg(scomp->dev, "dma buffer size:\n"); + for (i = 0; i < available_fmt->audio_fmt_num; i++) + dev_dbg(scomp->dev, "%d: %u\n", i, + available_fmt->dma_buffer_size[i]); + + ret = sof_update_ipc_object(scomp, &node_type, + SOF_COPIER_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(node_type), 1); + + if (ret) { + dev_err(scomp->dev, "parse host copier node type token failed %d\n", + ret); + goto err; + } + dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type); + + ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); + ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); + if (!ipc4_copier->gtw_attr) { + ret = -ENOMEM; + goto err; + } + + ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; + ipc4_copier->data.gtw_cfg.config_length = + sizeof(struct sof_ipc4_gtw_attributes) >> 2; + + /* set up module info and message header */ + ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); + if (ret) + goto free_gtw_attr; + + return 0; + +free_gtw_attr: + kfree(ipc4_copier->gtw_attr); +err: + kfree(available_fmt->dma_buffer_size); +free_copier: + kfree(ipc4_copier); + return ret; +} + +static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_copier *ipc4_copier = swidget->private; + struct sof_ipc4_available_audio_format *available_fmt; + + if (!ipc4_copier) + return; + + available_fmt = &ipc4_copier->available_fmt; + kfree(available_fmt->dma_buffer_size); + kfree(available_fmt->base_config); + kfree(available_fmt->out_audio_fmt); + kfree(ipc4_copier->gtw_attr); + kfree(ipc4_copier); + swidget->private = NULL; +} + +static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_available_audio_format *available_fmt; + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_copier *ipc4_copier; + int node_type = 0; + int ret, i; + + ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); + if (!ipc4_copier) + return -ENOMEM; + + available_fmt = &ipc4_copier->available_fmt; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true); + if (ret) + goto free_copier; + + available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), + GFP_KERNEL); + if (!available_fmt->dma_buffer_size) { + ret = -ENOMEM; + goto free_copier; + } + + ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, + SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(u32), + available_fmt->audio_fmt_num); + if (ret) { + dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", + swidget->widget->name); + goto err; + } + + for (i = 0; i < available_fmt->audio_fmt_num; i++) + dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i, + available_fmt->dma_buffer_size[i]); + + ret = sof_update_ipc_object(scomp, &node_type, + SOF_COPIER_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(node_type), 1); + if (ret) { + dev_err(scomp->dev, "parse dai node type failed %d\n", ret); + goto err; + } + + ret = sof_update_ipc_object(scomp, ipc4_copier, + SOF_DAI_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(u32), 1); + if (ret) { + dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret); + goto err; + } + + dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name, + node_type, ipc4_copier->dai_type, ipc4_copier->dai_index); + + ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_ALH: + { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_alh_configuration_blob *blob; + struct snd_sof_widget *w; + + blob = kzalloc(sizeof(*blob), GFP_KERNEL); + if (!blob) { + ret = -ENOMEM; + goto err; + } + + list_for_each_entry(w, &sdev->widget_list, list) { + if (w->widget->sname && + strcmp(w->widget->sname, swidget->widget->sname)) + continue; + + blob->alh_cfg.count++; + } + + ipc4_copier->copier_config = (uint32_t *)blob; + ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2; + break; + } + case SOF_DAI_INTEL_SSP: + /* set SSP DAI index as the node_id */ + ipc4_copier->data.gtw_cfg.node_id |= + SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index); + break; + case SOF_DAI_INTEL_DMIC: + /* set DMIC DAI index as the node_id */ + ipc4_copier->data.gtw_cfg.node_id |= + SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index); + break; + default: + ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); + if (!ipc4_copier->gtw_attr) { + ret = -ENOMEM; + goto err; + } + + ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; + ipc4_copier->data.gtw_cfg.config_length = + sizeof(struct sof_ipc4_gtw_attributes) >> 2; + break; + } + + dai->scomp = scomp; + dai->private = ipc4_copier; + + /* set up module info and message header */ + ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); + if (ret) + goto free_copier_config; + + return 0; + +free_copier_config: + kfree(ipc4_copier->copier_config); +err: + kfree(available_fmt->dma_buffer_size); +free_copier: + kfree(ipc4_copier); + return ret; +} + +static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_available_audio_format *available_fmt; + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_copier *ipc4_copier; + + if (!dai) + return; + + ipc4_copier = dai->private; + available_fmt = &ipc4_copier->available_fmt; + + kfree(available_fmt->dma_buffer_size); + kfree(available_fmt->base_config); + kfree(available_fmt->out_audio_fmt); + if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && + ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC) + kfree(ipc4_copier->copier_config); + kfree(dai->private); + kfree(dai); + swidget->private = NULL; +} + +static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc4_pipeline *pipeline; + int ret; + + pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); + if (!pipeline) + return -ENOMEM; + + ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*pipeline), 1); + if (ret) { + dev_err(scomp->dev, "parsing scheduler tokens failed\n"); + goto err; + } + + /* parse one set of pipeline tokens */ + ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*swidget), 1); + if (ret) { + dev_err(scomp->dev, "parsing pipeline tokens failed\n"); + goto err; + } + + /* TODO: Get priority from topology */ + pipeline->priority = 0; + + dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n", + swidget->widget->name, swidget->pipeline_id, + pipeline->priority, pipeline->lp_mode); + + swidget->private = pipeline; + + pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority); + pipeline->msg.primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id); + pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE); + pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); + + pipeline->msg.extension = pipeline->lp_mode; + pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; + + return 0; +err: + kfree(pipeline); + return ret; +} + +static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_fw_module *fw_module; + struct snd_sof_control *scontrol; + struct sof_ipc4_gain *gain; + int ret; + + gain = kzalloc(sizeof(*gain), GFP_KERNEL); + if (!gain) + return -ENOMEM; + + swidget->private = gain; + + gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; + gain->data.init_val = SOF_IPC4_VOL_ZERO_DB; + + /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false); + if (ret) + goto err; + + ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(gain->data), 1); + if (ret) { + dev_err(scomp->dev, "Parsing gain tokens failed\n"); + goto err; + } + + dev_dbg(scomp->dev, + "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n", + swidget->widget->name, gain->data.curve_type, gain->data.curve_duration, + gain->data.init_val, gain->base_config.cpc); + + ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); + if (ret) + goto err; + + fw_module = swidget->module_info; + + /* update module ID for all kcontrols for this widget */ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) + if (scontrol->comp_id == swidget->comp_id) { + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct sof_ipc4_msg *msg = &cdata->msg; + + msg->primary |= fw_module->man4_module_entry.id; + } + + return 0; +err: + kfree(gain); + return ret; +} + +static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc4_mixer *mixer; + int ret; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + + swidget->private = mixer; + + /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false); + if (ret) + goto err; + + ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg); + if (ret) + goto err; + + return 0; +err: + kfree(mixer); + return ret; +} + +static void +sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, + struct sof_ipc4_base_module_cfg *base_config) +{ + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + int task_mem, queue_mem; + int ibs, bss, total; + + ibs = base_config->ibs; + bss = base_config->is_pages; + + task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE; + task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss; + + if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) { + task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE); + task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE; + task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE; + } else { + task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE); + task_mem += SOF_IPC4_DP_TASK_LIST_SIZE; + } + + ibs = SOF_IPC4_FW_ROUNDUP(ibs); + queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs); + + total = SOF_IPC4_FW_PAGE(task_mem + queue_mem); + + pipe_widget = swidget->pipe_widget; + pipeline = pipe_widget->private; + pipeline->mem_usage += total; +} + +static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget) +{ + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + int max_instances = fw_module->man4_module_entry.instance_max_count; + + swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL); + if (swidget->instance_id < 0) { + dev_err(sdev->dev, "failed to assign instance id for widget %s", + swidget->widget->name); + return swidget->instance_id; + } + + return 0; +} + +static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + struct sof_ipc4_base_module_cfg *base_config, + struct sof_ipc4_audio_format *out_format, + struct snd_pcm_hw_params *params, + struct sof_ipc4_available_audio_format *available_fmt, + size_t object_offset) +{ + void *ptr = available_fmt->ref_audio_fmt; + u32 valid_bits; + u32 channels; + u32 rate; + int sample_valid_bits; + int i; + + if (!ptr) { + dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + sample_valid_bits = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + sample_valid_bits = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + sample_valid_bits = 32; + break; + default: + dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); + return -EINVAL; + } + + if (!available_fmt->audio_fmt_num) { + dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name); + return -EINVAL; + } + + /* + * Search supported audio formats to match rate, channels ,and + * sample_valid_bytes from runtime params + */ + for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) { + struct sof_ipc4_audio_format *fmt = ptr; + + rate = fmt->sampling_frequency; + channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + if (params_rate(params) == rate && params_channels(params) == channels && + sample_valid_bits == valid_bits) { + dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n", + rate, valid_bits, channels, i); + + /* copy ibs/obs and input format */ + memcpy(base_config, &available_fmt->base_config[i], + sizeof(struct sof_ipc4_base_module_cfg)); + + /* copy output format */ + if (out_format) + memcpy(out_format, &available_fmt->out_audio_fmt[i], + sizeof(struct sof_ipc4_audio_format)); + break; + } + } + + if (i == available_fmt->audio_fmt_num) { + dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", + __func__, params_rate(params), sample_valid_bits, params_channels(params)); + return -EINVAL; + } + + dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt, + sizeof(*base_config), 1); + if (out_format) { + dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(sdev->dev, out_format, + sizeof(*out_format), 1); + } + + /* Return the index of the matched format */ + return i; +} + +static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + struct sof_ipc4_copier *ipc4_copier = NULL; + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + + /* reset pipeline memory usage */ + pipe_widget = swidget->pipe_widget; + pipeline = pipe_widget->private; + pipeline->mem_usage = 0; + + if (WIDGET_IS_AIF(swidget->id)) { + ipc4_copier = swidget->private; + } else if (WIDGET_IS_DAI(swidget->id)) { + struct snd_sof_dai *dai = swidget->private; + + ipc4_copier = dai->private; + if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { + struct sof_ipc4_alh_configuration_blob *blob; + unsigned int group_id; + + blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; + if (blob->alh_cfg.count > 1) { + group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - + ALH_MULTI_GTW_BASE; + ida_free(&alh_group_ida, group_id); + } + } + } + + if (ipc4_copier) { + kfree(ipc4_copier->ipc_config_data); + ipc4_copier->ipc_config_data = NULL; + ipc4_copier->ipc_config_size = 0; + } + + ida_free(&fw_module->m_ida, swidget->instance_id); +} + +#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) +static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, + int *sample_rate, int *channel_count, int *bit_depth) +{ + struct snd_soc_tplg_hw_config *hw_config; + struct snd_sof_dai_link *slink; + bool dai_link_found = false; + bool hw_cfg_found = false; + int i; + + /* get current hw_config from link */ + list_for_each_entry(slink, &sdev->dai_link_list, list) { + if (!strcmp(slink->link->name, dai->name)) { + dai_link_found = true; + break; + } + } + + if (!dai_link_found) { + dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name); + return -EINVAL; + } + + for (i = 0; i < slink->num_hw_configs; i++) { + hw_config = &slink->hw_configs[i]; + if (dai->current_config == le32_to_cpu(hw_config->id)) { + hw_cfg_found = true; + break; + } + } + + if (!hw_cfg_found) { + dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__, + dai->name); + return -EINVAL; + } + + *bit_depth = le32_to_cpu(hw_config->tdm_slot_width); + *channel_count = le32_to_cpu(hw_config->tdm_slots); + *sample_rate = le32_to_cpu(hw_config->fsync_rate); + + dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n", + *sample_rate, *bit_depth, *channel_count); + + return 0; +} + +static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, + struct snd_pcm_hw_params *params, u32 dai_index, + u32 linktype, u8 dir, u32 **dst, u32 *len) +{ + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct nhlt_specific_cfg *cfg; + int sample_rate, channel_count; + int bit_depth, ret; + u32 nhlt_type; + + /* convert to NHLT type */ + switch (linktype) { + case SOF_DAI_INTEL_DMIC: + nhlt_type = NHLT_LINK_DMIC; + bit_depth = params_width(params); + channel_count = params_channels(params); + sample_rate = params_rate(params); + break; + case SOF_DAI_INTEL_SSP: + nhlt_type = NHLT_LINK_SSP; + ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count, + &bit_depth); + if (ret < 0) + return ret; + break; + default: + return 0; + } + + dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n", + dai_index, nhlt_type, dir); + + /* find NHLT blob with matching params */ + cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, + bit_depth, bit_depth, channel_count, sample_rate, + dir, 0); + + if (!cfg) { + dev_err(sdev->dev, + "no matching blob for sample rate: %d sample width: %d channels: %d\n", + sample_rate, bit_depth, channel_count); + return -EINVAL; + } + + /* config length should be in dwords */ + *len = cfg->size >> 2; + *dst = (u32 *)cfg->caps; + + return 0; +} +#else +static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, + struct snd_pcm_hw_params *params, u32 dai_index, + u32 linktype, u8 dir, u32 **dst, u32 *len) +{ + return 0; +} +#endif + +static int +sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + struct sof_ipc4_available_audio_format *available_fmt; + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_copier_data *copier_data; + struct snd_pcm_hw_params *ref_params; + struct sof_ipc4_copier *ipc4_copier; + struct snd_sof_dai *dai; + struct snd_mask *fmt; + int out_sample_valid_bits; + size_t ref_audio_fmt_size; + void **ipc_config_data; + int *ipc_config_size; + u32 **data; + int ipc_size, ret; + + dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); + + switch (swidget->id) { + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: + { + struct sof_ipc4_gtw_attributes *gtw_attr; + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + + pipe_widget = swidget->pipe_widget; + pipeline = pipe_widget->private; + ipc4_copier = (struct sof_ipc4_copier *)swidget->private; + gtw_attr = ipc4_copier->gtw_attr; + copier_data = &ipc4_copier->data; + available_fmt = &ipc4_copier->available_fmt; + + /* + * base_config->audio_fmt and out_audio_fmt represent the input and output audio + * formats. Use the input format as the reference to match pcm params for playback + * and the output format as reference for capture. + */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; + ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); + } else { + available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; + ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); + } + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; + copier_data->gtw_cfg.node_id |= + SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1); + + /* set gateway attributes */ + gtw_attr->lp_buffer_alloc = pipeline->lp_mode; + ref_params = fe_params; + break; + } + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + { + dai = swidget->private; + + ipc4_copier = (struct sof_ipc4_copier *)dai->private; + copier_data = &ipc4_copier->data; + available_fmt = &ipc4_copier->available_fmt; + if (dir == SNDRV_PCM_STREAM_CAPTURE) { + available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; + ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); + + /* + * modify the input params for the dai copier as it only supports + * 32-bit always + */ + fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + } else { + available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; + ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); + } + + ref_params = pipeline_params; + + ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, + ipc4_copier->dai_type, dir, + &ipc4_copier->copier_config, + &copier_data->gtw_cfg.config_length); + if (ret < 0) + return ret; + + break; + } + default: + dev_err(sdev->dev, "unsupported type %d for copier %s", + swidget->id, swidget->widget->name); + return -EINVAL; + } + + /* set input and output audio formats */ + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, + &copier_data->out_format, ref_params, + available_fmt, ref_audio_fmt_size); + if (ret < 0) + return ret; + + switch (swidget->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + { + /* + * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. + * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt + */ + if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { + struct sof_ipc4_alh_configuration_blob *blob; + struct sof_ipc4_copier_data *alh_data; + struct sof_ipc4_copier *alh_copier; + struct snd_sof_widget *w; + u32 ch_mask = 0; + u32 ch_map; + int i; + + blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; + + blob->gw_attr.lp_buffer_alloc = 0; + + /* Get channel_mask from ch_map */ + ch_map = copier_data->base_config.audio_fmt.ch_map; + for (i = 0; ch_map; i++) { + if ((ch_map & 0xf) != 0xf) + ch_mask |= BIT(i); + ch_map >>= 4; + } + + /* + * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] + * for all widgets with the same stream name + */ + i = 0; + list_for_each_entry(w, &sdev->widget_list, list) { + if (w->widget->sname && + strcmp(w->widget->sname, swidget->widget->sname)) + continue; + + dai = w->private; + alh_copier = (struct sof_ipc4_copier *)dai->private; + alh_data = &alh_copier->data; + blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id; + blob->alh_cfg.mapping[i].channel_mask = ch_mask; + i++; + } + if (blob->alh_cfg.count > 1) { + int group_id; + + group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT, + GFP_KERNEL); + + if (group_id < 0) + return group_id; + + /* add multi-gateway base */ + group_id += ALH_MULTI_GTW_BASE; + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; + copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id); + } + } + } + } + + /* modify the input params for the next widget */ + fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); + out_sample_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); + snd_mask_none(fmt); + switch (out_sample_valid_bits) { + case 16: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + break; + case 24: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + break; + case 32: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + break; + default: + dev_err(sdev->dev, "invalid sample frame format %d\n", + params_format(pipeline_params)); + return -EINVAL; + } + + /* set the gateway dma_buffer_size using the matched ID returned above */ + copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; + + data = &ipc4_copier->copier_config; + ipc_config_size = &ipc4_copier->ipc_config_size; + ipc_config_data = &ipc4_copier->ipc_config_data; + + /* config_length is DWORD based */ + ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4; + + dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); + + *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); + if (!*ipc_config_data) + return -ENOMEM; + + *ipc_config_size = ipc_size; + + /* copy IPC data */ + memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); + if (copier_data->gtw_cfg.config_length) + memcpy(*ipc_config_data + sizeof(*copier_data), + *data, copier_data->gtw_cfg.config_length * 4); + + /* update pipeline memory usage */ + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); + + /* assign instance ID */ + return sof_ipc4_widget_assign_instance_id(sdev, swidget); +} + +static void sof_ipc4_unprepare_generic_module(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + + ida_free(&fw_module->m_ida, swidget->instance_id); +} + +static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_gain *gain = swidget->private; + int ret; + + gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt; + + /* output format is not required to be sent to the FW for gain */ + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, + NULL, pipeline_params, &gain->available_fmt, + sizeof(gain->base_config)); + if (ret < 0) + return ret; + + /* update pipeline memory usage */ + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); + + /* assign instance ID */ + return sof_ipc4_widget_assign_instance_id(sdev, swidget); +} + +static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_mixer *mixer = swidget->private; + int ret; + + /* only 32bit is supported by mixer */ + mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt; + + /* output format is not required to be sent to the FW for mixer */ + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, + NULL, pipeline_params, &mixer->available_fmt, + sizeof(mixer->base_config)); + if (ret < 0) + return ret; + + /* update pipeline memory usage */ + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); + + /* assign instance ID */ + return sof_ipc4_widget_assign_instance_id(sdev, swidget); +} + +static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + struct sof_ipc4_control_data *control_data; + struct sof_ipc4_msg *msg; + int i; + + scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); + + /* scontrol->ipc_control_data will be freed in sof_control_unload */ + scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->ipc_control_data) + return -ENOMEM; + + control_data = scontrol->ipc_control_data; + control_data->index = scontrol->index; + + msg = &control_data->msg; + msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); + msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); + + /* set default volume values to 0dB in control */ + for (i = 0; i < scontrol->num_channels; i++) { + control_data->chanv[i].channel = i; + control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; + } + + return 0; +} + +static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + switch (scontrol->info_type) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + return sof_ipc4_control_load_volume(sdev, scontrol); + default: + break; + } + + return 0; +} + +static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) +{ + struct snd_sof_widget *pipe_widget = swidget->pipe_widget; + struct sof_ipc4_pipeline *pipeline; + struct sof_ipc4_msg *msg; + void *ipc_data = NULL; + u32 ipc_size = 0; + int ret; + + dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", + swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); + + switch (swidget->id) { + case snd_soc_dapm_scheduler: + pipeline = swidget->private; + + dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, + pipeline->mem_usage); + + msg = &pipeline->msg; + msg->primary |= pipeline->mem_usage; + break; + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: + { + struct sof_ipc4_copier *ipc4_copier = swidget->private; + + ipc_size = ipc4_copier->ipc_config_size; + ipc_data = ipc4_copier->ipc_config_data; + + msg = &ipc4_copier->msg; + break; + } + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + { + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = dai->private; + + ipc_size = ipc4_copier->ipc_config_size; + ipc_data = ipc4_copier->ipc_config_data; + + msg = &ipc4_copier->msg; + break; + } + case snd_soc_dapm_pga: + { + struct sof_ipc4_gain *gain = swidget->private; + + ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + + sizeof(struct sof_ipc4_gain_data); + ipc_data = gain; + + msg = &gain->msg; + break; + } + case snd_soc_dapm_mixer: + { + struct sof_ipc4_mixer *mixer = swidget->private; + + ipc_size = sizeof(mixer->base_config); + ipc_data = &mixer->base_config; + + msg = &mixer->msg; + break; + } + default: + dev_err(sdev->dev, "widget type %d not supported", swidget->id); + return -EINVAL; + } + + if (swidget->id != snd_soc_dapm_scheduler) { + pipeline = pipe_widget->private; + msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; + msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); + + msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; + msg->extension |= ipc_size >> 2; + msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK; + msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode); + } + + msg->data_size = ipc_size; + msg->data_ptr = ipc_data; + + ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0); + if (ret < 0) + dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); + + return ret; +} + +static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) +{ + int ret = 0; + + /* freeing a pipeline frees all the widgets associated with it */ + if (swidget->id == snd_soc_dapm_scheduler) { + struct sof_ipc4_pipeline *pipeline = swidget->private; + struct sof_ipc4_msg msg = {{ 0 }}; + u32 header; + + header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id); + header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); + header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); + + msg.primary = header; + + ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); + if (ret < 0) + dev_err(sdev->dev, "failed to free pipeline widget %s\n", + swidget->widget->name); + + pipeline->mem_usage = 0; + pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; + } + + return ret; +} + +static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) +{ + struct snd_sof_widget *src_widget = sroute->src_widget; + struct snd_sof_widget *sink_widget = sroute->sink_widget; + struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; + struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; + struct sof_ipc4_msg msg = {{ 0 }}; + u32 header, extension; + int src_queue = 0; + int dst_queue = 0; + int ret; + + dev_dbg(sdev->dev, "bind %s -> %s\n", + src_widget->widget->name, sink_widget->widget->name); + + header = src_fw_module->man4_module_entry.id; + header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); + header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND); + header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + + extension = sink_fw_module->man4_module_entry.id; + extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); + extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue); + extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue); + + msg.primary = header; + msg.extension = extension; + + ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); + if (ret < 0) + dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n", + __func__, src_widget->widget->name, sink_widget->widget->name); + + return ret; +} + +static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) +{ + struct snd_sof_widget *src_widget = sroute->src_widget; + struct snd_sof_widget *sink_widget = sroute->sink_widget; + struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; + struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; + struct sof_ipc4_msg msg = {{ 0 }}; + u32 header, extension; + int src_queue = 0; + int dst_queue = 0; + int ret; + + dev_dbg(sdev->dev, "unbind modules %s -> %s\n", + src_widget->widget->name, sink_widget->widget->name); + + header = src_fw_module->man4_module_entry.id; + header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); + header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND); + header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + + extension = sink_fw_module->man4_module_entry.id; + extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); + extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue); + extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue); + + msg.primary = header; + msg.extension = extension; + + ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); + if (ret < 0) + dev_err(sdev->dev, "failed to unbind modules %s -> %s\n", + src_widget->widget->name, sink_widget->widget->name); + + return ret; +} + +static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, + unsigned int flags, struct snd_sof_dai_config_data *data) +{ + struct snd_sof_widget *pipe_widget = swidget->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_gtw_attributes *gtw_attr; + struct sof_ipc4_copier_data *copier_data; + struct sof_ipc4_copier *ipc4_copier; + + if (!dai || !dai->private) { + dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", + swidget->widget->name); + return -EINVAL; + } + + ipc4_copier = (struct sof_ipc4_copier *)dai->private; + copier_data = &ipc4_copier->data; + + if (!data) + return 0; + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_HDA: + gtw_attr = ipc4_copier->gtw_attr; + gtw_attr->lp_buffer_alloc = pipeline->lp_mode; + fallthrough; + case SOF_DAI_INTEL_ALH: + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; + copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); + break; + case SOF_DAI_INTEL_DMIC: + case SOF_DAI_INTEL_SSP: + /* nothing to do for SSP/DMIC */ + break; + default: + dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, + ipc4_copier->dai_type); + return -EINVAL; + } + + return 0; +} + +static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, + struct snd_soc_tplg_manifest *man) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_manifest_tlv *manifest_tlv; + struct sof_manifest *manifest; + u32 size = le32_to_cpu(man->priv.size); + u8 *man_ptr = man->priv.data; + u32 len_check; + int i; + + if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { + dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", + __func__, size); + return -EINVAL; + } + + manifest = (struct sof_manifest *)man_ptr; + + dev_info(scomp->dev, + "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n", + le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor), + le16_to_cpu(manifest->abi_patch), + SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); + + /* TODO: Add ABI compatibility check */ + + /* no more data after the ABI version */ + if (size <= SOF_IPC4_TPLG_ABI_SIZE) + return 0; + + manifest_tlv = manifest->items; + len_check = sizeof(struct sof_manifest); + for (i = 0; i < le16_to_cpu(manifest->count); i++) { + len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); + if (len_check > size) + return -EINVAL; + + switch (le32_to_cpu(manifest_tlv->type)) { + case SOF_MANIFEST_DATA_TYPE_NHLT: + /* no NHLT in BIOS, so use the one from topology manifest */ + if (ipc4_data->nhlt) + break; + ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data, + le32_to_cpu(manifest_tlv->size), GFP_KERNEL); + if (!ipc4_data->nhlt) + return -ENOMEM; + break; + default: + dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", + manifest_tlv->type); + break; + } + man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); + manifest_tlv = (struct sof_manifest_tlv *)man_ptr; + } + + return 0; +} + +static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) +{ + struct sof_ipc4_copier *ipc4_copier = dai->private; + struct snd_soc_tplg_hw_config *hw_config; + struct snd_sof_dai_link *slink; + bool dai_link_found = false; + bool hw_cfg_found = false; + int i; + + if (!ipc4_copier) + return 0; + + list_for_each_entry(slink, &sdev->dai_link_list, list) { + if (!strcmp(slink->link->name, dai->name)) { + dai_link_found = true; + break; + } + } + + if (!dai_link_found) { + dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name); + return -EINVAL; + } + + for (i = 0; i < slink->num_hw_configs; i++) { + hw_config = &slink->hw_configs[i]; + if (dai->current_config == le32_to_cpu(hw_config->id)) { + hw_cfg_found = true; + break; + } + } + + if (!hw_cfg_found) { + dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name); + return -EINVAL; + } + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_SSP: + switch (clk_type) { + case SOF_DAI_CLK_INTEL_SSP_MCLK: + return le32_to_cpu(hw_config->mclk_rate); + case SOF_DAI_CLK_INTEL_SSP_BCLK: + return le32_to_cpu(hw_config->bclk_rate); + default: + dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); + break; + } + break; + default: + dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type); + break; + } + + return -EINVAL; +} + +static enum sof_tokens host_token_list[] = { + SOF_COMP_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, + SOF_COPIER_GATEWAY_CFG_TOKENS, + SOF_COPIER_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + +static enum sof_tokens pipeline_token_list[] = { + SOF_SCHED_TOKENS, + SOF_PIPELINE_TOKENS, +}; + +static enum sof_tokens dai_token_list[] = { + SOF_COMP_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, + SOF_COPIER_GATEWAY_CFG_TOKENS, + SOF_COPIER_TOKENS, + SOF_DAI_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + +static enum sof_tokens pga_token_list[] = { + SOF_COMP_TOKENS, + SOF_GAIN_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + +static enum sof_tokens mixer_token_list[] = { + SOF_COMP_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + +static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { + [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, + host_token_list, ARRAY_SIZE(host_token_list), NULL, + sof_ipc4_prepare_copier_module, + sof_ipc4_unprepare_copier_module}, + [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, + host_token_list, ARRAY_SIZE(host_token_list), NULL, + sof_ipc4_prepare_copier_module, + sof_ipc4_unprepare_copier_module}, + [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, + dai_token_list, ARRAY_SIZE(dai_token_list), NULL, + sof_ipc4_prepare_copier_module, + sof_ipc4_unprepare_copier_module}, + [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, + dai_token_list, ARRAY_SIZE(dai_token_list), NULL, + sof_ipc4_prepare_copier_module, + sof_ipc4_unprepare_copier_module}, + [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp, + pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL, + NULL, NULL}, + [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp, + pga_token_list, ARRAY_SIZE(pga_token_list), NULL, + sof_ipc4_prepare_gain_module, + sof_ipc4_unprepare_generic_module}, + [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp, + mixer_token_list, ARRAY_SIZE(mixer_token_list), + NULL, sof_ipc4_prepare_mixer_module, + sof_ipc4_unprepare_generic_module}, +}; + +const struct sof_ipc_tplg_ops ipc4_tplg_ops = { + .widget = tplg_ipc4_widget_ops, + .token_list = ipc4_token_list, + .control_setup = sof_ipc4_control_setup, + .control = &tplg_ipc4_control_ops, + .widget_setup = sof_ipc4_widget_setup, + .widget_free = sof_ipc4_widget_free, + .route_setup = sof_ipc4_route_setup, + .route_free = sof_ipc4_route_free, + .dai_config = sof_ipc4_dai_config, + .parse_manifest = sof_ipc4_parse_manifest, + .dai_get_clk = sof_ipc4_dai_get_clk, +}; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h new file mode 100644 index 000000000000..3bc2fe38c733 --- /dev/null +++ b/sound/soc/sof/ipc4-topology.h @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2022 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__ +#define __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__ + +#include <sound/sof/ipc4/header.h> + +#define SOF_IPC4_FW_PAGE_SIZE BIT(12) +#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12) +#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1))) + +#define SOF_IPC4_MODULE_LL BIT(5) +#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12 +#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448 +#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128 +#define SOF_IPC4_LL_TASK_OBJECT_SIZE 72 +#define SOF_IPC4_DP_TASK_OBJECT_SIZE 104 +#define SOF_IPC4_DP_TASK_LIST_SIZE (12 + 8) +#define SOF_IPC4_LL_TASK_LIST_ITEM_SIZE 12 +#define SOF_IPC4_FW_MAX_PAGE_COUNT 20 +#define SOF_IPC4_FW_MAX_QUEUE_COUNT 8 + +/* Node index and mask applicable for host copier and ALH/HDA type DAI copiers */ +#define SOF_IPC4_NODE_INDEX_MASK 0xFF +#define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK) +#define SOF_IPC4_NODE_TYPE(x) ((x) << 8) + +/* Node ID for SSP type DAI copiers */ +#define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4) + +/* Node ID for DMIC type DAI copiers */ +#define SOF_IPC4_NODE_INDEX_INTEL_DMIC(x) (((x) & 0x7) << 5) + +#define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff +#define SOF_IPC4_VOL_ZERO_DB 0x7fffffff + +#define ALH_MAX_NUMBER_OF_GTW 16 + +/* + * The base of multi-gateways. Multi-gateways addressing starts from + * ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources + * and ALH_MULTI_GTW_COUNT multi-sinks available. + * Addressing is continuous from ALH_MULTI_GTW_BASE to + * ALH_MULTI_GTW_BASE + ALH_MULTI_GTW_COUNT - 1. + */ +#define ALH_MULTI_GTW_BASE 0x50 +/* A magic number from FW */ +#define ALH_MULTI_GTW_COUNT 8 + +/** + * struct sof_ipc4_pipeline - pipeline config data + * @priority: Priority of this pipeline + * @lp_mode: Low power mode + * @mem_usage: Memory usage + * @state: Pipeline state + * @msg: message structure for pipeline + */ +struct sof_ipc4_pipeline { + uint32_t priority; + uint32_t lp_mode; + uint32_t mem_usage; + int state; + struct sof_ipc4_msg msg; +}; + +/** + * struct sof_ipc4_available_audio_format - Available audio formats + * @base_config: Available base config + * @out_audio_fmt: Available output audio format + * @ref_audio_fmt: Reference audio format to match runtime audio format + * @dma_buffer_size: Available Gateway DMA buffer size (in bytes) + * @audio_fmt_num: Number of available audio formats + */ +struct sof_ipc4_available_audio_format { + struct sof_ipc4_base_module_cfg *base_config; + struct sof_ipc4_audio_format *out_audio_fmt; + struct sof_ipc4_audio_format *ref_audio_fmt; + u32 *dma_buffer_size; + int audio_fmt_num; +}; + +/** + * struct sof_copier_gateway_cfg - IPC gateway configuration + * @node_id: ID of Gateway Node + * @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes) + * @config_length: Length of gateway node configuration blob specified in #config_data + * config_data: Gateway node configuration blob + */ +struct sof_copier_gateway_cfg { + uint32_t node_id; + uint32_t dma_buffer_size; + uint32_t config_length; + uint32_t config_data[]; +}; + +/** + * struct sof_ipc4_copier_data - IPC data for copier + * @base_config: Base configuration including input audio format + * @out_format: Output audio format + * @copier_feature_mask: Copier feature mask + * @gtw_cfg: Gateway configuration + */ +struct sof_ipc4_copier_data { + struct sof_ipc4_base_module_cfg base_config; + struct sof_ipc4_audio_format out_format; + uint32_t copier_feature_mask; + struct sof_copier_gateway_cfg gtw_cfg; +}; + +/** + * struct sof_ipc4_gtw_attributes: Gateway attributes + * @lp_buffer_alloc: Gateway data requested in low power memory + * @alloc_from_reg_file: Gateway data requested in register file memory + * @rsvd: reserved for future use + */ +struct sof_ipc4_gtw_attributes { + uint32_t lp_buffer_alloc : 1; + uint32_t alloc_from_reg_file : 1; + uint32_t rsvd : 30; +}; + +/** struct sof_ipc4_alh_multi_gtw_cfg: ALH gateway cfg data + * @count: Number of streams (valid items in mapping array) + * @alh_id: ALH stream id of a single ALH stream aggregated + * @channel_mask: Channel mask + * @mapping: ALH streams + */ +struct sof_ipc4_alh_multi_gtw_cfg { + uint32_t count; + struct { + uint32_t alh_id; + uint32_t channel_mask; + } mapping[ALH_MAX_NUMBER_OF_GTW]; +} __packed; + +/** struct sof_ipc4_alh_configuration_blob: ALH blob + * @gw_attr: Gateway attributes + * @alh_cfg: ALH configuration data + */ +struct sof_ipc4_alh_configuration_blob { + struct sof_ipc4_gtw_attributes gw_attr; + struct sof_ipc4_alh_multi_gtw_cfg alh_cfg; +}; + +/** + * struct sof_ipc4_copier - copier config data + * @data: IPC copier data + * @copier_config: Copier + blob + * @ipc_config_size: Size of copier_config + * @available_fmt: Available audio format + * @frame_fmt: frame format + * @msg: message structure for copier + * @gtw_attr: Gateway attributes for copier blob + * @dai_type: DAI type + * @dai_index: DAI index + */ +struct sof_ipc4_copier { + struct sof_ipc4_copier_data data; + u32 *copier_config; + uint32_t ipc_config_size; + void *ipc_config_data; + struct sof_ipc4_available_audio_format available_fmt; + u32 frame_fmt; + struct sof_ipc4_msg msg; + struct sof_ipc4_gtw_attributes *gtw_attr; + u32 dai_type; + int dai_index; +}; + +/** + * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data + * @channel: Channel ID + * @value: gain value + */ +struct sof_ipc4_ctrl_value_chan { + u32 channel; + u32 value; +}; + +/** + * struct sof_ipc4_control_data - IPC data for kcontrol IO + * @msg: message structure for kcontrol IO + * @index: pipeline ID + * @chanv: channel ID and value array used by volume type controls + * @data: data for binary kcontrols + */ +struct sof_ipc4_control_data { + struct sof_ipc4_msg msg; + int index; + + union { + struct sof_ipc4_ctrl_value_chan chanv[0]; + struct sof_abi_hdr data[0]; + }; +}; + +/** + * struct sof_ipc4_gain_data - IPC gain blob + * @channels: Channels + * @init_val: Initial value + * @curve_type: Curve type + * @reserved: reserved for future use + * @curve_duration: Curve duration + */ +struct sof_ipc4_gain_data { + uint32_t channels; + uint32_t init_val; + uint32_t curve_type; + uint32_t reserved; + uint32_t curve_duration; +} __aligned(8); + +/** + * struct sof_ipc4_gain - gain config data + * @base_config: IPC base config data + * @data: IPC gain blob + * @available_fmt: Available audio format + * @msg: message structure for gain + */ +struct sof_ipc4_gain { + struct sof_ipc4_base_module_cfg base_config; + struct sof_ipc4_gain_data data; + struct sof_ipc4_available_audio_format available_fmt; + struct sof_ipc4_msg msg; +}; + +/** + * struct sof_ipc4_mixer - mixer config data + * @base_config: IPC base config data + * @available_fmt: Available audio format + * @msg: IPC4 message struct containing header and data info + */ +struct sof_ipc4_mixer { + struct sof_ipc4_base_module_cfg base_config; + struct sof_ipc4_available_audio_format available_fmt; + struct sof_ipc4_msg msg; +}; + +#endif diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 658802c86685..432b812bdf9c 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -574,7 +574,7 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) data_size = sizeof(struct sof_ipc4_notify_resource_data); break; default: - dev_dbg(sdev->dev, "%s: Unhandled DSP message: %#x|%#x\n", __func__, + dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n", ipc4_msg->primary, ipc4_msg->extension); break; } @@ -597,10 +597,53 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) } } +static int sof_ipc4_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on) +{ + struct sof_ipc4_dx_state_info dx_state; + struct sof_ipc4_msg msg; + + dx_state.core_mask = BIT(core_idx); + if (on) + dx_state.dx_mask = BIT(core_idx); + else + dx_state.dx_mask = 0; + + msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.extension = 0; + msg.data_ptr = &dx_state; + msg.data_size = sizeof(dx_state); + + return sof_ipc4_tx_msg(sdev, &msg, msg.data_size, NULL, 0, false); +} + +/* + * The context save callback is used to send a message to the firmware notifying + * it that the primary core is going to be turned off, which is used as an + * indication to prepare for a full power down, thus preparing for IMR boot + * (when supported) + * + * Note: in IPC4 there is no message used to restore context, thus no context + * restore callback is implemented + */ +static int sof_ipc4_ctx_save(struct snd_sof_dev *sdev) +{ + return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false); +} + +static const struct sof_ipc_pm_ops ipc4_pm_ops = { + .ctx_save = sof_ipc4_ctx_save, + .set_core_state = sof_ipc4_set_core_state, +}; + const struct sof_ipc_ops ipc4_ops = { .tx_msg = sof_ipc4_tx_msg, .rx_msg = sof_ipc4_rx_msg, .set_get_data = sof_ipc4_set_get_data, .get_reply = sof_ipc4_get_reply, + .pm = &ipc4_pm_ops, .fw_loader = &ipc4_loader_ops, + .tplg = &ipc4_tplg_ops, + .pcm = &ipc4_pcm_ops, }; diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig index a149dd1b3f44..4a2eddf6009a 100644 --- a/sound/soc/sof/mediatek/Kconfig +++ b/sound/soc/sof/mediatek/Kconfig @@ -15,6 +15,7 @@ config SND_SOC_SOF_MTK_COMMON tristate select SND_SOC_SOF_OF_DEV select SND_SOC_SOF + select SND_SOC_SOF_IPC3 select SND_SOC_SOF_XTENSA select SND_SOC_SOF_COMPRESS help diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index 4ab998756bbc..d41e904e6614 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -20,6 +20,7 @@ struct mtk_adsp_chip_info { u32 sramsize; u32 dramsize; u32 cfgregsize; + u32 shared_size; void __iomem *va_sram; /* corresponding to pa_sram */ void __iomem *va_dram; /* corresponding to pa_dram */ void __iomem *va_cfgreg; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c index 6bcb4b9b00fb..9ef08e43aa38 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c @@ -132,6 +132,13 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable) return ret; } + ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_H], + priv->clk[CLK_TOP_CLK26M]); + if (ret) { + dev_err(dev, "set audio_h_sel failed %d\n", ret); + return ret; + } + ret = adsp_enable_all_clock(sdev); if (ret) { dev_err(dev, "failed to adsp_enable_clock: %d\n", ret); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 30111ab23bf5..9c146015cd1b 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -145,6 +145,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) dev_dbg(dev, "DMA %pR\n", &res); + adsp->pa_shared_dram = (phys_addr_t)res.start; + adsp->shared_size = resource_size(&res); + if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_shared_dram); + return -EINVAL; + } + ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -273,23 +281,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) { struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; - u32 shared_size; /* remap shared-dram base to be non-cachable */ - shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; - adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; - if (adsp->va_dram) { - adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; - } else { - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "ioremap failed for shared DRAM\n"); - return -ENOMEM; - } + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + adsp->shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "failed to ioremap base %pa size %#x\n", + adsp->shared_dram, adsp->shared_size); + return -ENOMEM; } + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, shared_size); + adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); return 0; } @@ -361,9 +364,11 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) goto err_adsp_sram_power_off; } - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, - priv->adsp->pa_dram, - priv->adsp->dramsize); + priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM]; + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", &priv->adsp->pa_dram, priv->adsp->dramsize); @@ -438,6 +443,19 @@ static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) { struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); int ret; + u32 reset_sw, dbg_pc; + + /* wait dsp enter idle, timeout is 1 second */ + ret = snd_sof_dsp_read_poll_timeout(sdev, DSP_REG_BAR, + DSP_RESET_SW, reset_sw, + ((reset_sw & ADSP_PWAIT) == ADSP_PWAIT), + SUSPEND_DSP_IDLE_POLL_INTERVAL_US, + SUSPEND_DSP_IDLE_TIMEOUT_US); + if (ret < 0) { + dbg_pc = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGPC); + dev_warn(sdev->dev, "dsp not idle, powering off anyway : swrest %#x, pc %#x, ret %d\n", + reset_sw, dbg_pc, ret); + } /* stall and reset dsp */ sof_hifixdsp_shutdown(sdev); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h index 929424182357..7ffd523f936c 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.h +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -34,6 +34,7 @@ struct snd_sof_dev; #define ADSP_DRESET_SW BIT(1) #define ADSP_RUNSTALL BIT(3) #define STATVECTOR_SEL BIT(4) +#define ADSP_PWAIT BIT(16) #define DSP_PFAULTBUS 0x0028 #define DSP_PFAULTINFO 0x002c #define DSP_GPR00 0x0030 @@ -153,6 +154,10 @@ struct snd_sof_dev; #define DRAM_REMAP_SHIFT 12 #define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1) +/* suspend dsp idle check interval and timeout */ +#define SUSPEND_DSP_IDLE_TIMEOUT_US 1000000 /* timeout to wait dsp idle, 1 sec */ +#define SUSPEND_DSP_IDLE_POLL_INTERVAL_US 500 /* 0.5 msec */ + void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr); void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev); #endif diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b79ae4f66eba..55d43adb6a29 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -29,6 +29,12 @@ static inline int sof_ops_init(struct snd_sof_dev *sdev) return 0; } +static inline void sof_ops_free(struct snd_sof_dev *sdev) +{ + if (sdev->pdata->desc->ops_free) + sdev->pdata->desc->ops_free(sdev); +} + /* Mandatory operations are verified during probing */ /* init */ diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a76d0b5b2ad9..27504abc5385 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -604,6 +604,14 @@ static int sof_pcm_probe(struct snd_soc_component *component) const char *tplg_filename; int ret; + /* + * make sure the device is pm_runtime_active before loading the + * topology and initiating IPC or bus transactions + */ + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + /* load the default topology */ sdev->component = component; @@ -621,6 +629,9 @@ static int sof_pcm_probe(struct snd_soc_component *component) return ret; } + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 27cc5fb642e5..4284ea2f3a1f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -168,6 +168,7 @@ struct sof_ipc_tplg_widget_ops { * @dai_get_clk: Function pointer for getting the DAI clock setting * @set_up_all_pipelines: Function pointer for setting up all topology pipelines * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines + * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest */ struct sof_ipc_tplg_ops { const struct sof_ipc_tplg_widget_ops *widget; @@ -185,6 +186,8 @@ struct sof_ipc_tplg_ops { int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type); int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify); int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify); + int (*parse_manifest)(struct snd_soc_component *scomp, int index, + struct snd_soc_tplg_manifest *man); }; /** struct snd_sof_tuple - Tuple info @@ -225,6 +228,15 @@ enum sof_tokens { SOF_AFE_TOKENS, SOF_CORE_TOKENS, SOF_COMP_EXT_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_COPIER_GATEWAY_CFG_TOKENS, + SOF_COPIER_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_COPIER_FORMAT_TOKENS, + SOF_GAIN_TOKENS, + SOF_ACPDMIC_TOKENS, /* this should be the last */ SOF_TOKEN_COUNT, diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 16cca666bb85..125aa2137195 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -383,8 +383,8 @@ void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary); } else { - dev_dbg_once(sdev->dev, "%s: Not supported IPC version: %d\n", - __func__, sdev->pdata->ipc_type); + dev_dbg_once(sdev->dev, "Not supported IPC version: %d\n", + sdev->pdata->ipc_type); return; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f0f3d72c0da7..8bbc94907c62 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -37,6 +37,12 @@ #define SOF_DBG_IGNORE_D3_PERSISTENT BIT(7) /* ignore the DSP D3 persistent capability * and always download firmware upon D3 exit */ +#define SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS BIT(8) /* print DMA position updates + * in dmesg logs + */ +#define SOF_DBG_PRINT_IPC_SUCCESS_LOGS BIT(9) /* print IPC success + * in dmesg logs + */ /* Flag definitions used for controlling the DSP dump behavior */ #define SOF_DBG_DUMP_REGS BIT(0) @@ -378,12 +384,14 @@ struct sof_ipc_fw_tracing_ops { /** * struct sof_ipc_pm_ops - IPC-specific PM ops - * @ctx_save: Function pointer for context save - * @ctx_restore: Function pointer for context restore + * @ctx_save: Optional function pointer for context save + * @ctx_restore: Optional function pointer for context restore + * @set_core_state: Optional function pointer for turning on/off a DSP core */ struct sof_ipc_pm_ops { int (*ctx_save)(struct snd_sof_dev *sdev); int (*ctx_restore)(struct snd_sof_dev *sdev); + int (*set_core_state)(struct snd_sof_dev *sdev, int core_idx, bool on); }; /** @@ -657,7 +665,7 @@ void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level, u32 panic_code, u32 tracep_code, void *oops, struct sof_ipc_panic_info *panic_info, void *stack, size_t stack_words); -void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg); int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev); int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, u32 offset, size_t size, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b1fcab7ce48e..7e54eb1bf77b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -36,9 +36,6 @@ #define TLV_STEP 1 #define TLV_MUTE 2 -/* size of tplg abi in byte */ -#define SOF_TPLG_ABI_SIZE 3 - /** * sof_update_ipc_object - Parse multiple sets of tokens within the token array associated with the * token ID. @@ -1141,6 +1138,21 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, return 0; } +static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples) +{ + int i; + + if (!tuples) + return -EINVAL; + + for (i = 0; i < num_tuples; i++) { + if (tuples[i].token == token_id) + return tuples[i].value.v; + } + + return -EINVAL; +} + static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_sof_widget *swidget, struct snd_soc_tplg_dapm_widget *tw, enum sof_tokens *object_token_list, int count) @@ -1168,6 +1180,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s /* parse token list for widget */ for (i = 0; i < count; i++) { + int num_sets = 1; + if (object_token_list[i] >= SOF_TOKEN_COUNT) { dev_err(scomp->dev, "Invalid token id %d for widget %s\n", object_token_list[i], swidget->widget->name); @@ -1175,8 +1189,9 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s goto err; } - /* parse and save UUID in swidget */ - if (object_token_list[i] == SOF_COMP_EXT_TOKENS) { + switch (object_token_list[i]) { + case SOF_COMP_EXT_TOKENS: + /* parse and save UUID in swidget */ ret = sof_parse_tokens(scomp, swidget, token_list[object_token_list[i]].tokens, token_list[object_token_list[i]].count, @@ -1189,11 +1204,41 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s } continue; + case SOF_IN_AUDIO_FORMAT_TOKENS: + case SOF_OUT_AUDIO_FORMAT_TOKENS: + case SOF_COPIER_GATEWAY_CFG_TOKENS: + case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS: + num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS, + swidget->tuples, swidget->num_tuples); + + if (num_sets < 0) { + dev_err(sdev->dev, "Invalid audio format count for %s\n", + swidget->widget->name); + ret = num_sets; + goto err; + } + + if (num_sets > 1) { + struct snd_sof_tuple *new_tuples; + + num_tuples += token_list[object_token_list[i]].count * num_sets; + new_tuples = krealloc(swidget->tuples, + sizeof(*new_tuples) * num_tuples, GFP_KERNEL); + if (!new_tuples) { + ret = -ENOMEM; + goto err; + } + + swidget->tuples = new_tuples; + } + break; + default: + break; } /* copy one set of tuples per token ID into swidget->tuples */ ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), - object_token_list[i], 1, swidget->tuples, + object_token_list[i], num_sets, swidget->tuples, num_tuples, &swidget->num_tuples); if (ret < 0) { dev_err(scomp->dev, "Failed parsing %s for widget %s err: %d\n", @@ -1208,21 +1253,6 @@ err: return ret; } -static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples) -{ - int i; - - if (!tuples) - return -EINVAL; - - for (i = 0; i < num_tuples; i++) { - if (tuples[i].token == token_id) - return tuples[i].value.v; - } - - return -EINVAL; -} - /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -1709,6 +1739,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ token_id = SOF_AFE_TOKENS; num_tuples += token_list[SOF_AFE_TOKENS].count; break; + case SOF_DAI_AMD_DMIC: + token_id = SOF_ACPDMIC_TOKENS; + num_tuples += token_list[SOF_ACPDMIC_TOKENS].count; + break; default: break; } @@ -1987,45 +2021,11 @@ static int sof_complete(struct snd_soc_component *scomp) static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { - u32 size; - u32 abi_version; - - size = le32_to_cpu(man->priv.size); - - /* backward compatible with tplg without ABI info */ - if (!size) { - dev_dbg(scomp->dev, "No topology ABI info\n"); - return 0; - } - - if (size != SOF_TPLG_ABI_SIZE) { - dev_err(scomp->dev, "error: invalid topology ABI size\n"); - return -EINVAL; - } - - dev_info(scomp->dev, - "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", - man->priv.data[0], man->priv.data[1], - man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR, - SOF_ABI_PATCH); - - abi_version = SOF_ABI_VER(man->priv.data[0], - man->priv.data[1], - man->priv.data[2]); - - if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) { - dev_err(scomp->dev, "error: incompatible topology ABI version\n"); - return -EINVAL; - } + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) { - if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) { - dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n"); - } else { - dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n"); - return -EINVAL; - } - } + if (ipc_tplg_ops->parse_manifest) + return ipc_tplg_ops->parse_manifest(scomp, index, man); return 0; } diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 6ee714542b84..122805160e70 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -296,7 +296,7 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_component *component, static int stm32_adfsdm_dummy_cb(const void *data, void *private) { /* - * This dummmy callback is requested by iio_channel_get_all_cb() API, + * This dummy callback is requested by iio_channel_get_all_cb() API, * but the stm32_dfsdm_get_buff_cb() API is used instead, to optimize * DMA transfers. */ diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index ac5dff4d1677..32d885f84a92 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -593,16 +593,16 @@ static int stm32_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: i2s->ms_flg = I2S_MS_SLAVE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: i2s->ms_flg = I2S_MS_MASTER; break; default: dev_err(cpu_dai->dev, "Unsupported mode %#x\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); + fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index dd636af81c9b..03cc6d12d18b 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -45,8 +45,6 @@ #define STM_SAI_B_ID 0x1 #define STM_SAI_IS_SUB_A(x) ((x)->id == STM_SAI_A_ID) -#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID) -#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B") #define SAI_SYNC_NONE 0x0 #define SAI_SYNC_INTERNAL 0x1 @@ -719,18 +717,18 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr); /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: /* codec is master */ cr1 |= SAI_XCR1_SLAVE; sai->master = false; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: sai->master = true; break; default: dev_err(cpu_dai->dev, "Unsupported mode %#x\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); + fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 60712f24ade5..53e3f43816cc 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -250,37 +250,33 @@ struct sun4i_codec { static void sun4i_codec_start_playback(struct sun4i_codec *scodec) { /* Flush TX FIFO */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH), - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); + regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); /* Enable DAC DRQ */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN), - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); + regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); } static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) { /* Disable DAC DRQ */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN), - 0); + regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); } static void sun4i_codec_start_capture(struct sun4i_codec *scodec) { /* Enable ADC DRQ */ - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); + regmap_field_set_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); } static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) { /* Disable ADC DRQ */ - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); + regmap_field_clear_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); } static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, @@ -323,8 +319,7 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, /* Flush RX FIFO */ - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), + regmap_field_set_bits(scodec->reg_adc_fifoc, BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); @@ -365,8 +360,7 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, u32 val; /* Flush the TX FIFO */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH), + regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); /* Set TX FIFO Empty Trigger Level */ @@ -386,9 +380,8 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, val); /* Send zeros when we have an underrun */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT), - 0); + regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, + BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); return 0; }; @@ -485,33 +478,27 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, /* Set the number of channels we want to use */ if (params_channels(params) == 1) - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + regmap_field_set_bits(scodec->reg_adc_fifoc, BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); else - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), - 0); + regmap_field_clear_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); /* Set the number of sample bits to either 16 or 24 bits */ if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS), + regmap_field_set_bits(scodec->reg_adc_fifoc, BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS)); - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), - 0); + regmap_field_clear_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; } else { - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS), - 0); + regmap_field_clear_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS)); /* Fill most significant bits with valid data MSB */ - regmap_field_update_bits(scodec->reg_adc_fifoc, - BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), + regmap_field_set_bits(scodec->reg_adc_fifoc, BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; @@ -543,24 +530,20 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, /* Set the number of sample bits to either 16 or 24 bits */ if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS), + regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); /* Set TX FIFO mode to padding the LSBs with 0 */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE), - 0); + regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; } else { - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS), - 0); + regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); /* Set TX FIFO mode to repeat the MSB */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE), + regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; @@ -624,8 +607,7 @@ static int sun4i_codec_startup(struct snd_pcm_substream *substream, * Stop issuing DRQ when we have room for less than 16 samples * in our TX FIFO */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT, + regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); return clk_prepare_enable(scodec->clk_module); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 7047f71629ab..5be33d07361b 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -161,6 +161,8 @@ struct sun4i_i2s; * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. + * @num_din_pins: input pins + * @num_dout_pins: output pins (currently set but unused) * @bclk_dividers: bit clock dividers array * @num_bclk_dividers: number of bit clock dividers * @mclk_dividers: mclk dividers array @@ -702,13 +704,13 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN4I_I2S_FMT0_FMT_MASK, val); /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* BCLK and LRCLK master */ val = SUN4I_I2S_CTRL_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* BCLK and LRCLK slave */ val = SUN4I_I2S_CTRL_MODE_SLAVE; break; @@ -802,13 +804,13 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN8I_I2S_TX_CHAN_OFFSET(offset)); /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* BCLK and LRCLK master */ val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* BCLK and LRCLK slave */ val = 0; break; @@ -909,13 +911,13 @@ static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* BCLK and LRCLK master */ val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* BCLK and LRCLK slave */ val = 0; break; diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 0bea2162f68d..f797c535f298 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -286,11 +286,11 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) u32 dsp_format, format, invert, value; /* clock masters */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */ value = 0x1; break; - case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */ + case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */ value = 0x0; break; default: diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 2482d9867357..b6712a3d1fa1 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -85,6 +85,15 @@ config SND_SOC_TEGRA210_I2S compatible devices. Say Y or M if you want to add support for Tegra210 I2S module. +config SND_SOC_TEGRA210_OPE + tristate "Tegra210 OPE module" + help + Config to enable the Output Processing Engine (OPE) which includes + Parametric Equalizer (PEQ) and Multi Band Dynamic Range Compressor + (MBDRC) sub blocks for data processing. It can support up to 8 + channels. + Say Y or M if you want to add support for Tegra210 OPE module. + config SND_SOC_TEGRA186_ASRC tristate "Tegra186 ASRC module" help diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 70a498ddb2fa..b723c78e665d 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -19,6 +19,7 @@ snd-soc-tegra210-sfc-objs := tegra210_sfc.o snd-soc-tegra210-amx-objs := tegra210_amx.o snd-soc-tegra210-adx-objs := tegra210_adx.o snd-soc-tegra210-mixer-objs := tegra210_mixer.o +snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o +obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o # Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 27365a877e47..2e1a726602f0 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -95,11 +95,11 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, } mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: val |= TEGRA20_I2S_CTRL_MASTER_ENABLE; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index e1f90daea7a1..b38d205b69cc 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -170,6 +170,11 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = { DAI(MIXER1 TX3), DAI(MIXER1 TX4), DAI(MIXER1 TX5), + /* XBAR -> OPE -> XBAR */ + DAI(OPE1 RX), + DAI(OPE1 TX), + DAI(OPE2 RX), + DAI(OPE2 TX), }; static struct snd_soc_dai_driver tegra186_ahub_dais[] = { @@ -294,6 +299,9 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = { DAI(ASRC1 RX6), DAI(ASRC1 TX6), DAI(ASRC1 RX7), + /* XBAR -> OPE -> XBAR */ + DAI(OPE1 RX), + DAI(OPE1 TX), }; static const char * const tegra210_ahub_mux_texts[] = { @@ -337,6 +345,8 @@ static const char * const tegra210_ahub_mux_texts[] = { "MIXER1 TX3", "MIXER1 TX4", "MIXER1 TX5", + "OPE1", + "OPE2", }; static const char * const tegra186_ahub_mux_texts[] = { @@ -408,6 +418,7 @@ static const char * const tegra186_ahub_mux_texts[] = { "ASRC1 TX4", "ASRC1 TX5", "ASRC1 TX6", + "OPE1", }; static const unsigned int tegra210_ahub_mux_values[] = { @@ -459,6 +470,9 @@ static const unsigned int tegra210_ahub_mux_values[] = { MUX_VALUE(1, 2), MUX_VALUE(1, 3), MUX_VALUE(1, 4), + /* OPE */ + MUX_VALUE(2, 0), + MUX_VALUE(2, 1), }; static const unsigned int tegra186_ahub_mux_values[] = { @@ -540,6 +554,8 @@ static const unsigned int tegra186_ahub_mux_values[] = { MUX_VALUE(3, 27), MUX_VALUE(3, 28), MUX_VALUE(3, 29), + /* OPE */ + MUX_VALUE(2, 0), }; /* Controls for t210 */ @@ -584,6 +600,8 @@ MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26); MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27); MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28); MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29); +MUX_ENUM_CTRL_DECL(t210_ope1_tx, 0x40); +MUX_ENUM_CTRL_DECL(t210_ope2_tx, 0x41); /* Controls for t186 */ MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00); @@ -657,6 +675,7 @@ MUX_ENUM_CTRL_DECL_186(t186_asrc14_tx, 0x6f); MUX_ENUM_CTRL_DECL_186(t186_asrc15_tx, 0x70); MUX_ENUM_CTRL_DECL_186(t186_asrc16_tx, 0x71); MUX_ENUM_CTRL_DECL_186(t186_asrc17_tx, 0x72); +MUX_ENUM_CTRL_DECL_186(t186_ope1_tx, 0x40); /* Controls for t234 */ MUX_ENUM_CTRL_DECL_234(t234_mvc1_tx, 0x44); @@ -758,6 +777,8 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = { TX_WIDGETS("MIXER1 TX3"), TX_WIDGETS("MIXER1 TX4"), TX_WIDGETS("MIXER1 TX5"), + WIDGETS("OPE1", t210_ope1_tx), + WIDGETS("OPE2", t210_ope2_tx), }; static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { @@ -867,6 +888,7 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { TX_WIDGETS("ASRC1 TX4"), TX_WIDGETS("ASRC1 TX5"), TX_WIDGETS("ASRC1 TX6"), + WIDGETS("OPE1", t186_ope1_tx), }; static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = { @@ -976,6 +998,7 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = { TX_WIDGETS("ASRC1 TX4"), TX_WIDGETS("ASRC1 TX5"), TX_WIDGETS("ASRC1 TX6"), + WIDGETS("OPE1", t186_ope1_tx), }; #define TEGRA_COMMON_MUX_ROUTES(name) \ @@ -1018,7 +1041,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = { { name " Mux", "MIXER1 TX2", "MIXER1 TX2 XBAR-RX" }, \ { name " Mux", "MIXER1 TX3", "MIXER1 TX3 XBAR-RX" }, \ { name " Mux", "MIXER1 TX4", "MIXER1 TX4 XBAR-RX" }, \ - { name " Mux", "MIXER1 TX5", "MIXER1 TX5 XBAR-RX" }, + { name " Mux", "MIXER1 TX5", "MIXER1 TX5 XBAR-RX" }, \ + { name " Mux", "OPE1", "OPE1 XBAR-RX" }, + +#define TEGRA210_ONLY_MUX_ROUTES(name) \ + { name " Mux", "OPE2", "OPE2 XBAR-RX" }, #define TEGRA186_ONLY_MUX_ROUTES(name) \ { name " Mux", "ADMAIF11", "ADMAIF11 XBAR-RX" }, \ @@ -1050,10 +1077,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = { { name " Mux", "ASRC1 TX5", "ASRC1 TX5 XBAR-RX" }, \ { name " Mux", "ASRC1 TX6", "ASRC1 TX6 XBAR-RX" }, -#define TEGRA210_MUX_ROUTES(name) \ - TEGRA_COMMON_MUX_ROUTES(name) +#define TEGRA210_MUX_ROUTES(name) \ + TEGRA_COMMON_MUX_ROUTES(name) \ + TEGRA210_ONLY_MUX_ROUTES(name) -#define TEGRA186_MUX_ROUTES(name) \ +#define TEGRA186_MUX_ROUTES(name) \ TEGRA_COMMON_MUX_ROUTES(name) \ TEGRA186_ONLY_MUX_ROUTES(name) @@ -1121,6 +1149,8 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = { TEGRA210_MUX_ROUTES("MIXER1 RX8") TEGRA210_MUX_ROUTES("MIXER1 RX9") TEGRA210_MUX_ROUTES("MIXER1 RX10") + TEGRA210_MUX_ROUTES("OPE1") + TEGRA210_MUX_ROUTES("OPE2") }; static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { @@ -1215,6 +1245,7 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { TEGRA186_MUX_ROUTES("ASRC1 RX5") TEGRA186_MUX_ROUTES("ASRC1 RX6") TEGRA186_MUX_ROUTES("ASRC1 RX7") + TEGRA186_MUX_ROUTES("OPE1") }; static const struct snd_soc_component_driver tegra210_ahub_component = { diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index 9552bbb939dd..01c76ba36e1a 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -214,11 +214,11 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int mask, val; mask = I2S_CTRL_MASTER_EN_MASK; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: val = 0; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BP_FP: val = I2S_CTRL_MASTER_EN; break; default: diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c new file mode 100644 index 000000000000..d786daa6aba6 --- /dev/null +++ b/sound/soc/tegra/tegra210_mbdrc.c @@ -0,0 +1,1014 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_mbdrc.c - Tegra210 MBDRC driver +// +// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "tegra210_mbdrc.h" +#include "tegra210_ope.h" + +#define MBDRC_FILTER_REG(reg, id) \ + ((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE)) + +#define MBDRC_FILTER_REG_DEFAULTS(id) \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a}, \ + { MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000} + +static const struct reg_default tegra210_mbdrc_reg_defaults[] = { + { TEGRA210_MBDRC_CFG, 0x0030de51}, + { TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003}, + { TEGRA210_MBDRC_FAST_FACTOR, 0x30000800}, + + MBDRC_FILTER_REG_DEFAULTS(0), + MBDRC_FILTER_REG_DEFAULTS(1), + MBDRC_FILTER_REG_DEFAULTS(2), +}; + +/* Default MBDRC parameters */ +static const struct tegra210_mbdrc_config mbdrc_init_config = { + .mode = 0, /* Bypass */ + .rms_off = 48, + .peak_rms_mode = 1, /* PEAK */ + .fliter_structure = 0, /* All-pass tree */ + .shift_ctrl = 30, + .frame_size = 32, + .channel_mask = 0x3, + .fa_factor = 2048, + .fr_factor = 14747, + + .band_params[MBDRC_LOW_BAND] = { + .band = MBDRC_LOW_BAND, + .iir_stages = 5, + .in_attack_tc = 1044928780, + .in_release_tc = 138497695, + .fast_attack_tc = 2147483647, + .in_threshold = {130, 80, 20, 6}, + .out_threshold = {155, 55, 13, 6}, + .ratio = {40960, 8192, 2867, 2048, 410}, + .makeup_gain = 4, + .gain_init = 419430, + .gain_attack_tc = 14268942, + .gain_release_tc = 1440547090, + .fast_release_tc = 2147480170, + + .biquad_params = { + /* + * Gains: + * + * b0, b1, a0, + * a1, a2, + */ + + /* Band-0 */ + 961046798, -2030431983, 1073741824, + 2030431983, -961046798, + /* Band-1 */ + 1030244425, -2099481453, 1073741824, + 2099481453, -1030244425, + /* Band-2 */ + 1067169294, -2136327263, 1073741824, + 2136327263, -1067169294, + /* Band-3 */ + 434951949, -1306567134, 1073741824, + 1306567134, -434951949, + /* Band-4 */ + 780656019, -1605955641, 1073741824, + 1605955641, -780656019, + /* Band-5 */ + 1024497031, -1817128152, 1073741824, + 1817128152, -1024497031, + /* Band-6 */ + 1073741824, 0, 0, + 0, 0, + /* Band-7 */ + 1073741824, 0, 0, + 0, 0, + } + }, + + .band_params[MBDRC_MID_BAND] = { + .band = MBDRC_MID_BAND, + .iir_stages = 5, + .in_attack_tc = 1581413104, + .in_release_tc = 35494783, + .fast_attack_tc = 2147483647, + .in_threshold = {130, 50, 30, 6}, + .out_threshold = {106, 50, 30, 13}, + .ratio = {40960, 2867, 4096, 2867, 410}, + .makeup_gain = 6, + .gain_init = 419430, + .gain_attack_tc = 4766887, + .gain_release_tc = 1044928780, + .fast_release_tc = 2147480170, + + .biquad_params = { + /* + * Gains: + * + * b0, b1, a0, + * a1, a2, + */ + + /* Band-0 */ + -1005668963, 1073741824, 0, + 1005668963, 0, + /* Band-1 */ + 998437058, -2067742187, 1073741824, + 2067742187, -998437058, + /* Band-2 */ + 1051963422, -2121153948, 1073741824, + 2121153948, -1051963422, + /* Band-3 */ + 434951949, -1306567134, 1073741824, + 1306567134, -434951949, + /* Band-4 */ + 780656019, -1605955641, 1073741824, + 1605955641, -780656019, + /* Band-5 */ + 1024497031, -1817128152, 1073741824, + 1817128152, -1024497031, + /* Band-6 */ + 1073741824, 0, 0, + 0, 0, + /* Band-7 */ + 1073741824, 0, 0, + 0, 0, + } + }, + + .band_params[MBDRC_HIGH_BAND] = { + .band = MBDRC_HIGH_BAND, + .iir_stages = 5, + .in_attack_tc = 2144750688, + .in_release_tc = 70402888, + .fast_attack_tc = 2147483647, + .in_threshold = {130, 50, 30, 6}, + .out_threshold = {106, 50, 30, 13}, + .ratio = {40960, 2867, 4096, 2867, 410}, + .makeup_gain = 6, + .gain_init = 419430, + .gain_attack_tc = 4766887, + .gain_release_tc = 1044928780, + .fast_release_tc = 2147480170, + + .biquad_params = { + /* + * Gains: + * + * b0, b1, a0, + * a1, a2, + */ + + /* Band-0 */ + 1073741824, 0, 0, + 0, 0, + /* Band-1 */ + 1073741824, 0, 0, + 0, 0, + /* Band-2 */ + 1073741824, 0, 0, + 0, 0, + /* Band-3 */ + -619925131, 1073741824, 0, + 619925131, 0, + /* Band-4 */ + 606839335, -1455425976, 1073741824, + 1455425976, -606839335, + /* Band-5 */ + 917759617, -1724690840, 1073741824, + 1724690840, -917759617, + /* Band-6 */ + 1073741824, 0, 0, + 0, 0, + /* Band-7 */ + 1073741824, 0, 0, + 0, 0, + } + } +}; + +static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl, + unsigned int reg_data, unsigned int ram_offset, + unsigned int *data, size_t size) +{ + unsigned int val; + unsigned int i; + + val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK; + val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN; + val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN; + val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE; + + regmap_write(regmap, reg_ctrl, val); + + for (i = 0; i < size; i++) + regmap_write(regmap, reg_data, data[i]); +} + +static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + unsigned int val; + + regmap_read(ope->mbdrc_regmap, mc->reg, &val); + + ucontrol->value.integer.value[0] = (val >> mc->shift) & mc->max; + + return 0; +} + +static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + unsigned int val = ucontrol->value.integer.value[0]; + bool change = false; + + val = val << mc->shift; + + regmap_update_bits_check(ope->mbdrc_regmap, mc->reg, + (mc->max << mc->shift), val, &change); + + return change ? 1 : 0; +} + +static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + + regmap_read(ope->mbdrc_regmap, e->reg, &val); + + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; + + return 0; +} + +static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + bool change = false; + unsigned int val; + unsigned int mask; + + if (ucontrol->value.enumerated.item[0] > e->items - 1) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = e->mask << e->shift_l; + + regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val, + &change); + + return change ? 1 : 0; +} + +static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 *data = (u32 *)ucontrol->value.bytes.data; + u32 regs = params->soc.base; + u32 mask = params->soc.mask; + u32 shift = params->shift; + unsigned int i; + + for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) { + regmap_read(ope->mbdrc_regmap, regs, &data[i]); + + data[i] = ((data[i] & mask) >> shift); + } + + return 0; +} + +static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 *data = (u32 *)ucontrol->value.bytes.data; + u32 regs = params->soc.base; + u32 mask = params->soc.mask; + u32 shift = params->shift; + bool change = false; + unsigned int i; + + for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) { + bool update = false; + + regmap_update_bits_check(ope->mbdrc_regmap, regs, mask, + data[i] << shift, &update); + + change |= update; + } + + return change ? 1 : 0; +} + +static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 *data = (u32 *)ucontrol->value.bytes.data; + u32 regs = params->soc.base; + u32 num_regs = params->soc.num_regs; + u32 val; + unsigned int i; + + for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) { + regmap_read(ope->mbdrc_regmap, regs, &val); + + data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >> + TEGRA210_MBDRC_THRESH_1ST_SHIFT; + data[i + 1] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >> + TEGRA210_MBDRC_THRESH_2ND_SHIFT; + data[i + 2] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >> + TEGRA210_MBDRC_THRESH_3RD_SHIFT; + data[i + 3] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >> + TEGRA210_MBDRC_THRESH_4TH_SHIFT; + } + + return 0; +} + +static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 *data = (u32 *)ucontrol->value.bytes.data; + u32 regs = params->soc.base; + u32 num_regs = params->soc.num_regs; + bool change = false; + unsigned int i; + + for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) { + bool update = false; + + data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) & + TEGRA210_MBDRC_THRESH_1ST_MASK) | + ((data[i + 1] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) & + TEGRA210_MBDRC_THRESH_2ND_MASK) | + ((data[i + 2] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) & + TEGRA210_MBDRC_THRESH_3RD_MASK) | + ((data[i + 3] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) & + TEGRA210_MBDRC_THRESH_4TH_MASK)); + + regmap_update_bits_check(ope->mbdrc_regmap, regs, 0xffffffff, + data[i], &update); + + change |= update; + } + + return change ? 1 : 0; +} + +static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + u32 *data = (u32 *)ucontrol->value.bytes.data; + + memset(data, 0, params->soc.num_regs * cmpnt->val_bytes); + + return 0; +} + +static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 reg_ctrl = params->soc.base; + u32 reg_data = reg_ctrl + cmpnt->val_bytes; + u32 *data = (u32 *)ucontrol->value.bytes.data; + + tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data, + params->shift, data, params->soc.num_regs); + + return 1; +} + +static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = params->num_regs * sizeof(u32); + + return 0; +} + +static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + int val; + + regmap_read(ope->mbdrc_regmap, mc->reg, &val); + + ucontrol->value.integer.value[0] = + ((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN); + + return 0; +} + +static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + int val = ucontrol->value.integer.value[0]; + bool change = false; + + val += TEGRA210_MBDRC_MASTER_VOL_MIN; + + regmap_update_bits_check(ope->mbdrc_regmap, mc->reg, + mc->max << mc->shift, val << mc->shift, + &change); + + regmap_read(ope->mbdrc_regmap, mc->reg, &val); + + return change ? 1 : 0; +} + +static const char * const tegra210_mbdrc_mode_text[] = { + "Bypass", "Fullband", "Dualband", "Multiband" +}; + +static const struct soc_enum tegra210_mbdrc_mode_enum = + SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT, + 4, tegra210_mbdrc_mode_text); + +static const char * const tegra210_mbdrc_peak_rms_text[] = { + "Peak", "RMS" +}; + +static const struct soc_enum tegra210_mbdrc_peak_rms_enum = + SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT, + 2, tegra210_mbdrc_peak_rms_text); + +static const char * const tegra210_mbdrc_filter_structure_text[] = { + "All-pass-tree", "Flexible" +}; + +static const struct soc_enum tegra210_mbdrc_filter_structure_enum = + SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2, + tegra210_mbdrc_filter_structure_text); + +static const char * const tegra210_mbdrc_frame_size_text[] = { + "N1", "N2", "N4", "N8", "N16", "N32", "N64" +}; + +static const struct soc_enum tegra210_mbdrc_frame_size_enum = + SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT, + 7, tegra210_mbdrc_frame_size_text); + +#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo) \ + TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \ + tegra210_mbdrc_band_params_get, \ + tegra210_mbdrc_band_params_put, \ + tegra210_mbdrc_param_info) + +#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo) \ + TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT, \ + xshift, xmask, xinfo) + +static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600, 25500); + +static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = { + SOC_ENUM_EXT("MBDRC Peak RMS Mode", tegra210_mbdrc_peak_rms_enum, + tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum), + + SOC_ENUM_EXT("MBDRC Filter Structure", + tegra210_mbdrc_filter_structure_enum, + tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum), + + SOC_ENUM_EXT("MBDRC Frame Size", tegra210_mbdrc_frame_size_enum, + tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum), + + SOC_ENUM_EXT("MBDRC Mode", tegra210_mbdrc_mode_enum, + tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum), + + SOC_SINGLE_EXT("MBDRC RMS Offset", TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0x1ff, 0, + tegra210_mbdrc_get, tegra210_mbdrc_put), + + SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0x1f, 0, + tegra210_mbdrc_get, tegra210_mbdrc_put), + + SOC_SINGLE_EXT("MBDRC Fast Attack Factor", TEGRA210_MBDRC_FAST_FACTOR, + TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0, + tegra210_mbdrc_get, tegra210_mbdrc_put), + + SOC_SINGLE_EXT("MBDRC Fast Release Factor", TEGRA210_MBDRC_FAST_FACTOR, + TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0, + tegra210_mbdrc_get, tegra210_mbdrc_put), + + SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume", + TEGRA210_MBDRC_MASTER_VOL, + TEGRA210_MBDRC_MASTER_VOL_SHIFT, + 0, 0x1ff, 0, + tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put, + mdbrc_vol_tlv), + + TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages", TEGRA210_MBDRC_IIR_CFG, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT, + TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const", TEGRA210_MBDRC_IN_ATTACK, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT, + TEGRA210_MBDRC_IN_ATTACK_TC_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const", TEGRA210_MBDRC_IN_RELEASE, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT, + TEGRA210_MBDRC_IN_RELEASE_TC_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const", TEGRA210_MBDRC_FAST_ATTACK, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT, + TEGRA210_MBDRC_FAST_ATTACK_TC_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC In Threshold", TEGRA210_MBDRC_IN_THRESHOLD, + TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff, + tegra210_mbdrc_threshold_get, + tegra210_mbdrc_threshold_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold", TEGRA210_MBDRC_OUT_THRESHOLD, + TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff, + tegra210_mbdrc_threshold_get, + tegra210_mbdrc_threshold_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Ratio", TEGRA210_MBDRC_RATIO_1ST, + TEGRA210_MBDRC_FILTER_COUNT * 5, + TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain", TEGRA210_MBDRC_MAKEUP_GAIN, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT, + TEGRA210_MBDRC_MAKEUP_GAIN_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Init Gain", TEGRA210_MBDRC_INIT_GAIN, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_INIT_GAIN_SHIFT, + TEGRA210_MBDRC_INIT_GAIN_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain", TEGRA210_MBDRC_GAIN_ATTACK, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_GAIN_ATTACK_SHIFT, + TEGRA210_MBDRC_GAIN_ATTACK_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Release Gain", TEGRA210_MBDRC_GAIN_RELEASE, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_GAIN_RELEASE_SHIFT, + TEGRA210_MBDRC_GAIN_RELEASE_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain", + TEGRA210_MBDRC_FAST_RELEASE, + TEGRA210_MBDRC_FILTER_COUNT, + TEGRA210_MBDRC_FAST_RELEASE_SHIFT, + TEGRA210_MBDRC_FAST_RELEASE_MASK, + tegra210_mbdrc_band_params_get, + tegra210_mbdrc_band_params_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs", + TEGRA210_MBDRC_CFG_RAM_CTRL, + TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff, + tegra210_mbdrc_biquad_coeffs_get, + tegra210_mbdrc_biquad_coeffs_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs", + TEGRA210_MBDRC_CFG_RAM_CTRL + + TEGRA210_MBDRC_FILTER_PARAM_STRIDE, + TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff, + tegra210_mbdrc_biquad_coeffs_get, + tegra210_mbdrc_biquad_coeffs_put, + tegra210_mbdrc_param_info), + + TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs", + TEGRA210_MBDRC_CFG_RAM_CTRL + + (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2), + TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff, + tegra210_mbdrc_biquad_coeffs_get, + tegra210_mbdrc_biquad_coeffs_put, + tegra210_mbdrc_param_info), +}; + +static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg) +{ + if (reg >= TEGRA210_MBDRC_IIR_CFG) + reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) % + (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * + TEGRA210_MBDRC_FILTER_COUNT)); + + switch (reg) { + case TEGRA210_MBDRC_SOFT_RESET: + case TEGRA210_MBDRC_CG: + case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg) +{ + if (tegra210_mbdrc_wr_reg(dev, reg)) + return true; + + if (reg >= TEGRA210_MBDRC_IIR_CFG) + reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) % + (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * + TEGRA210_MBDRC_FILTER_COUNT)); + + switch (reg) { + case TEGRA210_MBDRC_STATUS: + return true; + default: + return false; + } +} + +static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg >= TEGRA210_MBDRC_IIR_CFG) + reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) % + (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * + TEGRA210_MBDRC_FILTER_COUNT)); + + switch (reg) { + case TEGRA210_MBDRC_SOFT_RESET: + case TEGRA210_MBDRC_STATUS: + case TEGRA210_MBDRC_CFG_RAM_CTRL: + case TEGRA210_MBDRC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg) +{ + if (reg >= TEGRA210_MBDRC_IIR_CFG) + reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) % + (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * + TEGRA210_MBDRC_FILTER_COUNT)); + + switch (reg) { + case TEGRA210_MBDRC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_mbdrc_regmap_cfg = { + .name = "mbdrc", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_MBDRC_MAX_REG, + .writeable_reg = tegra210_mbdrc_wr_reg, + .readable_reg = tegra210_mbdrc_rd_reg, + .volatile_reg = tegra210_mbdrc_volatile_reg, + .precious_reg = tegra210_mbdrc_precious_reg, + .reg_defaults = tegra210_mbdrc_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_mbdrc_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt) +{ + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + const struct tegra210_mbdrc_config *conf = &mbdrc_init_config; + u32 val = 0; + unsigned int i; + + regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val); + + val &= TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK; + + if (val == TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS) + return 0; + + for (i = 0; i < MBDRC_NUM_BAND; i++) { + const struct tegra210_mbdrc_band_params *params = + &conf->band_params[i]; + + u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE; + + tegra210_mbdrc_write_ram(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL, + reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, + 0, (u32 *)¶ms->biquad_params[0], + TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5); + } + return 0; +} + +int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt) +{ + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + const struct tegra210_mbdrc_config *conf = &mbdrc_init_config; + unsigned int i; + u32 val; + + pm_runtime_get_sync(cmpnt->dev); + + /* Initialize MBDRC registers and AHUB RAM with default params */ + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK, + conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK, + conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_PEAK_RMS_MASK, + conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK, + conf->fliter_structure << + TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK, + conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, + TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK, + __ffs(conf->frame_size) << + TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK, + TEGRA210_MBDRC_CHANNEL_MASK_MASK, + conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR, + TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK, + conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR, + TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK, + conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT); + + for (i = 0; i < MBDRC_NUM_BAND; i++) { + const struct tegra210_mbdrc_band_params *params = + &conf->band_params[i]; + u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE; + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_IIR_CFG, + TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK, + params->iir_stages << + TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_IN_ATTACK, + TEGRA210_MBDRC_IN_ATTACK_TC_MASK, + params->in_attack_tc << + TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_IN_RELEASE, + TEGRA210_MBDRC_IN_RELEASE_TC_MASK, + params->in_release_tc << + TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_FAST_ATTACK, + TEGRA210_MBDRC_FAST_ATTACK_TC_MASK, + params->fast_attack_tc << + TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT); + + val = (((params->in_threshold[0] >> + TEGRA210_MBDRC_THRESH_1ST_SHIFT) & + TEGRA210_MBDRC_THRESH_1ST_MASK) | + ((params->in_threshold[1] >> + TEGRA210_MBDRC_THRESH_2ND_SHIFT) & + TEGRA210_MBDRC_THRESH_2ND_MASK) | + ((params->in_threshold[2] >> + TEGRA210_MBDRC_THRESH_3RD_SHIFT) & + TEGRA210_MBDRC_THRESH_3RD_MASK) | + ((params->in_threshold[3] >> + TEGRA210_MBDRC_THRESH_4TH_SHIFT) & + TEGRA210_MBDRC_THRESH_4TH_MASK)); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_IN_THRESHOLD, + 0xffffffff, val); + + val = (((params->out_threshold[0] >> + TEGRA210_MBDRC_THRESH_1ST_SHIFT) & + TEGRA210_MBDRC_THRESH_1ST_MASK) | + ((params->out_threshold[1] >> + TEGRA210_MBDRC_THRESH_2ND_SHIFT) & + TEGRA210_MBDRC_THRESH_2ND_MASK) | + ((params->out_threshold[2] >> + TEGRA210_MBDRC_THRESH_3RD_SHIFT) & + TEGRA210_MBDRC_THRESH_3RD_MASK) | + ((params->out_threshold[3] >> + TEGRA210_MBDRC_THRESH_4TH_SHIFT) & + TEGRA210_MBDRC_THRESH_4TH_MASK)); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_OUT_THRESHOLD, + 0xffffffff, val); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_RATIO_1ST, + TEGRA210_MBDRC_RATIO_1ST_MASK, + params->ratio[0] << TEGRA210_MBDRC_RATIO_1ST_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_RATIO_2ND, + TEGRA210_MBDRC_RATIO_2ND_MASK, + params->ratio[1] << TEGRA210_MBDRC_RATIO_2ND_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_RATIO_3RD, + TEGRA210_MBDRC_RATIO_3RD_MASK, + params->ratio[2] << TEGRA210_MBDRC_RATIO_3RD_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_RATIO_4TH, + TEGRA210_MBDRC_RATIO_4TH_MASK, + params->ratio[3] << TEGRA210_MBDRC_RATIO_4TH_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_RATIO_5TH, + TEGRA210_MBDRC_RATIO_5TH_MASK, + params->ratio[4] << TEGRA210_MBDRC_RATIO_5TH_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_MAKEUP_GAIN, + TEGRA210_MBDRC_MAKEUP_GAIN_MASK, + params->makeup_gain << + TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_INIT_GAIN, + TEGRA210_MBDRC_INIT_GAIN_MASK, + params->gain_init << + TEGRA210_MBDRC_INIT_GAIN_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_GAIN_ATTACK, + TEGRA210_MBDRC_GAIN_ATTACK_MASK, + params->gain_attack_tc << + TEGRA210_MBDRC_GAIN_ATTACK_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_GAIN_RELEASE, + TEGRA210_MBDRC_GAIN_RELEASE_MASK, + params->gain_release_tc << + TEGRA210_MBDRC_GAIN_RELEASE_SHIFT); + + regmap_update_bits(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_FAST_RELEASE, + TEGRA210_MBDRC_FAST_RELEASE_MASK, + params->fast_release_tc << + TEGRA210_MBDRC_FAST_RELEASE_SHIFT); + + tegra210_mbdrc_write_ram(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL, + reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0, + (u32 *)¶ms->biquad_params[0], + TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5); + } + + pm_runtime_put_sync(cmpnt->dev); + + snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls, + ARRAY_SIZE(tegra210_mbdrc_controls)); + + return 0; +} + +int tegra210_mbdrc_regmap_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_ope *ope = dev_get_drvdata(dev); + struct device_node *child; + struct resource mem; + void __iomem *regs; + int err; + + child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor"); + if (!child) + return -ENODEV; + + err = of_address_to_resource(child, 0, &mem); + of_node_put(child); + if (err < 0) { + dev_err(dev, "fail to get MBDRC resource\n"); + return err; + } + + mem.flags = IORESOURCE_MEM; + regs = devm_ioremap_resource(dev, &mem); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_mbdrc_regmap_cfg); + if (IS_ERR(ope->mbdrc_regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(ope->mbdrc_regmap); + } + + regcache_cache_only(ope->mbdrc_regmap, true); + + return 0; +} diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h new file mode 100644 index 000000000000..4c48da0e1dea --- /dev/null +++ b/sound/soc/tegra/tegra210_mbdrc.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_mbdrc.h - Definitions for Tegra210 MBDRC driver + * + * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_MBDRC_H__ +#define __TEGRA210_MBDRC_H__ + +#include <linux/platform_device.h> +#include <sound/soc.h> + +/* Register offsets from TEGRA210_MBDRC*_BASE */ +#define TEGRA210_MBDRC_SOFT_RESET 0x4 +#define TEGRA210_MBDRC_CG 0x8 +#define TEGRA210_MBDRC_STATUS 0xc +#define TEGRA210_MBDRC_CFG 0x28 +#define TEGRA210_MBDRC_CHANNEL_MASK 0x2c +#define TEGRA210_MBDRC_MASTER_VOL 0x30 +#define TEGRA210_MBDRC_FAST_FACTOR 0x34 + +#define TEGRA210_MBDRC_FILTER_COUNT 3 +#define TEGRA210_MBDRC_FILTER_PARAM_STRIDE 0x4 + +#define TEGRA210_MBDRC_IIR_CFG 0x38 +#define TEGRA210_MBDRC_IN_ATTACK 0x44 +#define TEGRA210_MBDRC_IN_RELEASE 0x50 +#define TEGRA210_MBDRC_FAST_ATTACK 0x5c +#define TEGRA210_MBDRC_IN_THRESHOLD 0x68 +#define TEGRA210_MBDRC_OUT_THRESHOLD 0x74 +#define TEGRA210_MBDRC_RATIO_1ST 0x80 +#define TEGRA210_MBDRC_RATIO_2ND 0x8c +#define TEGRA210_MBDRC_RATIO_3RD 0x98 +#define TEGRA210_MBDRC_RATIO_4TH 0xa4 +#define TEGRA210_MBDRC_RATIO_5TH 0xb0 +#define TEGRA210_MBDRC_MAKEUP_GAIN 0xbc +#define TEGRA210_MBDRC_INIT_GAIN 0xc8 +#define TEGRA210_MBDRC_GAIN_ATTACK 0xd4 +#define TEGRA210_MBDRC_GAIN_RELEASE 0xe0 +#define TEGRA210_MBDRC_FAST_RELEASE 0xec +#define TEGRA210_MBDRC_CFG_RAM_CTRL 0xf8 +#define TEGRA210_MBDRC_CFG_RAM_DATA 0x104 + +#define TEGRA210_MBDRC_MAX_REG (TEGRA210_MBDRC_CFG_RAM_DATA + \ + (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * \ + (TEGRA210_MBDRC_FILTER_COUNT - 1))) + +/* Fields for TEGRA210_MBDRC_CFG */ +#define TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT 16 +#define TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK (0x1ff << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT) + +#define TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT 14 +#define TEGRA210_MBDRC_CFG_PEAK_RMS_MASK (0x1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT) +#define TEGRA210_MBDRC_CFG_PEAK (1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT) + +#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT 13 +#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK (0x1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT) +#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_FLEX (1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT) + +#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT 8 +#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK (0x1f << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT) + +#define TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT 4 +#define TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK (0xf << TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT) + +#define TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT 0 +#define TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK (0x3 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT) +#define TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS (0 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT) + +/* Fields for TEGRA210_MBDRC_CHANNEL_MASK */ +#define TEGRA210_MBDRC_CHANNEL_MASK_SHIFT 0 +#define TEGRA210_MBDRC_CHANNEL_MASK_MASK (0xff << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT) + +/* Fields for TEGRA210_MBDRC_MASTER_VOL */ +#define TEGRA210_MBDRC_MASTER_VOL_SHIFT 23 +#define TEGRA210_MBDRC_MASTER_VOL_MIN -256 +#define TEGRA210_MBDRC_MASTER_VOL_MAX 256 + +/* Fields for TEGRA210_MBDRC_FAST_FACTOR */ +#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT 16 +#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_MASK (0xffff << TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT) + +#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT 0 +#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK (0xffff << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT) + +/* Fields for TEGRA210_MBDRC_IIR_CFG */ +#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT 0 +#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK (0xf << TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT) + +/* Fields for TEGRA210_MBDRC_IN_ATTACK */ +#define TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT 0 +#define TEGRA210_MBDRC_IN_ATTACK_TC_MASK (0xffffffff << TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT) + +/* Fields for TEGRA210_MBDRC_IN_RELEASE */ +#define TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT 0 +#define TEGRA210_MBDRC_IN_RELEASE_TC_MASK (0xffffffff << TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT) + +/* Fields for TEGRA210_MBDRC_FAST_ATTACK */ +#define TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT 0 +#define TEGRA210_MBDRC_FAST_ATTACK_TC_MASK (0xffffffff << TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT) + +/* Fields for TEGRA210_MBDRC_IN_THRESHOLD / TEGRA210_MBDRC_OUT_THRESHOLD */ +#define TEGRA210_MBDRC_THRESH_4TH_SHIFT 24 +#define TEGRA210_MBDRC_THRESH_4TH_MASK (0xff << TEGRA210_MBDRC_THRESH_4TH_SHIFT) + +#define TEGRA210_MBDRC_THRESH_3RD_SHIFT 16 +#define TEGRA210_MBDRC_THRESH_3RD_MASK (0xff << TEGRA210_MBDRC_THRESH_3RD_SHIFT) + +#define TEGRA210_MBDRC_THRESH_2ND_SHIFT 8 +#define TEGRA210_MBDRC_THRESH_2ND_MASK (0xff << TEGRA210_MBDRC_THRESH_2ND_SHIFT) + +#define TEGRA210_MBDRC_THRESH_1ST_SHIFT 0 +#define TEGRA210_MBDRC_THRESH_1ST_MASK (0xff << TEGRA210_MBDRC_THRESH_1ST_SHIFT) + +/* Fields for TEGRA210_MBDRC_RATIO_1ST */ +#define TEGRA210_MBDRC_RATIO_1ST_SHIFT 0 +#define TEGRA210_MBDRC_RATIO_1ST_MASK (0xffff << TEGRA210_MBDRC_RATIO_1ST_SHIFT) + +/* Fields for TEGRA210_MBDRC_RATIO_2ND */ +#define TEGRA210_MBDRC_RATIO_2ND_SHIFT 0 +#define TEGRA210_MBDRC_RATIO_2ND_MASK (0xffff << TEGRA210_MBDRC_RATIO_2ND_SHIFT) + +/* Fields for TEGRA210_MBDRC_RATIO_3RD */ +#define TEGRA210_MBDRC_RATIO_3RD_SHIFT 0 +#define TEGRA210_MBDRC_RATIO_3RD_MASK (0xffff << TEGRA210_MBDRC_RATIO_3RD_SHIFT) + +/* Fields for TEGRA210_MBDRC_RATIO_4TH */ +#define TEGRA210_MBDRC_RATIO_4TH_SHIFT 0 +#define TEGRA210_MBDRC_RATIO_4TH_MASK (0xffff << TEGRA210_MBDRC_RATIO_4TH_SHIFT) + +/* Fields for TEGRA210_MBDRC_RATIO_5TH */ +#define TEGRA210_MBDRC_RATIO_5TH_SHIFT 0 +#define TEGRA210_MBDRC_RATIO_5TH_MASK (0xffff << TEGRA210_MBDRC_RATIO_5TH_SHIFT) + +/* Fields for TEGRA210_MBDRC_MAKEUP_GAIN */ +#define TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT 0 +#define TEGRA210_MBDRC_MAKEUP_GAIN_MASK (0x3f << TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT) + +/* Fields for TEGRA210_MBDRC_INIT_GAIN */ +#define TEGRA210_MBDRC_INIT_GAIN_SHIFT 0 +#define TEGRA210_MBDRC_INIT_GAIN_MASK (0xffffffff << TEGRA210_MBDRC_INIT_GAIN_SHIFT) + +/* Fields for TEGRA210_MBDRC_GAIN_ATTACK */ +#define TEGRA210_MBDRC_GAIN_ATTACK_SHIFT 0 +#define TEGRA210_MBDRC_GAIN_ATTACK_MASK (0xffffffff << TEGRA210_MBDRC_GAIN_ATTACK_SHIFT) + +/* Fields for TEGRA210_MBDRC_GAIN_RELEASE */ +#define TEGRA210_MBDRC_GAIN_RELEASE_SHIFT 0 +#define TEGRA210_MBDRC_GAIN_RELEASE_MASK (0xffffffff << TEGRA210_MBDRC_GAIN_RELEASE_SHIFT) + +/* Fields for TEGRA210_MBDRC_FAST_RELEASE */ +#define TEGRA210_MBDRC_FAST_RELEASE_SHIFT 0 +#define TEGRA210_MBDRC_FAST_RELEASE_MASK (0xffffffff << TEGRA210_MBDRC_FAST_RELEASE_SHIFT) + +#define TEGRA210_MBDRC_RAM_CTRL_RW_READ 0 +#define TEGRA210_MBDRC_RAM_CTRL_RW_WRITE (1 << 14) +#define TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN (1 << 13) +#define TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN (1 << 12) +#define TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK 0x1ff + +/* + * Order and size of each structure element for following structures should not + * be altered size order of elements and their size are based on PEQ co-eff ram + * and shift ram layout. + */ +#define TEGRA210_MBDRC_THRESHOLD_NUM 4 +#define TEGRA210_MBDRC_RATIO_NUM (TEGRA210_MBDRC_THRESHOLD_NUM + 1) +#define TEGRA210_MBDRC_MAX_BIQUAD_STAGES 8 + +/* Order of these enums are same as the order of band specific hw registers */ +enum { + MBDRC_LOW_BAND, + MBDRC_MID_BAND, + MBDRC_HIGH_BAND, + MBDRC_NUM_BAND, +}; + +struct tegra210_mbdrc_band_params { + u32 band; + u32 iir_stages; + u32 in_attack_tc; + u32 in_release_tc; + u32 fast_attack_tc; + u32 in_threshold[TEGRA210_MBDRC_THRESHOLD_NUM]; + u32 out_threshold[TEGRA210_MBDRC_THRESHOLD_NUM]; + u32 ratio[TEGRA210_MBDRC_RATIO_NUM]; + u32 makeup_gain; + u32 gain_init; + u32 gain_attack_tc; + u32 gain_release_tc; + u32 fast_release_tc; + /* For biquad_params[][5] order of coeff is b0, b1, a0, a1, a2 */ + u32 biquad_params[TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5]; +}; + +struct tegra210_mbdrc_config { + unsigned int mode; + unsigned int rms_off; + unsigned int peak_rms_mode; + unsigned int fliter_structure; + unsigned int shift_ctrl; + unsigned int frame_size; + unsigned int channel_mask; + unsigned int fa_factor; /* Fast attack factor */ + unsigned int fr_factor; /* Fast release factor */ + struct tegra210_mbdrc_band_params band_params[MBDRC_NUM_BAND]; +}; + +int tegra210_mbdrc_regmap_init(struct platform_device *pdev); +int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt); +int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt); + +#endif diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c new file mode 100644 index 000000000000..3dd2bdec657b --- /dev/null +++ b/sound/soc/tegra/tegra210_ope.c @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_ope.c - Tegra210 OPE driver +// +// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_mbdrc.h" +#include "tegra210_ope.h" +#include "tegra210_peq.h" +#include "tegra_cif.h" + +static const struct reg_default tegra210_ope_reg_defaults[] = { + { TEGRA210_OPE_RX_INT_MASK, 0x00000001}, + { TEGRA210_OPE_RX_CIF_CTRL, 0x00007700}, + { TEGRA210_OPE_TX_INT_MASK, 0x00000001}, + { TEGRA210_OPE_TX_CIF_CTRL, 0x00007700}, + { TEGRA210_OPE_CG, 0x1}, +}; + +static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + if (channels < 2) + return -EINVAL; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + return -EINVAL; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; + + tegra_set_cif(ope->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_ope_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->dev; + struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai); + int err; + + /* Set RX and TX CIF */ + err = tegra210_ope_set_audio_cif(ope, params, + TEGRA210_OPE_RX_CIF_CTRL); + if (err) { + dev_err(dev, "Can't set OPE RX CIF: %d\n", err); + return err; + } + + err = tegra210_ope_set_audio_cif(ope, params, + TEGRA210_OPE_TX_CIF_CTRL); + if (err) { + dev_err(dev, "Can't set OPE TX CIF: %d\n", err); + return err; + } + + tegra210_mbdrc_hw_params(dai->component); + + return err; +} + +static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt) +{ + struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev); + + tegra210_peq_component_init(cmpnt); + tegra210_mbdrc_component_init(cmpnt); + + /* + * The OPE, PEQ and MBDRC functionalities are combined under one + * device registered by OPE driver. In fact OPE HW block includes + * sub blocks PEQ and MBDRC. However driver registers separate + * regmap interfaces for each of these. ASoC core depends on + * dev_get_regmap() to populate the regmap field for a given ASoC + * component. A component can have one regmap reference and since + * the DAPM routes depend on OPE regmap only, below explicit + * assignment is done to highlight this. This is needed for ASoC + * core to access correct regmap during DAPM path setup. + */ + snd_soc_component_init_regmap(cmpnt, ope->regmap); + + return 0; +} + +static const struct snd_soc_dai_ops tegra210_ope_dai_ops = { + .hw_params = tegra210_ope_hw_params, +}; + +static struct snd_soc_dai_driver tegra210_ope_dais[] = { + { + .name = "OPE-RX-CIF", + .playback = { + .stream_name = "RX-CIF-Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "RX-CIF-Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + }, + { + .name = "OPE-TX-CIF", + .playback = { + .stream_name = "TX-CIF-Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "TX-CIF-Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra210_ope_dai_ops, + } +}; + +static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE, + TEGRA210_OPE_EN_SHIFT, 0), +}; + +#define OPE_ROUTES(sname) \ + { "RX XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX-CIF-" sname, NULL, "TX" }, \ + { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \ + { "XBAR-RX", NULL, "TX XBAR-" sname } + +static const struct snd_soc_dapm_route tegra210_ope_routes[] = { + { "TX", NULL, "RX" }, + OPE_ROUTES("Playback"), + OPE_ROUTES("Capture"), +}; + +static const char * const tegra210_ope_data_dir_text[] = { + "MBDRC to PEQ", + "PEQ to MBDRC" +}; + +static const struct soc_enum tegra210_ope_data_dir_enum = + SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT, + 2, tegra210_ope_data_dir_text); + +static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.enumerated.item[0] = ope->data_dir; + + return 0; +} + +static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + unsigned int value = ucontrol->value.enumerated.item[0]; + + if (value == ope->data_dir) + return 0; + + ope->data_dir = value; + + return 1; +} + +static const struct snd_kcontrol_new tegra210_ope_controls[] = { + SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum, + tegra210_ope_get_data_dir, tegra210_ope_put_data_dir), +}; + +static const struct snd_soc_component_driver tegra210_ope_cmpnt = { + .probe = tegra210_ope_component_probe, + .dapm_widgets = tegra210_ope_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets), + .dapm_routes = tegra210_ope_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_ope_routes), + .controls = tegra210_ope_controls, + .num_controls = ARRAY_SIZE(tegra210_ope_controls), +}; + +static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL: + case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL: + case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG: + case TEGRA210_OPE_DIR: + return true; + default: + return false; + } +} + +static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg) +{ + if (tegra210_ope_wr_reg(dev, reg)) + return true; + + switch (reg) { + case TEGRA210_OPE_RX_STATUS: + case TEGRA210_OPE_RX_INT_STATUS: + case TEGRA210_OPE_TX_STATUS: + case TEGRA210_OPE_TX_INT_STATUS: + case TEGRA210_OPE_STATUS: + case TEGRA210_OPE_INT_STATUS: + return true; + default: + return false; + } +} + +static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_OPE_RX_STATUS: + case TEGRA210_OPE_RX_INT_STATUS: + case TEGRA210_OPE_TX_STATUS: + case TEGRA210_OPE_TX_INT_STATUS: + case TEGRA210_OPE_SOFT_RESET: + case TEGRA210_OPE_STATUS: + case TEGRA210_OPE_INT_STATUS: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_ope_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_OPE_DIR, + .writeable_reg = tegra210_ope_wr_reg, + .readable_reg = tegra210_ope_rd_reg, + .volatile_reg = tegra210_ope_volatile_reg, + .reg_defaults = tegra210_ope_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_ope_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static int tegra210_ope_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_ope *ope; + void __iomem *regs; + int err; + + ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL); + if (!ope) + return -ENOMEM; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + ope->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_ope_regmap_config); + if (IS_ERR(ope->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(ope->regmap); + } + + regcache_cache_only(ope->regmap, true); + + dev_set_drvdata(dev, ope); + + err = tegra210_peq_regmap_init(pdev); + if (err < 0) { + dev_err(dev, "PEQ init failed\n"); + return err; + } + + err = tegra210_mbdrc_regmap_init(pdev); + if (err < 0) { + dev_err(dev, "MBDRC init failed\n"); + return err; + } + + err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt, + tegra210_ope_dais, + ARRAY_SIZE(tegra210_ope_dais)); + if (err) { + dev_err(dev, "can't register OPE component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_ope_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev) +{ + struct tegra210_ope *ope = dev_get_drvdata(dev); + + tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains, + ope->peq_biquad_shifts); + + regcache_cache_only(ope->mbdrc_regmap, true); + regcache_cache_only(ope->peq_regmap, true); + regcache_cache_only(ope->regmap, true); + + regcache_mark_dirty(ope->regmap); + regcache_mark_dirty(ope->peq_regmap); + regcache_mark_dirty(ope->mbdrc_regmap); + + return 0; +} + +static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev) +{ + struct tegra210_ope *ope = dev_get_drvdata(dev); + + regcache_cache_only(ope->regmap, false); + regcache_cache_only(ope->peq_regmap, false); + regcache_cache_only(ope->mbdrc_regmap, false); + + regcache_sync(ope->regmap); + regcache_sync(ope->peq_regmap); + regcache_sync(ope->mbdrc_regmap); + + tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains, + ope->peq_biquad_shifts); + + return 0; +} + +static const struct dev_pm_ops tegra210_ope_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend, + tegra210_ope_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static const struct of_device_id tegra210_ope_of_match[] = { + { .compatible = "nvidia,tegra210-ope" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_ope_of_match); + +static struct platform_driver tegra210_ope_driver = { + .driver = { + .name = "tegra210-ope", + .of_match_table = tegra210_ope_of_match, + .pm = &tegra210_ope_pm_ops, + }, + .probe = tegra210_ope_probe, + .remove = tegra210_ope_remove, +}; +module_platform_driver(tegra210_ope_driver) + +MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>"); +MODULE_DESCRIPTION("Tegra210 OPE ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra210_ope.h b/sound/soc/tegra/tegra210_ope.h new file mode 100644 index 000000000000..2835af6ce631 --- /dev/null +++ b/sound/soc/tegra/tegra210_ope.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_ope.h - Definitions for Tegra210 OPE driver + * + * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_OPE_H__ +#define __TEGRA210_OPE_H__ + +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "tegra210_peq.h" + +/* + * OPE_RX registers are with respect to XBAR. + * The data comes from XBAR to OPE + */ +#define TEGRA210_OPE_RX_STATUS 0xc +#define TEGRA210_OPE_RX_INT_STATUS 0x10 +#define TEGRA210_OPE_RX_INT_MASK 0x14 +#define TEGRA210_OPE_RX_INT_SET 0x18 +#define TEGRA210_OPE_RX_INT_CLEAR 0x1c +#define TEGRA210_OPE_RX_CIF_CTRL 0x20 + +/* + * OPE_TX registers are with respect to XBAR. + * The data goes out from OPE to XBAR + */ +#define TEGRA210_OPE_TX_STATUS 0x4c +#define TEGRA210_OPE_TX_INT_STATUS 0x50 +#define TEGRA210_OPE_TX_INT_MASK 0x54 +#define TEGRA210_OPE_TX_INT_SET 0x58 +#define TEGRA210_OPE_TX_INT_CLEAR 0x5c +#define TEGRA210_OPE_TX_CIF_CTRL 0x60 + +/* OPE Gloabal registers */ +#define TEGRA210_OPE_ENABLE 0x80 +#define TEGRA210_OPE_SOFT_RESET 0x84 +#define TEGRA210_OPE_CG 0x88 +#define TEGRA210_OPE_STATUS 0x8c +#define TEGRA210_OPE_INT_STATUS 0x90 +#define TEGRA210_OPE_DIR 0x94 + +/* Fields for TEGRA210_OPE_ENABLE */ +#define TEGRA210_OPE_EN_SHIFT 0 +#define TEGRA210_OPE_EN (1 << TEGRA210_OPE_EN_SHIFT) + +/* Fields for TEGRA210_OPE_SOFT_RESET */ +#define TEGRA210_OPE_SOFT_RESET_SHIFT 0 +#define TEGRA210_OPE_SOFT_RESET_EN (1 << TEGRA210_OPE_SOFT_RESET_SHIFT) + +#define TEGRA210_OPE_DIR_SHIFT 0 + +struct tegra210_ope { + struct regmap *regmap; + struct regmap *peq_regmap; + struct regmap *mbdrc_regmap; + u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH]; + u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH]; + unsigned int data_dir; +}; + +/* Extension of soc_bytes structure defined in sound/soc.h */ +struct tegra_soc_bytes { + struct soc_bytes soc; + u32 shift; /* Used as offset for AHUB RAM related programing */ +}; + +/* Utility structures for using mixer control of type snd_soc_bytes */ +#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \ + xhandler_get, xhandler_put, xinfo) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = xinfo, \ + .get = xhandler_get, \ + .put = xhandler_put, \ + .private_value = ((unsigned long)&(struct tegra_soc_bytes) \ + { \ + .soc.base = xbase, \ + .soc.num_regs = xregs, \ + .soc.mask = xmask, \ + .shift = xshift \ + }) \ +} + +#endif diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c new file mode 100644 index 000000000000..205d956abb42 --- /dev/null +++ b/sound/soc/tegra/tegra210_peq.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_peq.c - Tegra210 PEQ driver +// +// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_ope.h" +#include "tegra210_peq.h" + +static const struct reg_default tegra210_peq_reg_defaults[] = { + { TEGRA210_PEQ_CFG, 0x00000013}, + { TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000}, + { TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000}, +}; + +static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = { + 1495012349, /* Pre-gain */ + + /* Gains : b0, b1, a0, a1, a2 */ + 536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */ + 134217728, -265414508, 131766272, 2140402222, -1071252997, /* Band-1 */ + 268435456, -233515765, -33935948, 1839817267, -773826124, /* Band-2 */ + 536870912, -672537913, 139851540, 1886437554, -824433167, /* Band-3 */ + 268435456, -114439279, 173723964, 205743566, 278809729, /* Band-4 */ + 1, 0, 0, 0, 0, /* Band-5 */ + 1, 0, 0, 0, 0, /* Band-6 */ + 1, 0, 0, 0, 0, /* Band-7 */ + 1, 0, 0, 0, 0, /* Band-8 */ + 1, 0, 0, 0, 0, /* Band-9 */ + 1, 0, 0, 0, 0, /* Band-10 */ + 1, 0, 0, 0, 0, /* Band-11 */ + + 963423114, /* Post-gain */ +}; + +static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = { + 23, /* Pre-shift */ + 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */ + 28, /* Post-shift */ +}; + +static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH]; + +static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl, + unsigned int reg_data, unsigned int ram_offset, + unsigned int *data, size_t size) +{ + unsigned int val; + unsigned int i; + + val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK; + val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN; + val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN; + val |= TEGRA210_PEQ_RAM_CTRL_RW_READ; + + regmap_write(regmap, reg_ctrl, val); + + /* + * Since all ahub non-io modules work under same ahub clock it is not + * necessary to check ahub read busy bit after every read. + */ + for (i = 0; i < size; i++) + regmap_read(regmap, reg_data, &data[i]); +} + +static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl, + unsigned int reg_data, unsigned int ram_offset, + unsigned int *data, size_t size) +{ + unsigned int val; + unsigned int i; + + val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK; + val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN; + val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN; + val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE; + + regmap_write(regmap, reg_ctrl, val); + + for (i = 0; i < size; i++) + regmap_write(regmap, reg_data, data[i]); +} + +static int tegra210_peq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + unsigned int mask = (1 << fls(mc->max)) - 1; + unsigned int val; + + regmap_read(ope->peq_regmap, mc->reg, &val); + + ucontrol->value.integer.value[0] = (val >> mc->shift) & mask; + + if (!mc->invert) + return 0; + + ucontrol->value.integer.value[0] = + mc->max - ucontrol->value.integer.value[0]; + + return 0; +} + +static int tegra210_peq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + unsigned int mask = (1 << fls(mc->max)) - 1; + bool change = false; + unsigned int val; + + val = (ucontrol->value.integer.value[0] & mask); + + if (mc->invert) + val = mc->max - val; + + val = val << mc->shift; + + regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift), + val, &change); + + return change ? 1 : 0; +} + +static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 i, reg_ctrl = params->soc.base; + u32 reg_data = reg_ctrl + cmpnt->val_bytes; + s32 *data = (s32 *)biquad_coeff_buffer; + + pm_runtime_get_sync(cmpnt->dev); + + tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data, + params->shift, data, params->soc.num_regs); + + pm_runtime_put_sync(cmpnt->dev); + + for (i = 0; i < params->soc.num_regs; i++) + ucontrol->value.integer.value[i] = (long)data[i]; + + return 0; +} + +static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + u32 i, reg_ctrl = params->soc.base; + u32 reg_data = reg_ctrl + cmpnt->val_bytes; + s32 *data = (s32 *)biquad_coeff_buffer; + + for (i = 0; i < params->soc.num_regs; i++) + data[i] = (s32)ucontrol->value.integer.value[i]; + + pm_runtime_get_sync(cmpnt->dev); + + tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data, + params->shift, data, params->soc.num_regs); + + pm_runtime_put_sync(cmpnt->dev); + + return 1; +} + +static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = INT_MIN; + uinfo->value.integer.max = INT_MAX; + uinfo->count = params->num_regs; + + return 0; +} + +#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan) \ + TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params", \ + TEGRA210_PEQ_CFG_RAM_CTRL, \ + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH, \ + (TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \ + tegra210_peq_ram_get, tegra210_peq_ram_put, \ + tegra210_peq_param_info) + +#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan) \ + TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params", \ + TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, \ + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH, \ + (TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f, \ + tegra210_peq_ram_get, tegra210_peq_ram_put, \ + tegra210_peq_param_info) + +static const struct snd_kcontrol_new tegra210_peq_controls[] = { + SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG, + TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0, + tegra210_peq_get, tegra210_peq_put), + + SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG, + TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT, + TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0, + tegra210_peq_get, tegra210_peq_put), + + TEGRA210_PEQ_GAIN_PARAMS_CTRL(0), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(1), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(2), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(3), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(4), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(5), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(6), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(7), + + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7), +}; + +static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_SOFT_RESET: + case TEGRA210_PEQ_CG: + case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg) +{ + if (tegra210_peq_wr_reg(dev, reg)) + return true; + + switch (reg) { + case TEGRA210_PEQ_STATUS: + return true; + default: + return false; + } +} + +static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_SOFT_RESET: + case TEGRA210_PEQ_STATUS: + case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_CFG_RAM_DATA: + case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_peq_regmap_config = { + .name = "peq", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_PEQ_CFG_RAM_SHIFT_DATA, + .writeable_reg = tegra210_peq_wr_reg, + .readable_reg = tegra210_peq_rd_reg, + .volatile_reg = tegra210_peq_volatile_reg, + .precious_reg = tegra210_peq_precious_reg, + .reg_defaults = tegra210_peq_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_peq_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains, + u32 *biquad_shifts) +{ + unsigned int i; + + for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) { + tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL, + TEGRA210_PEQ_CFG_RAM_DATA, + (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH), + biquad_gains, + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH); + + tegra210_peq_write_ram(regmap, + TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, + TEGRA210_PEQ_CFG_RAM_SHIFT_DATA, + (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH), + biquad_shifts, + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH); + + } +} + +void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains, + u32 *biquad_shifts) +{ + unsigned int i; + + for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) { + tegra210_peq_read_ram(regmap, + TEGRA210_PEQ_CFG_RAM_CTRL, + TEGRA210_PEQ_CFG_RAM_DATA, + (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH), + biquad_gains, + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH); + + tegra210_peq_read_ram(regmap, + TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, + TEGRA210_PEQ_CFG_RAM_SHIFT_DATA, + (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH), + biquad_shifts, + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH); + } +} + +int tegra210_peq_component_init(struct snd_soc_component *cmpnt) +{ + struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt); + unsigned int i; + + pm_runtime_get_sync(cmpnt->dev); + regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG, + TEGRA210_PEQ_CFG_MODE_MASK, + 0 << TEGRA210_PEQ_CFG_MODE_SHIFT); + regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG, + TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK, + (TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) << + TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT); + + /* Initialize PEQ AHUB RAM with default params */ + for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) { + + /* Set default gain params */ + tegra210_peq_write_ram(ope->peq_regmap, + TEGRA210_PEQ_CFG_RAM_CTRL, + TEGRA210_PEQ_CFG_RAM_DATA, + (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH), + (u32 *)&biquad_init_gains, + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH); + + /* Set default shift params */ + tegra210_peq_write_ram(ope->peq_regmap, + TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, + TEGRA210_PEQ_CFG_RAM_SHIFT_DATA, + (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH), + (u32 *)&biquad_init_shifts, + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH); + + } + + pm_runtime_put_sync(cmpnt->dev); + + snd_soc_add_component_controls(cmpnt, tegra210_peq_controls, + ARRAY_SIZE(tegra210_peq_controls)); + + return 0; +} + +int tegra210_peq_regmap_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_ope *ope = dev_get_drvdata(dev); + struct device_node *child; + struct resource mem; + void __iomem *regs; + int err; + + child = of_get_child_by_name(dev->of_node, "equalizer"); + if (!child) + return -ENODEV; + + err = of_address_to_resource(child, 0, &mem); + of_node_put(child); + if (err < 0) { + dev_err(dev, "fail to get PEQ resource\n"); + return err; + } + + mem.flags = IORESOURCE_MEM; + regs = devm_ioremap_resource(dev, &mem); + if (IS_ERR(regs)) + return PTR_ERR(regs); + ope->peq_regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_peq_regmap_config); + if (IS_ERR(ope->peq_regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(ope->peq_regmap); + } + + regcache_cache_only(ope->peq_regmap, true); + + return 0; +} diff --git a/sound/soc/tegra/tegra210_peq.h b/sound/soc/tegra/tegra210_peq.h new file mode 100644 index 000000000000..6d3de4ff05cc --- /dev/null +++ b/sound/soc/tegra/tegra210_peq.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_peq.h - Definitions for Tegra210 PEQ driver + * + * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_PEQ_H__ +#define __TEGRA210_PEQ_H__ + +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +/* Register offsets from PEQ base */ +#define TEGRA210_PEQ_SOFT_RESET 0x0 +#define TEGRA210_PEQ_CG 0x4 +#define TEGRA210_PEQ_STATUS 0x8 +#define TEGRA210_PEQ_CFG 0xc +#define TEGRA210_PEQ_CFG_RAM_CTRL 0x10 +#define TEGRA210_PEQ_CFG_RAM_DATA 0x14 +#define TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL 0x18 +#define TEGRA210_PEQ_CFG_RAM_SHIFT_DATA 0x1c + +/* Fields in TEGRA210_PEQ_CFG */ +#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT 2 +#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK (0xf << TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT) + +#define TEGRA210_PEQ_CFG_MODE_SHIFT 0 +#define TEGRA210_PEQ_CFG_MODE_MASK (0x1 << TEGRA210_PEQ_CFG_MODE_SHIFT) + +#define TEGRA210_PEQ_RAM_CTRL_RW_READ 0 +#define TEGRA210_PEQ_RAM_CTRL_RW_WRITE (1 << 14) +#define TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN (1 << 13) +#define TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN (1 << 12) +#define TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK 0x1ff + +/* PEQ register definition ends here */ +#define TEGRA210_PEQ_MAX_BIQUAD_STAGES 12 + +#define TEGRA210_PEQ_MAX_CHANNELS 8 + +#define TEGRA210_PEQ_BIQUAD_INIT_STAGE 5 + +#define TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES * 5) +#define TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES) + +int tegra210_peq_regmap_init(struct platform_device *pdev); +int tegra210_peq_component_init(struct snd_soc_component *cmpnt); +void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains, + u32 *biquad_shifts); +void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains, + u32 *biquad_shifts); + +#endif diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 084a533bf4f2..3aa157c82ae2 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -87,11 +87,11 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, } mask |= TEGRA30_I2S_CTRL_MASTER_ENABLE; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: val |= TEGRA30_I2S_CTRL_MASTER_ENABLE; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 0363a088d2e0..fe572b720b09 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -230,15 +230,15 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, dev->fmt = fmt; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* cpu is master */ pcr = DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; /* * Selection of the clock input pin that is the @@ -260,7 +260,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* codec is master */ pcr = 0; break; @@ -395,12 +395,12 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } - master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; + master = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; fmt = params_format(params); mcbsp_word_length = asp_word_length[fmt]; switch (master) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: freq = clk_get_rate(dev->clk); srgr = DAVINCI_MCBSP_SRGR_FSGM | DAVINCI_MCBSP_SRGR_CLKSM; @@ -426,7 +426,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, clk_div &= 0xFF; srgr |= clk_div; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: srgr = DAVINCI_MCBSP_SRGR_FSGM; clk_div = dev->clk_div - 1; srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); @@ -434,7 +434,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, clk_div &= 0xFF; srgr |= clk_div; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* Clock and frame sync given from external sources */ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); srgr = DAVINCI_MCBSP_SRGR_FSGM; @@ -473,15 +473,15 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, fmt = double_fmt[fmt]; } switch (master) { - case SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BP_FC: rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); rcr |= DAVINCI_MCBSP_RCR_RPHASE; xcr |= DAVINCI_MCBSP_XCR_XPHASE; break; - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BC_FP: rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); break; @@ -492,13 +492,13 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, mcbsp_word_length = asp_word_length[fmt]; switch (master) { - case SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BP_FC: rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); break; - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BC_FP: rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); break; diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 377be2e2b6ee..e2aab4729f3a 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -492,8 +492,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), FSRDLY(3)); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* codec is clock and frame slave */ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); @@ -510,7 +510,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp->bclk_master = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_BP_FC: /* codec is clock slave and frame master */ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); @@ -527,7 +527,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp->bclk_master = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: /* codec is clock master and frame slave */ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); @@ -544,7 +544,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp->bclk_master = 0; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* codec is clock and frame master */ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 4479d74f0a45..58d8e200a7b9 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -1036,8 +1036,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, /* In McBSP master modes, FRAME (i.e. sample rate) is generated * by _counting_ BCLKs. Calculate frame size in BCLKs */ - master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK; - if (master == SND_SOC_DAIFMT_CBS_CFS) { + master = mcbsp->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + if (master == SND_SOC_DAIFMT_BP_FP) { div = mcbsp->clk_div ? mcbsp->clk_div : 1; framesize = (mcbsp->in_freq / div) / params_rate(params); @@ -1136,20 +1136,20 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: /* McBSP master. Set FS and bit clocks as outputs */ regs->pcr0 |= FSXM | FSRM | CLKXM | CLKRM; /* Sample rate generator drives the FS */ regs->srgr2 |= FSGM; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: /* McBSP slave. FS clock as output */ regs->srgr2 |= FSGM; regs->pcr0 |= FSXM | FSRM; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* McBSP slave */ break; default: diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 4f41bb0ab2b0..fdd55d772b8e 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -4,8 +4,6 @@ * * Author: Ola Lilja (ola.o.lilja@stericsson.com) * for ST-Ericsson. - * - * License terms: */ #include <asm/mach-types.h> diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index 1ea1729984a9..e5e73a2bd9fe 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -5,8 +5,6 @@ * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * Kristoffer Karlsson <kristoffer.karlsson@stericsson.com> * for ST-Ericsson. - * - * License terms: */ #include <linux/module.h> diff --git a/sound/soc/ux500/mop500_ab8500.h b/sound/soc/ux500/mop500_ab8500.h index 087ef246d87d..98de80a9cc4f 100644 --- a/sound/soc/ux500/mop500_ab8500.h +++ b/sound/soc/ux500/mop500_ab8500.h @@ -4,8 +4,6 @@ * * Author: Ola Lilja <ola.o.lilja@stericsson.com> * for ST-Ericsson. - * - * License terms: */ #ifndef MOP500_AB8500_H diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 21052378a32e..e48098f039d9 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -5,8 +5,6 @@ * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. - * - * License terms: */ #include <linux/module.h> @@ -191,8 +189,8 @@ static int setup_clocking(struct snd_soc_dai *dai, return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: dev_dbg(dai->dev, "%s: Codec is master.\n", __func__); msp_config->iodelay = 0x20; @@ -204,7 +202,7 @@ static int setup_clocking(struct snd_soc_dai *dai, break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__); msp_config->tx_clk_sel = TX_CLK_SEL_SRG; @@ -328,15 +326,15 @@ static int setup_msp_config(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__, runtime->rate, runtime->channels); switch (fmt & - (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP: dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__); msp_config->default_protdesc = 1; msp_config->protocol = MSP_I2S_PROTOCOL; break; - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC: dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__); msp_config->data_size = MSP_DATA_BITS_16; @@ -348,10 +346,10 @@ static int setup_msp_config(struct snd_pcm_substream *substream, break; - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC: dev_dbg(dai->dev, "%s: PCM format.\n", __func__); msp_config->data_size = MSP_DATA_BITS_16; @@ -477,7 +475,7 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, } /* Set OPP-level */ - if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) && + if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) && (drvdata->msp->f_bitclk > 19200000)) { /* If the bit-clock is higher than 19.2MHz, Vape should be * run in 100% OPP. Only when bit-clock is used (MSP master) @@ -544,13 +542,13 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai, dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id); switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | - SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC: break; default: diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index fcd4b26f5d2d..30bf70838196 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -5,8 +5,6 @@ * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. - * - * License terms: */ #ifndef UX500_msp_dai_H diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index fd0b88bb7921..d113411a19f8 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -6,8 +6,6 @@ * Roger Nilsson <roger.xr.nilsson@stericsson.com>, * Sandeep Kaushik <sandeep.kaushik@st.com> * for ST-Ericsson. - * - * License terms: */ #include <linux/module.h> diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 756b3973af9a..d45b5e2831cc 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -4,8 +4,6 @@ * * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * for ST-Ericsson. - * - * License terms: */ diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 18191084b8b8..d3802e5ef196 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -5,8 +5,6 @@ * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. - * - * License terms: */ #include <asm/page.h> diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h index ff3ef7223db6..bd4348ebf9a1 100644 --- a/sound/soc/ux500/ux500_pcm.h +++ b/sound/soc/ux500/ux500_pcm.h @@ -5,8 +5,6 @@ * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. - * - * License terms: */ #ifndef UX500_PCM_H #define UX500_PCM_H diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index aeb4b2c4d1d3..8bd121546032 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -339,7 +339,7 @@ static int xtfpga_i2s_set_fmt(struct snd_soc_dai *cpu_dai, { if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) return -EINVAL; - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) return -EINVAL; if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) return -EINVAL; @@ -487,7 +487,7 @@ static const struct snd_soc_component_driver xtfpga_i2s_component = { static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = { .startup = xtfpga_i2s_startup, .hw_params = xtfpga_i2s_hw_params, - .set_fmt = xtfpga_i2s_set_fmt, + .set_fmt = xtfpga_i2s_set_fmt, }; static struct snd_soc_dai_driver xtfpga_i2s_dai[] = { |