Path: blob/master/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
26488 views
// SPDX-License-Identifier: GPL-2.01/*2* MediaTek 8365 ALSA SoC Audio DAI ADDA Control3*4* Copyright (c) 2024 MediaTek Inc.5* Authors: Jia Zeng <[email protected]>6* Alexandre Mergnat <[email protected]>7*/89#include <linux/bitops.h>10#include <linux/regmap.h>11#include <sound/pcm_params.h>12#include "mt8365-afe-clk.h"13#include "mt8365-afe-common.h"14#include "../common/mtk-dai-adda-common.h"1516static int adda_afe_on_ref_cnt;1718/* DAI Drivers */1920static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate)21{22unsigned int val;2324if (rate == 8000 || rate == 16000)25val = AFE_ADDA_DL_VOICE_DATA;26else27val = 0;2829val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE,30mtk_adda_dl_rate_transform(afe, rate));31val |= AFE_ADDA_DL_8X_UPSAMPLE |32AFE_ADDA_DL_MUTE_OFF_CH1 |33AFE_ADDA_DL_MUTE_OFF_CH2 |34AFE_ADDA_DL_DEGRADE_GAIN;3536regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);37regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);38regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);39/* SA suggest apply -0.3db to audio/speech path */40regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1,410xffffffff, 0xf74f0000);42/* SA suggest use default value for sdm */43regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,440xffffffff, 0x0700701e);4546return 0;47}4849static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate)50{51unsigned int val;5253val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE,54mtk_adda_ul_rate_transform(afe, rate));55regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,56AFE_ADDA_UL_SAMPLING_RATE, val);57/* Using Internal ADC */58regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);5960return 0;61}6263int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe)64{65unsigned long flags;66struct mt8365_afe_private *afe_priv = afe->platform_priv;6768spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);6970adda_afe_on_ref_cnt++;71if (adda_afe_on_ref_cnt == 1)72regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,73AFE_ADDA_UL_DL_ADDA_AFE_ON,74AFE_ADDA_UL_DL_ADDA_AFE_ON);7576spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);7778return 0;79}8081int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe)82{83unsigned long flags;84struct mt8365_afe_private *afe_priv = afe->platform_priv;8586spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);8788adda_afe_on_ref_cnt--;89if (adda_afe_on_ref_cnt == 0)90regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,91AFE_ADDA_UL_DL_ADDA_AFE_ON,92~AFE_ADDA_UL_DL_ADDA_AFE_ON);93else if (adda_afe_on_ref_cnt < 0) {94adda_afe_on_ref_cnt = 0;95dev_warn(afe->dev, "Abnormal adda_on ref count. Force it to 0\n");96}9798spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);99100return 0;101}102103static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe,104bool enable)105{106regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);107108if (enable)109mt8365_dai_enable_adda_on(afe);110else111mt8365_dai_disable_adda_on(afe);112}113114static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe, bool enable)115{116if (enable) {117regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1);118mt8365_dai_enable_adda_on(afe);119/* enable aud_pad_top fifo */120regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,1210xffffffff, 0x31);122} else {123/* disable aud_pad_top fifo */124regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,1250xffffffff, 0x30);126regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0);127/* de suggest disable ADDA_UL_SRC at least wait 125us */128usleep_range(150, 300);129mt8365_dai_disable_adda_on(afe);130}131}132133static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream,134struct snd_soc_dai *dai)135{136struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);137unsigned int stream = substream->stream;138139mt8365_afe_enable_main_clk(afe);140141if (stream == SNDRV_PCM_STREAM_PLAYBACK) {142mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC);143mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);144} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {145mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC);146}147148return 0;149}150151static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream,152struct snd_soc_dai *dai)153{154struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);155struct mt8365_afe_private *afe_priv = afe->platform_priv;156struct mt8365_be_dai_data *be =157&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];158unsigned int stream = substream->stream;159160if (be->prepared[stream]) {161if (stream == SNDRV_PCM_STREAM_PLAYBACK) {162mt8365_dai_set_adda_out_enable(afe, false);163mt8365_afe_set_i2s_out_enable(afe, false);164} else {165mt8365_dai_set_adda_in_enable(afe, false);166}167be->prepared[stream] = false;168}169170if (stream == SNDRV_PCM_STREAM_PLAYBACK) {171mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);172mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC);173} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {174mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC);175}176177mt8365_afe_disable_main_clk(afe);178}179180static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream,181struct snd_soc_dai *dai)182{183struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);184struct mt8365_afe_private *afe_priv = afe->platform_priv;185struct mt8365_be_dai_data *be =186&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];187unsigned int rate = substream->runtime->rate;188int bit_width = snd_pcm_format_width(substream->runtime->format);189int ret;190191dev_info(afe->dev, "%s '%s' rate = %u\n", __func__,192snd_pcm_stream_str(substream), rate);193194if (be->prepared[substream->stream]) {195dev_info(afe->dev, "%s '%s' prepared already\n",196__func__, snd_pcm_stream_str(substream));197return 0;198}199200if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {201ret = mt8365_dai_set_adda_out(afe, rate);202if (ret)203return ret;204205ret = mt8365_afe_set_i2s_out(afe, rate, bit_width);206if (ret)207return ret;208209mt8365_dai_set_adda_out_enable(afe, true);210mt8365_afe_set_i2s_out_enable(afe, true);211} else {212ret = mt8365_dai_set_adda_in(afe, rate);213if (ret)214return ret;215216mt8365_dai_set_adda_in_enable(afe, true);217}218be->prepared[substream->stream] = true;219return 0;220}221222static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = {223.startup = mt8365_dai_int_adda_startup,224.shutdown = mt8365_dai_int_adda_shutdown,225.prepare = mt8365_dai_int_adda_prepare,226};227228static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {229{230.name = "INT ADDA",231.id = MT8365_AFE_IO_INT_ADDA,232.playback = {233.stream_name = "INT ADDA Playback",234.channels_min = 1,235.channels_max = 2,236.rates = SNDRV_PCM_RATE_8000_48000,237.formats = SNDRV_PCM_FMTBIT_S16_LE,238},239.capture = {240.stream_name = "INT ADDA Capture",241.channels_min = 1,242.channels_max = 2,243.rates = SNDRV_PCM_RATE_16000 |244SNDRV_PCM_RATE_32000 |245SNDRV_PCM_RATE_48000,246.formats = SNDRV_PCM_FMTBIT_S16_LE |247SNDRV_PCM_FMTBIT_S32_LE,248},249.ops = &mt8365_afe_int_adda_ops,250}251};252253/* DAI Controls */254255static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {256SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,25710, 1, 0),258};259260static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {261SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,26211, 1, 0),263};264265static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl =266SOC_DAPM_SINGLE_VIRT("Switch", 1);267268/* DAI widget */269270static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {271SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0,272&int_adda_o03_o04_enable_ctl),273/* inter-connections */274SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,275mtk_adda_dl_ch1_mix,276ARRAY_SIZE(mtk_adda_dl_ch1_mix)),277SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,278mtk_adda_dl_ch2_mix,279ARRAY_SIZE(mtk_adda_dl_ch2_mix)),280};281282/* DAI route */283284static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {285{"INT ADDA O03_O04", "Switch", "O03"},286{"INT ADDA O03_O04", "Switch", "O04"},287{"INT ADDA Playback", NULL, "INT ADDA O03_O04"},288{"INT ADDA Playback", NULL, "ADDA_DL_CH1"},289{"INT ADDA Playback", NULL, "ADDA_DL_CH2"},290{"AIN Mux", "INT ADC", "INT ADDA Capture"},291{"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"},292{"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"},293};294295int mt8365_dai_adda_register(struct mtk_base_afe *afe)296{297struct mtk_base_afe_dai *dai;298299dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);300if (!dai)301return -ENOMEM;302list_add(&dai->list, &afe->sub_dais);303dai->dai_drivers = mtk_dai_adda_driver;304dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);305dai->dapm_widgets = mtk_dai_adda_widgets;306dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);307dai->dapm_routes = mtk_dai_adda_routes;308dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);309return 0;310}311312313