1ae92dcbeSJiaxin Yu // SPDX-License-Identifier: GPL-2.0 2ae92dcbeSJiaxin Yu // 3ae92dcbeSJiaxin Yu // MediaTek ALSA SoC Audio DAI TDM Control 4ae92dcbeSJiaxin Yu // 5ae92dcbeSJiaxin Yu // Copyright (c) 2022 MediaTek Inc. 6ae92dcbeSJiaxin Yu // Author: Jiaxin Yu <jiaxin.yu@mediatek.com> 7ae92dcbeSJiaxin Yu 8ae92dcbeSJiaxin Yu #include <linux/regmap.h> 9ae92dcbeSJiaxin Yu #include <sound/pcm_params.h> 10ae92dcbeSJiaxin Yu 11ae92dcbeSJiaxin Yu #include "mt8186-afe-clk.h" 12ae92dcbeSJiaxin Yu #include "mt8186-afe-common.h" 13ae92dcbeSJiaxin Yu #include "mt8186-afe-gpio.h" 14ae92dcbeSJiaxin Yu #include "mt8186-interconnection.h" 15ae92dcbeSJiaxin Yu 16ae92dcbeSJiaxin Yu #define TDM_HD_EN_W_NAME "TDM_HD_EN" 17ae92dcbeSJiaxin Yu #define TDM_MCLK_EN_W_NAME "TDM_MCLK_EN" 18ae92dcbeSJiaxin Yu #define MTK_AFE_TDM_KCONTROL_NAME "TDM_HD_Mux" 19ae92dcbeSJiaxin Yu 20ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv { 21ae92dcbeSJiaxin Yu unsigned int id; 22ae92dcbeSJiaxin Yu unsigned int rate; /* for determine which apll to use */ 23ae92dcbeSJiaxin Yu unsigned int bck_invert; 24ae92dcbeSJiaxin Yu unsigned int lck_invert; 25ae92dcbeSJiaxin Yu unsigned int lrck_width; 26ae92dcbeSJiaxin Yu unsigned int mclk_id; 27ae92dcbeSJiaxin Yu unsigned int mclk_multiple; /* according to sample rate */ 28ae92dcbeSJiaxin Yu unsigned int mclk_rate; 29ae92dcbeSJiaxin Yu unsigned int mclk_apll; 30ae92dcbeSJiaxin Yu unsigned int tdm_mode; 31ae92dcbeSJiaxin Yu unsigned int data_mode; 32ae92dcbeSJiaxin Yu unsigned int slave_mode; 33ae92dcbeSJiaxin Yu unsigned int low_jitter_en; 34ae92dcbeSJiaxin Yu }; 35ae92dcbeSJiaxin Yu 36ae92dcbeSJiaxin Yu enum { 37ae92dcbeSJiaxin Yu TDM_IN_I2S = 0, 38ae92dcbeSJiaxin Yu TDM_IN_LJ = 1, 39ae92dcbeSJiaxin Yu TDM_IN_RJ = 2, 40ae92dcbeSJiaxin Yu TDM_IN_DSP_A = 4, 41ae92dcbeSJiaxin Yu TDM_IN_DSP_B = 5, 42ae92dcbeSJiaxin Yu }; 43ae92dcbeSJiaxin Yu 44ae92dcbeSJiaxin Yu enum { 45ae92dcbeSJiaxin Yu TDM_DATA_ONE_PIN = 0, 46ae92dcbeSJiaxin Yu TDM_DATA_MULTI_PIN, 47ae92dcbeSJiaxin Yu }; 48ae92dcbeSJiaxin Yu 49ae92dcbeSJiaxin Yu enum { 50ae92dcbeSJiaxin Yu TDM_BCK_NON_INV = 0, 51ae92dcbeSJiaxin Yu TDM_BCK_INV = 1, 52ae92dcbeSJiaxin Yu }; 53ae92dcbeSJiaxin Yu 54ae92dcbeSJiaxin Yu enum { 55ae92dcbeSJiaxin Yu TDM_LCK_NON_INV = 0, 56ae92dcbeSJiaxin Yu TDM_LCK_INV = 1, 57ae92dcbeSJiaxin Yu }; 58ae92dcbeSJiaxin Yu 59ae92dcbeSJiaxin Yu static unsigned int get_tdm_lrck_width(snd_pcm_format_t format, 60ae92dcbeSJiaxin Yu unsigned int mode) 61ae92dcbeSJiaxin Yu { 62ae92dcbeSJiaxin Yu if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B) 63ae92dcbeSJiaxin Yu return 0; 64ae92dcbeSJiaxin Yu 65ae92dcbeSJiaxin Yu return snd_pcm_format_physical_width(format) - 1; 66ae92dcbeSJiaxin Yu } 67ae92dcbeSJiaxin Yu 68ae92dcbeSJiaxin Yu static unsigned int get_tdm_ch_fixup(unsigned int channels) 69ae92dcbeSJiaxin Yu { 70ae92dcbeSJiaxin Yu if (channels > 4) 71ae92dcbeSJiaxin Yu return 8; 72ae92dcbeSJiaxin Yu else if (channels > 2) 73ae92dcbeSJiaxin Yu return 4; 74ae92dcbeSJiaxin Yu 75ae92dcbeSJiaxin Yu return 2; 76ae92dcbeSJiaxin Yu } 77ae92dcbeSJiaxin Yu 78ae92dcbeSJiaxin Yu static unsigned int get_tdm_ch_per_sdata(unsigned int mode, 79ae92dcbeSJiaxin Yu unsigned int channels) 80ae92dcbeSJiaxin Yu { 81ae92dcbeSJiaxin Yu if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B) 82ae92dcbeSJiaxin Yu return get_tdm_ch_fixup(channels); 83ae92dcbeSJiaxin Yu 84ae92dcbeSJiaxin Yu return 2; 85ae92dcbeSJiaxin Yu } 86ae92dcbeSJiaxin Yu 87ae92dcbeSJiaxin Yu enum { 88ae92dcbeSJiaxin Yu SUPPLY_SEQ_APLL, 89ae92dcbeSJiaxin Yu SUPPLY_SEQ_TDM_MCK_EN, 90ae92dcbeSJiaxin Yu SUPPLY_SEQ_TDM_HD_EN, 91ae92dcbeSJiaxin Yu SUPPLY_SEQ_TDM_EN, 92ae92dcbeSJiaxin Yu }; 93ae92dcbeSJiaxin Yu 94ae92dcbeSJiaxin Yu static int get_tdm_id_by_name(const char *name) 95ae92dcbeSJiaxin Yu { 96ae92dcbeSJiaxin Yu return MT8186_DAI_TDM_IN; 97ae92dcbeSJiaxin Yu } 98ae92dcbeSJiaxin Yu 99ae92dcbeSJiaxin Yu static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w, 100ae92dcbeSJiaxin Yu struct snd_kcontrol *kcontrol, 101ae92dcbeSJiaxin Yu int event) 102ae92dcbeSJiaxin Yu { 103ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 104ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 105ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 106ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(w->name); 107ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 108ae92dcbeSJiaxin Yu 109ae92dcbeSJiaxin Yu if (!tdm_priv) { 110ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 111ae92dcbeSJiaxin Yu return -EINVAL; 112ae92dcbeSJiaxin Yu } 113ae92dcbeSJiaxin Yu 114ae92dcbeSJiaxin Yu dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", 115ae92dcbeSJiaxin Yu __func__, w->name, event); 116ae92dcbeSJiaxin Yu 117ae92dcbeSJiaxin Yu switch (event) { 118ae92dcbeSJiaxin Yu case SND_SOC_DAPM_PRE_PMU: 119ae92dcbeSJiaxin Yu mt8186_afe_gpio_request(afe->dev, true, tdm_priv->id, 0); 120ae92dcbeSJiaxin Yu break; 121ae92dcbeSJiaxin Yu case SND_SOC_DAPM_POST_PMD: 122ae92dcbeSJiaxin Yu mt8186_afe_gpio_request(afe->dev, false, tdm_priv->id, 0); 123ae92dcbeSJiaxin Yu break; 124ae92dcbeSJiaxin Yu default: 125ae92dcbeSJiaxin Yu break; 126ae92dcbeSJiaxin Yu } 127ae92dcbeSJiaxin Yu 128ae92dcbeSJiaxin Yu return 0; 129ae92dcbeSJiaxin Yu } 130ae92dcbeSJiaxin Yu 131ae92dcbeSJiaxin Yu static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, 132ae92dcbeSJiaxin Yu struct snd_kcontrol *kcontrol, 133ae92dcbeSJiaxin Yu int event) 134ae92dcbeSJiaxin Yu { 135ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 136ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 137ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 138ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(w->name); 139ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 140ae92dcbeSJiaxin Yu 141ae92dcbeSJiaxin Yu if (!tdm_priv) { 142ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 143ae92dcbeSJiaxin Yu return -EINVAL; 144ae92dcbeSJiaxin Yu } 145ae92dcbeSJiaxin Yu 146ae92dcbeSJiaxin Yu dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", 147ae92dcbeSJiaxin Yu __func__, w->name, event, dai_id); 148ae92dcbeSJiaxin Yu 149ae92dcbeSJiaxin Yu switch (event) { 150ae92dcbeSJiaxin Yu case SND_SOC_DAPM_PRE_PMU: 151ae92dcbeSJiaxin Yu mt8186_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); 152ae92dcbeSJiaxin Yu break; 153ae92dcbeSJiaxin Yu case SND_SOC_DAPM_POST_PMD: 154ae92dcbeSJiaxin Yu tdm_priv->mclk_rate = 0; 155ae92dcbeSJiaxin Yu mt8186_mck_disable(afe, tdm_priv->mclk_id); 156ae92dcbeSJiaxin Yu break; 157ae92dcbeSJiaxin Yu default: 158ae92dcbeSJiaxin Yu break; 159ae92dcbeSJiaxin Yu } 160ae92dcbeSJiaxin Yu 161ae92dcbeSJiaxin Yu return 0; 162ae92dcbeSJiaxin Yu } 163ae92dcbeSJiaxin Yu 164ae92dcbeSJiaxin Yu /* dai component */ 165ae92dcbeSJiaxin Yu /* tdm virtual mux to output widget */ 166ae92dcbeSJiaxin Yu static const char * const tdm_mux_map[] = { 167ae92dcbeSJiaxin Yu "Normal", "Dummy_Widget", 168ae92dcbeSJiaxin Yu }; 169ae92dcbeSJiaxin Yu 170ae92dcbeSJiaxin Yu static int tdm_mux_map_value[] = { 171ae92dcbeSJiaxin Yu 0, 1, 172ae92dcbeSJiaxin Yu }; 173ae92dcbeSJiaxin Yu 174ae92dcbeSJiaxin Yu static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(tdm_mux_map_enum, 175ae92dcbeSJiaxin Yu SND_SOC_NOPM, 176ae92dcbeSJiaxin Yu 0, 177ae92dcbeSJiaxin Yu 1, 178ae92dcbeSJiaxin Yu tdm_mux_map, 179ae92dcbeSJiaxin Yu tdm_mux_map_value); 180ae92dcbeSJiaxin Yu 181ae92dcbeSJiaxin Yu static const struct snd_kcontrol_new tdm_in_mux_control = 182ae92dcbeSJiaxin Yu SOC_DAPM_ENUM("TDM In Select", tdm_mux_map_enum); 183ae92dcbeSJiaxin Yu 184ae92dcbeSJiaxin Yu static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { 185ae92dcbeSJiaxin Yu SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"), 186ae92dcbeSJiaxin Yu 187ae92dcbeSJiaxin Yu SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN, 188ae92dcbeSJiaxin Yu ETDM_IN1_CON0, ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT, 189ae92dcbeSJiaxin Yu 0, mtk_tdm_en_event, 190ae92dcbeSJiaxin Yu SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 191ae92dcbeSJiaxin Yu /* tdm hd en */ 192ae92dcbeSJiaxin Yu SND_SOC_DAPM_SUPPLY_S(TDM_HD_EN_W_NAME, SUPPLY_SEQ_TDM_HD_EN, 193ae92dcbeSJiaxin Yu ETDM_IN1_CON2, ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT, 194ae92dcbeSJiaxin Yu 0, NULL, 195ae92dcbeSJiaxin Yu SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 196ae92dcbeSJiaxin Yu 197ae92dcbeSJiaxin Yu SND_SOC_DAPM_SUPPLY_S(TDM_MCLK_EN_W_NAME, SUPPLY_SEQ_TDM_MCK_EN, 198ae92dcbeSJiaxin Yu SND_SOC_NOPM, 0, 0, 199ae92dcbeSJiaxin Yu mtk_tdm_mck_en_event, 200ae92dcbeSJiaxin Yu SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 201ae92dcbeSJiaxin Yu 202ae92dcbeSJiaxin Yu SND_SOC_DAPM_INPUT("TDM_DUMMY_IN"), 203ae92dcbeSJiaxin Yu 204ae92dcbeSJiaxin Yu SND_SOC_DAPM_MUX("TDM_In_Mux", 205ae92dcbeSJiaxin Yu SND_SOC_NOPM, 0, 0, &tdm_in_mux_control), 206ae92dcbeSJiaxin Yu }; 207ae92dcbeSJiaxin Yu 208ae92dcbeSJiaxin Yu static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source, 209ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *sink) 210ae92dcbeSJiaxin Yu { 211ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *w = sink; 212ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 213ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 214ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 215ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(w->name); 216ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 217ae92dcbeSJiaxin Yu 218ae92dcbeSJiaxin Yu if (!tdm_priv) { 219ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 220ae92dcbeSJiaxin Yu return 0; 221ae92dcbeSJiaxin Yu } 222ae92dcbeSJiaxin Yu 223ae92dcbeSJiaxin Yu return (tdm_priv->mclk_rate > 0) ? 1 : 0; 224ae92dcbeSJiaxin Yu } 225ae92dcbeSJiaxin Yu 226ae92dcbeSJiaxin Yu static int mtk_afe_tdm_mclk_apll_connect(struct snd_soc_dapm_widget *source, 227ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *sink) 228ae92dcbeSJiaxin Yu { 229ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *w = sink; 230ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 231ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 232ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 233ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(w->name); 234ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 235ae92dcbeSJiaxin Yu int cur_apll; 236ae92dcbeSJiaxin Yu 237ae92dcbeSJiaxin Yu /* which apll */ 238ae92dcbeSJiaxin Yu cur_apll = mt8186_get_apll_by_name(afe, source->name); 239ae92dcbeSJiaxin Yu 240ae92dcbeSJiaxin Yu return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; 241ae92dcbeSJiaxin Yu } 242ae92dcbeSJiaxin Yu 243ae92dcbeSJiaxin Yu static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source, 244ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *sink) 245ae92dcbeSJiaxin Yu { 246ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *w = sink; 247ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 248ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 249ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 250ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(w->name); 251ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 252ae92dcbeSJiaxin Yu 253ae92dcbeSJiaxin Yu if (!tdm_priv) { 254ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 255ae92dcbeSJiaxin Yu return 0; 256ae92dcbeSJiaxin Yu } 257ae92dcbeSJiaxin Yu 258ae92dcbeSJiaxin Yu return tdm_priv->low_jitter_en; 259ae92dcbeSJiaxin Yu } 260ae92dcbeSJiaxin Yu 261ae92dcbeSJiaxin Yu static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, 262ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *sink) 263ae92dcbeSJiaxin Yu { 264ae92dcbeSJiaxin Yu struct snd_soc_dapm_widget *w = sink; 265ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 266ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 267ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 268ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(w->name); 269ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 270ae92dcbeSJiaxin Yu int cur_apll; 271ae92dcbeSJiaxin Yu int tdm_need_apll; 272ae92dcbeSJiaxin Yu 273ae92dcbeSJiaxin Yu if (!tdm_priv) { 274ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 275ae92dcbeSJiaxin Yu return 0; 276ae92dcbeSJiaxin Yu } 277ae92dcbeSJiaxin Yu 278ae92dcbeSJiaxin Yu /* which apll */ 279ae92dcbeSJiaxin Yu cur_apll = mt8186_get_apll_by_name(afe, source->name); 280ae92dcbeSJiaxin Yu 281ae92dcbeSJiaxin Yu /* choose APLL from tdm rate */ 282ae92dcbeSJiaxin Yu tdm_need_apll = mt8186_get_apll_by_rate(afe, tdm_priv->rate); 283ae92dcbeSJiaxin Yu 284ae92dcbeSJiaxin Yu return (tdm_need_apll == cur_apll) ? 1 : 0; 285ae92dcbeSJiaxin Yu } 286ae92dcbeSJiaxin Yu 287ae92dcbeSJiaxin Yu /* low jitter control */ 288ae92dcbeSJiaxin Yu static const char * const mt8186_tdm_hd_str[] = { 289ae92dcbeSJiaxin Yu "Normal", "Low_Jitter" 290ae92dcbeSJiaxin Yu }; 291ae92dcbeSJiaxin Yu 292ae92dcbeSJiaxin Yu static const struct soc_enum mt8186_tdm_enum[] = { 293ae92dcbeSJiaxin Yu SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_tdm_hd_str), 294ae92dcbeSJiaxin Yu mt8186_tdm_hd_str), 295ae92dcbeSJiaxin Yu }; 296ae92dcbeSJiaxin Yu 297ae92dcbeSJiaxin Yu static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol, 298ae92dcbeSJiaxin Yu struct snd_ctl_elem_value *ucontrol) 299ae92dcbeSJiaxin Yu { 300ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 301ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 302ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 303ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(kcontrol->id.name); 304ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 305ae92dcbeSJiaxin Yu 306ae92dcbeSJiaxin Yu if (!tdm_priv) { 307ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 308ae92dcbeSJiaxin Yu return -EINVAL; 309ae92dcbeSJiaxin Yu } 310ae92dcbeSJiaxin Yu 311ae92dcbeSJiaxin Yu ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en; 312ae92dcbeSJiaxin Yu 313ae92dcbeSJiaxin Yu return 0; 314ae92dcbeSJiaxin Yu } 315ae92dcbeSJiaxin Yu 316ae92dcbeSJiaxin Yu static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol, 317ae92dcbeSJiaxin Yu struct snd_ctl_elem_value *ucontrol) 318ae92dcbeSJiaxin Yu { 319ae92dcbeSJiaxin Yu struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 320ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 321ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 322ae92dcbeSJiaxin Yu int dai_id = get_tdm_id_by_name(kcontrol->id.name); 323ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 324ae92dcbeSJiaxin Yu struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 325ae92dcbeSJiaxin Yu int hd_en; 326ae92dcbeSJiaxin Yu 327ae92dcbeSJiaxin Yu if (ucontrol->value.enumerated.item[0] >= e->items) 328ae92dcbeSJiaxin Yu return -EINVAL; 329ae92dcbeSJiaxin Yu 330ae92dcbeSJiaxin Yu hd_en = ucontrol->value.integer.value[0]; 331ae92dcbeSJiaxin Yu 332ae92dcbeSJiaxin Yu dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", 333ae92dcbeSJiaxin Yu __func__, kcontrol->id.name, hd_en); 334ae92dcbeSJiaxin Yu 335ae92dcbeSJiaxin Yu if (!tdm_priv) { 336ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 337ae92dcbeSJiaxin Yu return -EINVAL; 338ae92dcbeSJiaxin Yu } 339ae92dcbeSJiaxin Yu 340ae92dcbeSJiaxin Yu if (tdm_priv->low_jitter_en == hd_en) 341ae92dcbeSJiaxin Yu return 0; 342ae92dcbeSJiaxin Yu 343ae92dcbeSJiaxin Yu tdm_priv->low_jitter_en = hd_en; 344ae92dcbeSJiaxin Yu 345ae92dcbeSJiaxin Yu return 1; 346ae92dcbeSJiaxin Yu } 347ae92dcbeSJiaxin Yu 348ae92dcbeSJiaxin Yu static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = { 349ae92dcbeSJiaxin Yu SOC_ENUM_EXT(MTK_AFE_TDM_KCONTROL_NAME, mt8186_tdm_enum[0], 350ae92dcbeSJiaxin Yu mt8186_tdm_hd_get, mt8186_tdm_hd_set), 351ae92dcbeSJiaxin Yu }; 352ae92dcbeSJiaxin Yu 353ae92dcbeSJiaxin Yu static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { 354ae92dcbeSJiaxin Yu {"TDM IN", NULL, "aud_tdm_clk"}, 355ae92dcbeSJiaxin Yu {"TDM IN", NULL, "TDM_EN"}, 356ae92dcbeSJiaxin Yu {"TDM IN", NULL, TDM_HD_EN_W_NAME, mtk_afe_tdm_hd_connect}, 357ae92dcbeSJiaxin Yu {TDM_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, 358ae92dcbeSJiaxin Yu {TDM_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, 359ae92dcbeSJiaxin Yu 360ae92dcbeSJiaxin Yu {"TDM IN", NULL, TDM_MCLK_EN_W_NAME, mtk_afe_tdm_mclk_connect}, 361ae92dcbeSJiaxin Yu {TDM_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_mclk_apll_connect}, 362ae92dcbeSJiaxin Yu {TDM_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_mclk_apll_connect}, 363ae92dcbeSJiaxin Yu 364ae92dcbeSJiaxin Yu /* allow tdm on without codec on */ 365ae92dcbeSJiaxin Yu {"TDM IN", NULL, "TDM_In_Mux"}, 366ae92dcbeSJiaxin Yu {"TDM_In_Mux", "Dummy_Widget", "TDM_DUMMY_IN"}, 367ae92dcbeSJiaxin Yu }; 368ae92dcbeSJiaxin Yu 369ae92dcbeSJiaxin Yu /* dai ops */ 370ae92dcbeSJiaxin Yu static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, 371ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv, 372ae92dcbeSJiaxin Yu int freq) 373ae92dcbeSJiaxin Yu { 374ae92dcbeSJiaxin Yu int apll; 375ae92dcbeSJiaxin Yu int apll_rate; 376ae92dcbeSJiaxin Yu 377ae92dcbeSJiaxin Yu apll = mt8186_get_apll_by_rate(afe, freq); 378ae92dcbeSJiaxin Yu apll_rate = mt8186_get_apll_rate(afe, apll); 379ae92dcbeSJiaxin Yu 380ae92dcbeSJiaxin Yu if (!freq || freq > apll_rate) { 381ae92dcbeSJiaxin Yu dev_err(afe->dev, 382ae92dcbeSJiaxin Yu "%s(), freq(%d Hz) invalid\n", __func__, freq); 383ae92dcbeSJiaxin Yu return -EINVAL; 384ae92dcbeSJiaxin Yu } 385ae92dcbeSJiaxin Yu 386ae92dcbeSJiaxin Yu if (apll_rate % freq != 0) { 387ae92dcbeSJiaxin Yu dev_err(afe->dev, 388ae92dcbeSJiaxin Yu "%s(), APLL cannot generate %d Hz", __func__, freq); 389ae92dcbeSJiaxin Yu return -EINVAL; 390ae92dcbeSJiaxin Yu } 391ae92dcbeSJiaxin Yu 392ae92dcbeSJiaxin Yu tdm_priv->mclk_rate = freq; 393ae92dcbeSJiaxin Yu tdm_priv->mclk_apll = apll; 394ae92dcbeSJiaxin Yu 395ae92dcbeSJiaxin Yu return 0; 396ae92dcbeSJiaxin Yu } 397ae92dcbeSJiaxin Yu 398ae92dcbeSJiaxin Yu static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, 399ae92dcbeSJiaxin Yu struct snd_pcm_hw_params *params, 400ae92dcbeSJiaxin Yu struct snd_soc_dai *dai) 401ae92dcbeSJiaxin Yu { 402ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 403ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 404ae92dcbeSJiaxin Yu int tdm_id = dai->id; 405ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; 406ae92dcbeSJiaxin Yu unsigned int tdm_mode = tdm_priv->tdm_mode; 407ae92dcbeSJiaxin Yu unsigned int data_mode = tdm_priv->data_mode; 408ae92dcbeSJiaxin Yu unsigned int rate = params_rate(params); 409ae92dcbeSJiaxin Yu unsigned int channels = params_channels(params); 410ae92dcbeSJiaxin Yu snd_pcm_format_t format = params_format(params); 411ae92dcbeSJiaxin Yu unsigned int bit_width = 412ae92dcbeSJiaxin Yu snd_pcm_format_physical_width(format); 413ae92dcbeSJiaxin Yu unsigned int tdm_channels = (data_mode == TDM_DATA_ONE_PIN) ? 414ae92dcbeSJiaxin Yu get_tdm_ch_per_sdata(tdm_mode, channels) : 2; 415ae92dcbeSJiaxin Yu unsigned int lrck_width = 416ae92dcbeSJiaxin Yu get_tdm_lrck_width(format, tdm_mode); 417ae92dcbeSJiaxin Yu unsigned int tdm_con = 0; 418ae92dcbeSJiaxin Yu bool slave_mode = tdm_priv->slave_mode; 419ae92dcbeSJiaxin Yu bool lrck_inv = tdm_priv->lck_invert; 420ae92dcbeSJiaxin Yu bool bck_inv = tdm_priv->bck_invert; 421ae92dcbeSJiaxin Yu unsigned int tran_rate; 422ae92dcbeSJiaxin Yu unsigned int tran_relatch_rate; 423ae92dcbeSJiaxin Yu 424ae92dcbeSJiaxin Yu if (!tdm_priv) { 425ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 426ae92dcbeSJiaxin Yu return -EINVAL; 427ae92dcbeSJiaxin Yu } 428ae92dcbeSJiaxin Yu 429ae92dcbeSJiaxin Yu tdm_priv->rate = rate; 430ae92dcbeSJiaxin Yu 431ae92dcbeSJiaxin Yu tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id); 432ae92dcbeSJiaxin Yu tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate); 433ae92dcbeSJiaxin Yu 434ae92dcbeSJiaxin Yu /* calculate mclk_rate, if not set explicitly */ 435ae92dcbeSJiaxin Yu if (!tdm_priv->mclk_rate) { 436ae92dcbeSJiaxin Yu tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; 437ae92dcbeSJiaxin Yu mtk_dai_tdm_cal_mclk(afe, 438ae92dcbeSJiaxin Yu tdm_priv, 439ae92dcbeSJiaxin Yu tdm_priv->mclk_rate); 440ae92dcbeSJiaxin Yu } 441ae92dcbeSJiaxin Yu 442ae92dcbeSJiaxin Yu /* ETDM_IN1_CON0 */ 443ae92dcbeSJiaxin Yu tdm_con |= slave_mode << ETDM_IN1_CON0_REG_SLAVE_MODE_SFT; 444ae92dcbeSJiaxin Yu tdm_con |= tdm_mode << ETDM_IN1_CON0_REG_FMT_SFT; 445ae92dcbeSJiaxin Yu tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_BIT_LENGTH_SFT; 446ae92dcbeSJiaxin Yu tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_WORD_LENGTH_SFT; 447ae92dcbeSJiaxin Yu tdm_con |= (tdm_channels - 1) << ETDM_IN1_CON0_REG_CH_NUM_SFT; 448ae92dcbeSJiaxin Yu /* need to disable sync mode otherwise this may cause latch data error */ 449ae92dcbeSJiaxin Yu tdm_con |= 0 << ETDM_IN1_CON0_REG_SYNC_MODE_SFT; 450ae92dcbeSJiaxin Yu /* relatch 1x en clock fix to h26m */ 451ae92dcbeSJiaxin Yu tdm_con |= 0 << ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT; 452ae92dcbeSJiaxin Yu regmap_update_bits(afe->regmap, ETDM_IN1_CON0, ETDM_IN_CON0_CTRL_MASK, tdm_con); 453ae92dcbeSJiaxin Yu 454ae92dcbeSJiaxin Yu /* ETDM_IN1_CON1 */ 455ae92dcbeSJiaxin Yu tdm_con = 0; 456ae92dcbeSJiaxin Yu tdm_con |= 0 << ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT; 457ae92dcbeSJiaxin Yu tdm_con |= 1 << ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT; 458ae92dcbeSJiaxin Yu tdm_con |= (lrck_width - 1) << ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT; 459ae92dcbeSJiaxin Yu regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con); 460ae92dcbeSJiaxin Yu 461ae92dcbeSJiaxin Yu /* ETDM_IN1_CON3 */ 462ae92dcbeSJiaxin Yu tdm_con = 0; 463ae92dcbeSJiaxin Yu tdm_con = ETDM_IN_CON3_FS(tran_rate); 464ae92dcbeSJiaxin Yu regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con); 465ae92dcbeSJiaxin Yu 466ae92dcbeSJiaxin Yu /* ETDM_IN1_CON4 */ 467ae92dcbeSJiaxin Yu tdm_con = 0; 468ae92dcbeSJiaxin Yu tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate); 469ae92dcbeSJiaxin Yu if (slave_mode) { 470ae92dcbeSJiaxin Yu if (lrck_inv) 471ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON4_CON0_SLAVE_LRCK_INV; 472ae92dcbeSJiaxin Yu if (bck_inv) 473ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON4_CON0_SLAVE_BCK_INV; 474ae92dcbeSJiaxin Yu } else { 475ae92dcbeSJiaxin Yu if (lrck_inv) 476ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON4_CON0_MASTER_LRCK_INV; 477ae92dcbeSJiaxin Yu if (bck_inv) 478ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON4_CON0_MASTER_BCK_INV; 479ae92dcbeSJiaxin Yu } 480ae92dcbeSJiaxin Yu regmap_update_bits(afe->regmap, ETDM_IN1_CON4, ETDM_IN_CON4_CTRL_MASK, tdm_con); 481ae92dcbeSJiaxin Yu 482ae92dcbeSJiaxin Yu /* ETDM_IN1_CON2 */ 483ae92dcbeSJiaxin Yu tdm_con = 0; 484ae92dcbeSJiaxin Yu if (data_mode == TDM_DATA_MULTI_PIN) { 485ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON2_MULTI_IP_2CH_MODE; 486ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON2_MULTI_IP_CH(channels); 487ae92dcbeSJiaxin Yu } 488ae92dcbeSJiaxin Yu regmap_update_bits(afe->regmap, ETDM_IN1_CON2, ETDM_IN_CON2_CTRL_MASK, tdm_con); 489ae92dcbeSJiaxin Yu 490ae92dcbeSJiaxin Yu /* ETDM_IN1_CON8 */ 491ae92dcbeSJiaxin Yu tdm_con = 0; 492ae92dcbeSJiaxin Yu if (slave_mode) { 493ae92dcbeSJiaxin Yu tdm_con |= 1 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT; 494ae92dcbeSJiaxin Yu tdm_con |= 0 << ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT; 495ae92dcbeSJiaxin Yu tdm_con |= ETDM_IN_CON8_FS(tran_relatch_rate); 496ae92dcbeSJiaxin Yu } else { 497ae92dcbeSJiaxin Yu tdm_con |= 0 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT; 498ae92dcbeSJiaxin Yu } 499ae92dcbeSJiaxin Yu regmap_update_bits(afe->regmap, ETDM_IN1_CON8, ETDM_IN_CON8_CTRL_MASK, tdm_con); 500ae92dcbeSJiaxin Yu 501ae92dcbeSJiaxin Yu return 0; 502ae92dcbeSJiaxin Yu } 503ae92dcbeSJiaxin Yu 504ae92dcbeSJiaxin Yu static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, 505ae92dcbeSJiaxin Yu int clk_id, unsigned int freq, int dir) 506ae92dcbeSJiaxin Yu { 507ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); 508ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 509ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; 510ae92dcbeSJiaxin Yu 511ae92dcbeSJiaxin Yu if (!tdm_priv) { 512ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 513ae92dcbeSJiaxin Yu return -EINVAL; 514ae92dcbeSJiaxin Yu } 515ae92dcbeSJiaxin Yu 516ae92dcbeSJiaxin Yu if (dir != SND_SOC_CLOCK_IN) { 517ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); 518ae92dcbeSJiaxin Yu return -EINVAL; 519ae92dcbeSJiaxin Yu } 520ae92dcbeSJiaxin Yu 521ae92dcbeSJiaxin Yu dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); 522ae92dcbeSJiaxin Yu 523ae92dcbeSJiaxin Yu return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); 524ae92dcbeSJiaxin Yu } 525ae92dcbeSJiaxin Yu 526ae92dcbeSJiaxin Yu static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 527ae92dcbeSJiaxin Yu { 528ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); 529ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 530ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; 531ae92dcbeSJiaxin Yu 532ae92dcbeSJiaxin Yu if (!tdm_priv) { 533ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__); 534ae92dcbeSJiaxin Yu return -EINVAL; 535ae92dcbeSJiaxin Yu } 536ae92dcbeSJiaxin Yu 537ae92dcbeSJiaxin Yu /* DAI mode*/ 538ae92dcbeSJiaxin Yu switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 539ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_I2S: 540ae92dcbeSJiaxin Yu tdm_priv->tdm_mode = TDM_IN_I2S; 541ae92dcbeSJiaxin Yu tdm_priv->data_mode = TDM_DATA_MULTI_PIN; 542ae92dcbeSJiaxin Yu break; 543ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_LEFT_J: 544ae92dcbeSJiaxin Yu tdm_priv->tdm_mode = TDM_IN_LJ; 545ae92dcbeSJiaxin Yu tdm_priv->data_mode = TDM_DATA_MULTI_PIN; 546ae92dcbeSJiaxin Yu break; 547ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_RIGHT_J: 548ae92dcbeSJiaxin Yu tdm_priv->tdm_mode = TDM_IN_RJ; 549ae92dcbeSJiaxin Yu tdm_priv->data_mode = TDM_DATA_MULTI_PIN; 550ae92dcbeSJiaxin Yu break; 551ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_DSP_A: 552ae92dcbeSJiaxin Yu tdm_priv->tdm_mode = TDM_IN_DSP_A; 553ae92dcbeSJiaxin Yu tdm_priv->data_mode = TDM_DATA_ONE_PIN; 554ae92dcbeSJiaxin Yu break; 555ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_DSP_B: 556ae92dcbeSJiaxin Yu tdm_priv->tdm_mode = TDM_IN_DSP_B; 557ae92dcbeSJiaxin Yu tdm_priv->data_mode = TDM_DATA_ONE_PIN; 558ae92dcbeSJiaxin Yu break; 559ae92dcbeSJiaxin Yu default: 560ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), invalid DAIFMT_FORMAT_MASK", __func__); 561ae92dcbeSJiaxin Yu return -EINVAL; 562ae92dcbeSJiaxin Yu } 563ae92dcbeSJiaxin Yu 564ae92dcbeSJiaxin Yu /* DAI clock inversion*/ 565ae92dcbeSJiaxin Yu switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 566ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_NB_NF: 567ae92dcbeSJiaxin Yu tdm_priv->bck_invert = TDM_BCK_NON_INV; 568ae92dcbeSJiaxin Yu tdm_priv->lck_invert = TDM_LCK_NON_INV; 569ae92dcbeSJiaxin Yu break; 570ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_NB_IF: 571ae92dcbeSJiaxin Yu tdm_priv->bck_invert = TDM_BCK_NON_INV; 572ae92dcbeSJiaxin Yu tdm_priv->lck_invert = TDM_LCK_INV; 573ae92dcbeSJiaxin Yu break; 574ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_IB_NF: 575ae92dcbeSJiaxin Yu tdm_priv->bck_invert = TDM_BCK_INV; 576ae92dcbeSJiaxin Yu tdm_priv->lck_invert = TDM_LCK_NON_INV; 577ae92dcbeSJiaxin Yu break; 578ae92dcbeSJiaxin Yu case SND_SOC_DAIFMT_IB_IF: 579ae92dcbeSJiaxin Yu tdm_priv->bck_invert = TDM_BCK_INV; 580ae92dcbeSJiaxin Yu tdm_priv->lck_invert = TDM_LCK_INV; 581ae92dcbeSJiaxin Yu break; 582ae92dcbeSJiaxin Yu default: 583ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), invalid DAIFMT_INV_MASK", __func__); 584ae92dcbeSJiaxin Yu return -EINVAL; 585ae92dcbeSJiaxin Yu } 586ae92dcbeSJiaxin Yu 587ae92dcbeSJiaxin Yu switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 588*845a2155SCharles Keepax case SND_SOC_DAIFMT_BP_FP: 589ae92dcbeSJiaxin Yu tdm_priv->slave_mode = false; 590ae92dcbeSJiaxin Yu break; 591*845a2155SCharles Keepax case SND_SOC_DAIFMT_BC_FC: 592ae92dcbeSJiaxin Yu tdm_priv->slave_mode = true; 593ae92dcbeSJiaxin Yu break; 594ae92dcbeSJiaxin Yu default: 595ae92dcbeSJiaxin Yu dev_err(afe->dev, "%s(), invalid DAIFMT_CLOCK_PROVIDER_MASK", 596ae92dcbeSJiaxin Yu __func__); 597ae92dcbeSJiaxin Yu return -EINVAL; 598ae92dcbeSJiaxin Yu } 599ae92dcbeSJiaxin Yu 600ae92dcbeSJiaxin Yu return 0; 601ae92dcbeSJiaxin Yu } 602ae92dcbeSJiaxin Yu 603ae92dcbeSJiaxin Yu static int mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai *dai, 604ae92dcbeSJiaxin Yu unsigned int tx_mask, 605ae92dcbeSJiaxin Yu unsigned int rx_mask, 606ae92dcbeSJiaxin Yu int slots, 607ae92dcbeSJiaxin Yu int slot_width) 608ae92dcbeSJiaxin Yu { 609ae92dcbeSJiaxin Yu struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); 610ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 611ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; 612ae92dcbeSJiaxin Yu 613ae92dcbeSJiaxin Yu dev_dbg(dai->dev, "%s %d slot_width %d\n", __func__, dai->id, slot_width); 614ae92dcbeSJiaxin Yu 615ae92dcbeSJiaxin Yu tdm_priv->lrck_width = slot_width; 616ae92dcbeSJiaxin Yu 617ae92dcbeSJiaxin Yu return 0; 618ae92dcbeSJiaxin Yu } 619ae92dcbeSJiaxin Yu 620ae92dcbeSJiaxin Yu static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { 621ae92dcbeSJiaxin Yu .hw_params = mtk_dai_tdm_hw_params, 622ae92dcbeSJiaxin Yu .set_sysclk = mtk_dai_tdm_set_sysclk, 623ae92dcbeSJiaxin Yu .set_fmt = mtk_dai_tdm_set_fmt, 624ae92dcbeSJiaxin Yu .set_tdm_slot = mtk_dai_tdm_set_tdm_slot, 625ae92dcbeSJiaxin Yu }; 626ae92dcbeSJiaxin Yu 627ae92dcbeSJiaxin Yu /* dai driver */ 628ae92dcbeSJiaxin Yu #define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ 629ae92dcbeSJiaxin Yu SNDRV_PCM_RATE_88200 |\ 630ae92dcbeSJiaxin Yu SNDRV_PCM_RATE_96000 |\ 631ae92dcbeSJiaxin Yu SNDRV_PCM_RATE_176400 |\ 632ae92dcbeSJiaxin Yu SNDRV_PCM_RATE_192000) 633ae92dcbeSJiaxin Yu 634ae92dcbeSJiaxin Yu #define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 635ae92dcbeSJiaxin Yu SNDRV_PCM_FMTBIT_S24_LE |\ 636ae92dcbeSJiaxin Yu SNDRV_PCM_FMTBIT_S32_LE) 637ae92dcbeSJiaxin Yu 638ae92dcbeSJiaxin Yu static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { 639ae92dcbeSJiaxin Yu { 640ae92dcbeSJiaxin Yu .name = "TDM IN", 641ae92dcbeSJiaxin Yu .id = MT8186_DAI_TDM_IN, 642ae92dcbeSJiaxin Yu .capture = { 643ae92dcbeSJiaxin Yu .stream_name = "TDM IN", 644ae92dcbeSJiaxin Yu .channels_min = 2, 645ae92dcbeSJiaxin Yu .channels_max = 8, 646ae92dcbeSJiaxin Yu .rates = MTK_TDM_RATES, 647ae92dcbeSJiaxin Yu .formats = MTK_TDM_FORMATS, 648ae92dcbeSJiaxin Yu }, 649ae92dcbeSJiaxin Yu .ops = &mtk_dai_tdm_ops, 650ae92dcbeSJiaxin Yu }, 651ae92dcbeSJiaxin Yu }; 652ae92dcbeSJiaxin Yu 653ae92dcbeSJiaxin Yu static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe) 654ae92dcbeSJiaxin Yu { 655ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv; 656ae92dcbeSJiaxin Yu 657ae92dcbeSJiaxin Yu tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), 658ae92dcbeSJiaxin Yu GFP_KERNEL); 659ae92dcbeSJiaxin Yu if (!tdm_priv) 660ae92dcbeSJiaxin Yu return NULL; 661ae92dcbeSJiaxin Yu 662ae92dcbeSJiaxin Yu tdm_priv->mclk_multiple = 512; 663ae92dcbeSJiaxin Yu tdm_priv->mclk_id = MT8186_TDM_MCK; 664ae92dcbeSJiaxin Yu tdm_priv->id = MT8186_DAI_TDM_IN; 665ae92dcbeSJiaxin Yu 666ae92dcbeSJiaxin Yu return tdm_priv; 667ae92dcbeSJiaxin Yu } 668ae92dcbeSJiaxin Yu 669ae92dcbeSJiaxin Yu int mt8186_dai_tdm_register(struct mtk_base_afe *afe) 670ae92dcbeSJiaxin Yu { 671ae92dcbeSJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv; 672ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv *tdm_priv; 673ae92dcbeSJiaxin Yu struct mtk_base_afe_dai *dai; 674ae92dcbeSJiaxin Yu 675ae92dcbeSJiaxin Yu dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); 676ae92dcbeSJiaxin Yu if (!dai) 677ae92dcbeSJiaxin Yu return -ENOMEM; 678ae92dcbeSJiaxin Yu 679ae92dcbeSJiaxin Yu list_add(&dai->list, &afe->sub_dais); 680ae92dcbeSJiaxin Yu 681ae92dcbeSJiaxin Yu dai->dai_drivers = mtk_dai_tdm_driver; 682ae92dcbeSJiaxin Yu dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); 683ae92dcbeSJiaxin Yu 684ae92dcbeSJiaxin Yu dai->controls = mtk_dai_tdm_controls; 685ae92dcbeSJiaxin Yu dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls); 686ae92dcbeSJiaxin Yu dai->dapm_widgets = mtk_dai_tdm_widgets; 687ae92dcbeSJiaxin Yu dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); 688ae92dcbeSJiaxin Yu dai->dapm_routes = mtk_dai_tdm_routes; 689ae92dcbeSJiaxin Yu dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); 690ae92dcbeSJiaxin Yu 691ae92dcbeSJiaxin Yu tdm_priv = init_tdm_priv_data(afe); 692ae92dcbeSJiaxin Yu if (!tdm_priv) 693ae92dcbeSJiaxin Yu return -ENOMEM; 694ae92dcbeSJiaxin Yu 695ae92dcbeSJiaxin Yu afe_priv->dai_priv[MT8186_DAI_TDM_IN] = tdm_priv; 696ae92dcbeSJiaxin Yu 697ae92dcbeSJiaxin Yu return 0; 698ae92dcbeSJiaxin Yu } 699