brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · a04c24b Raw
312 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * MediaTek 8365 ALSA SoC Audio DAI ADDA Control4 *5 * Copyright (c) 2024 MediaTek Inc.6 * Authors: Jia Zeng <jia.zeng@mediatek.com>7 *          Alexandre Mergnat <amergnat@baylibre.com>8 */9 10#include <linux/bitops.h>11#include <linux/regmap.h>12#include <sound/pcm_params.h>13#include "mt8365-afe-clk.h"14#include "mt8365-afe-common.h"15#include "../common/mtk-dai-adda-common.h"16 17static int adda_afe_on_ref_cnt;18 19/* DAI Drivers */20 21static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate)22{23	unsigned int val;24 25	if (rate == 8000 || rate == 16000)26		val = AFE_ADDA_DL_VOICE_DATA;27	else28		val = 0;29 30	val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE,31		mtk_adda_dl_rate_transform(afe, rate));32	val |= AFE_ADDA_DL_8X_UPSAMPLE |33	       AFE_ADDA_DL_MUTE_OFF_CH1 |34	       AFE_ADDA_DL_MUTE_OFF_CH2 |35	       AFE_ADDA_DL_DEGRADE_GAIN;36 37	regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);38	regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);39	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);40	/* SA suggest apply -0.3db to audio/speech path */41	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1,42			   0xffffffff, 0xf74f0000);43	/* SA suggest use default value for sdm */44	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,45			   0xffffffff, 0x0700701e);46 47	return 0;48}49 50static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate)51{52	unsigned int val;53 54	val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE,55			 mtk_adda_ul_rate_transform(afe, rate));56	regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,57			   AFE_ADDA_UL_SAMPLING_RATE, val);58	/* Using Internal ADC */59	regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);60 61	return 0;62}63 64int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe)65{66	unsigned long flags;67	struct mt8365_afe_private *afe_priv = afe->platform_priv;68 69	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);70 71	adda_afe_on_ref_cnt++;72	if (adda_afe_on_ref_cnt == 1)73		regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,74				   AFE_ADDA_UL_DL_ADDA_AFE_ON,75				   AFE_ADDA_UL_DL_ADDA_AFE_ON);76 77	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);78 79	return 0;80}81 82int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe)83{84	unsigned long flags;85	struct mt8365_afe_private *afe_priv = afe->platform_priv;86 87	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);88 89	adda_afe_on_ref_cnt--;90	if (adda_afe_on_ref_cnt == 0)91		regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,92				   AFE_ADDA_UL_DL_ADDA_AFE_ON,93				   ~AFE_ADDA_UL_DL_ADDA_AFE_ON);94	else if (adda_afe_on_ref_cnt < 0) {95		adda_afe_on_ref_cnt = 0;96		dev_warn(afe->dev, "Abnormal adda_on ref count. Force it to 0\n");97	}98 99	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);100 101	return 0;102}103 104static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe,105					   bool enable)106{107	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);108 109	if (enable)110		mt8365_dai_enable_adda_on(afe);111	else112		mt8365_dai_disable_adda_on(afe);113}114 115static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe, bool enable)116{117	if (enable) {118		regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1);119		mt8365_dai_enable_adda_on(afe);120		/* enable aud_pad_top fifo */121		regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,122				   0xffffffff, 0x31);123	} else {124		/* disable aud_pad_top fifo */125		regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,126				   0xffffffff, 0x30);127		regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0);128		/* de suggest disable ADDA_UL_SRC at least wait 125us */129		usleep_range(150, 300);130		mt8365_dai_disable_adda_on(afe);131	}132}133 134static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream,135				       struct snd_soc_dai *dai)136{137	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);138	unsigned int stream = substream->stream;139 140	mt8365_afe_enable_main_clk(afe);141 142	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {143		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC);144		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);145	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {146		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC);147	}148 149	return 0;150}151 152static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream,153					 struct snd_soc_dai *dai)154{155	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);156	struct mt8365_afe_private *afe_priv = afe->platform_priv;157	struct mt8365_be_dai_data *be =158		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];159	unsigned int stream = substream->stream;160 161	if (be->prepared[stream]) {162		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {163			mt8365_dai_set_adda_out_enable(afe, false);164			mt8365_afe_set_i2s_out_enable(afe, false);165		} else {166			mt8365_dai_set_adda_in_enable(afe, false);167		}168		be->prepared[stream] = false;169	}170 171	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {172		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);173		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC);174	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {175		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC);176	}177 178	mt8365_afe_disable_main_clk(afe);179}180 181static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream,182				       struct snd_soc_dai *dai)183{184	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);185	struct mt8365_afe_private *afe_priv = afe->platform_priv;186	struct mt8365_be_dai_data *be =187		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];188	unsigned int rate = substream->runtime->rate;189	int bit_width = snd_pcm_format_width(substream->runtime->format);190	int ret;191 192	dev_info(afe->dev, "%s '%s' rate = %u\n", __func__,193		 snd_pcm_stream_str(substream), rate);194 195	if (be->prepared[substream->stream]) {196		dev_info(afe->dev, "%s '%s' prepared already\n",197			 __func__, snd_pcm_stream_str(substream));198		return 0;199	}200 201	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {202		ret = mt8365_dai_set_adda_out(afe, rate);203		if (ret)204			return ret;205 206		ret = mt8365_afe_set_i2s_out(afe, rate, bit_width);207		if (ret)208			return ret;209 210		mt8365_dai_set_adda_out_enable(afe, true);211		mt8365_afe_set_i2s_out_enable(afe, true);212	} else {213		ret = mt8365_dai_set_adda_in(afe, rate);214		if (ret)215			return ret;216 217		mt8365_dai_set_adda_in_enable(afe, true);218	}219	be->prepared[substream->stream] = true;220	return 0;221}222 223static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = {224	.startup	= mt8365_dai_int_adda_startup,225	.shutdown	= mt8365_dai_int_adda_shutdown,226	.prepare	= mt8365_dai_int_adda_prepare,227};228 229static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {230	{231		.name = "INT ADDA",232		.id = MT8365_AFE_IO_INT_ADDA,233		.playback = {234			.stream_name = "INT ADDA Playback",235			.channels_min = 1,236			.channels_max = 2,237			.rates = SNDRV_PCM_RATE_8000_48000,238			.formats = SNDRV_PCM_FMTBIT_S16_LE,239		},240		.capture = {241			.stream_name = "INT ADDA Capture",242			.channels_min = 1,243			.channels_max = 2,244			.rates = SNDRV_PCM_RATE_16000 |245				 SNDRV_PCM_RATE_32000 |246				 SNDRV_PCM_RATE_48000,247			.formats = SNDRV_PCM_FMTBIT_S16_LE |248				   SNDRV_PCM_FMTBIT_S32_LE,249		},250		.ops = &mt8365_afe_int_adda_ops,251	}252};253 254/* DAI Controls */255 256static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {257	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,258				    10, 1, 0),259};260 261static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {262	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,263				    11, 1, 0),264};265 266static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl =267	SOC_DAPM_SINGLE_VIRT("Switch", 1);268 269/* DAI widget */270 271static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {272	SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0,273			    &int_adda_o03_o04_enable_ctl),274	/* inter-connections */275	SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,276			   mtk_adda_dl_ch1_mix,277			   ARRAY_SIZE(mtk_adda_dl_ch1_mix)),278	SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,279			   mtk_adda_dl_ch2_mix,280			   ARRAY_SIZE(mtk_adda_dl_ch2_mix)),281};282 283/* DAI route */284 285static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {286	{"INT ADDA O03_O04", "Switch", "O03"},287	{"INT ADDA O03_O04", "Switch", "O04"},288	{"INT ADDA Playback", NULL, "INT ADDA O03_O04"},289	{"INT ADDA Playback", NULL, "ADDA_DL_CH1"},290	{"INT ADDA Playback", NULL, "ADDA_DL_CH2"},291	{"AIN Mux", "INT ADC", "INT ADDA Capture"},292	{"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"},293	{"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"},294};295 296int mt8365_dai_adda_register(struct mtk_base_afe *afe)297{298	struct mtk_base_afe_dai *dai;299 300	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);301	if (!dai)302		return -ENOMEM;303	list_add(&dai->list, &afe->sub_dais);304	dai->dai_drivers = mtk_dai_adda_driver;305	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);306	dai->dapm_widgets = mtk_dai_adda_widgets;307	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);308	dai->dapm_routes = mtk_dai_adda_routes;309	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);310	return 0;311}312