Path: blob/master/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c
26488 views
// SPDX-License-Identifier: GPL-2.01//2// MediaTek ALSA SoC Audio DAI TDM Control3//4// Copyright (c) 2018 MediaTek Inc.5// Author: KaiChieh Chuang <[email protected]>67#include <linux/regmap.h>8#include <sound/pcm_params.h>9#include "mt8183-afe-clk.h"10#include "mt8183-afe-common.h"11#include "mt8183-interconnection.h"12#include "mt8183-reg.h"1314struct mtk_afe_tdm_priv {15int bck_id;16int bck_rate;17int tdm_out_mode;18int bck_invert;19int lck_invert;20int mclk_id;21int mclk_multiple; /* according to sample rate */22int mclk_rate;23int mclk_apll;24};2526enum {27TDM_OUT_I2S = 0,28TDM_OUT_TDM = 1,29};3031enum {32TDM_BCK_NON_INV = 0,33TDM_BCK_INV = 1,34};3536enum {37TDM_LCK_NON_INV = 0,38TDM_LCK_INV = 1,39};4041enum {42TDM_WLEN_16_BIT = 1,43TDM_WLEN_32_BIT = 2,44};4546enum {47TDM_CHANNEL_BCK_16 = 0,48TDM_CHANNEL_BCK_24 = 1,49TDM_CHANNEL_BCK_32 = 2,50};5152enum {53TDM_CHANNEL_NUM_2 = 0,54TDM_CHANNEL_NUM_4 = 1,55TDM_CHANNEL_NUM_8 = 2,56};5758enum {59TDM_CH_START_O30_O31 = 0,60TDM_CH_START_O32_O33,61TDM_CH_START_O34_O35,62TDM_CH_START_O36_O37,63TDM_CH_ZERO,64};6566enum {67HDMI_BIT_WIDTH_16_BIT = 0,68HDMI_BIT_WIDTH_32_BIT = 1,69};7071static unsigned int get_hdmi_wlen(snd_pcm_format_t format)72{73return snd_pcm_format_physical_width(format) <= 16 ?74HDMI_BIT_WIDTH_16_BIT : HDMI_BIT_WIDTH_32_BIT;75}7677static unsigned int get_tdm_wlen(snd_pcm_format_t format)78{79return snd_pcm_format_physical_width(format) <= 16 ?80TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;81}8283static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)84{85return snd_pcm_format_physical_width(format) <= 16 ?86TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;87}8889static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)90{91return snd_pcm_format_physical_width(format) - 1;92}9394static unsigned int get_tdm_ch(unsigned int ch)95{96switch (ch) {97case 1:98case 2:99return TDM_CHANNEL_NUM_2;100case 3:101case 4:102return TDM_CHANNEL_NUM_4;103case 5:104case 6:105case 7:106case 8:107default:108return TDM_CHANNEL_NUM_8;109}110}111112static unsigned int get_tdm_ch_fixup(unsigned int channels)113{114if (channels > 4)115return 8;116else if (channels > 2)117return 4;118else119return 2;120}121122static unsigned int get_tdm_ch_per_sdata(unsigned int mode,123unsigned int channels)124{125if (mode == TDM_OUT_TDM)126return get_tdm_ch_fixup(channels);127else128return 2;129}130131/* interconnection */132enum {133HDMI_CONN_CH0 = 0,134HDMI_CONN_CH1,135HDMI_CONN_CH2,136HDMI_CONN_CH3,137HDMI_CONN_CH4,138HDMI_CONN_CH5,139HDMI_CONN_CH6,140HDMI_CONN_CH7,141};142143static const char *const hdmi_conn_mux_map[] = {144"CH0", "CH1", "CH2", "CH3",145"CH4", "CH5", "CH6", "CH7",146};147148static int hdmi_conn_mux_map_value[] = {149HDMI_CONN_CH0,150HDMI_CONN_CH1,151HDMI_CONN_CH2,152HDMI_CONN_CH3,153HDMI_CONN_CH4,154HDMI_CONN_CH5,155HDMI_CONN_CH6,156HDMI_CONN_CH7,157};158159static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,160AFE_HDMI_CONN0,161HDMI_O_0_SFT,162HDMI_O_0_MASK,163hdmi_conn_mux_map,164hdmi_conn_mux_map_value);165166static const struct snd_kcontrol_new hdmi_ch0_mux_control =167SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);168169static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,170AFE_HDMI_CONN0,171HDMI_O_1_SFT,172HDMI_O_1_MASK,173hdmi_conn_mux_map,174hdmi_conn_mux_map_value);175176static const struct snd_kcontrol_new hdmi_ch1_mux_control =177SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);178179static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,180AFE_HDMI_CONN0,181HDMI_O_2_SFT,182HDMI_O_2_MASK,183hdmi_conn_mux_map,184hdmi_conn_mux_map_value);185186static const struct snd_kcontrol_new hdmi_ch2_mux_control =187SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);188189static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,190AFE_HDMI_CONN0,191HDMI_O_3_SFT,192HDMI_O_3_MASK,193hdmi_conn_mux_map,194hdmi_conn_mux_map_value);195196static const struct snd_kcontrol_new hdmi_ch3_mux_control =197SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);198199static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,200AFE_HDMI_CONN0,201HDMI_O_4_SFT,202HDMI_O_4_MASK,203hdmi_conn_mux_map,204hdmi_conn_mux_map_value);205206static const struct snd_kcontrol_new hdmi_ch4_mux_control =207SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);208209static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,210AFE_HDMI_CONN0,211HDMI_O_5_SFT,212HDMI_O_5_MASK,213hdmi_conn_mux_map,214hdmi_conn_mux_map_value);215216static const struct snd_kcontrol_new hdmi_ch5_mux_control =217SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);218219static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,220AFE_HDMI_CONN0,221HDMI_O_6_SFT,222HDMI_O_6_MASK,223hdmi_conn_mux_map,224hdmi_conn_mux_map_value);225226static const struct snd_kcontrol_new hdmi_ch6_mux_control =227SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);228229static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,230AFE_HDMI_CONN0,231HDMI_O_7_SFT,232HDMI_O_7_MASK,233hdmi_conn_mux_map,234hdmi_conn_mux_map_value);235236static const struct snd_kcontrol_new hdmi_ch7_mux_control =237SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);238239enum {240SUPPLY_SEQ_APLL,241SUPPLY_SEQ_TDM_MCK_EN,242SUPPLY_SEQ_TDM_BCK_EN,243};244245static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,246struct snd_kcontrol *kcontrol,247int event)248{249struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);250struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);251struct mt8183_afe_private *afe_priv = afe->platform_priv;252struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];253254dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",255__func__, w->name, event);256257switch (event) {258case SND_SOC_DAPM_PRE_PMU:259mt8183_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);260break;261case SND_SOC_DAPM_POST_PMD:262mt8183_mck_disable(afe, tdm_priv->bck_id);263break;264default:265break;266}267268return 0;269}270271static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,272struct snd_kcontrol *kcontrol,273int event)274{275struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);276struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);277struct mt8183_afe_private *afe_priv = afe->platform_priv;278struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];279280dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",281__func__, w->name, event);282283switch (event) {284case SND_SOC_DAPM_PRE_PMU:285mt8183_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);286break;287case SND_SOC_DAPM_POST_PMD:288tdm_priv->mclk_rate = 0;289mt8183_mck_disable(afe, tdm_priv->mclk_id);290break;291default:292break;293}294295return 0;296}297298static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {299SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,300&hdmi_ch0_mux_control),301SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,302&hdmi_ch1_mux_control),303SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,304&hdmi_ch2_mux_control),305SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,306&hdmi_ch3_mux_control),307SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,308&hdmi_ch4_mux_control),309SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,310&hdmi_ch5_mux_control),311SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,312&hdmi_ch6_mux_control),313SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,314&hdmi_ch7_mux_control),315316SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),317318SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,319SND_SOC_NOPM, 0, 0,320mtk_tdm_bck_en_event,321SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),322323SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,324SND_SOC_NOPM, 0, 0,325mtk_tdm_mck_en_event,326SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),327};328329static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,330struct snd_soc_dapm_widget *sink)331{332struct snd_soc_dapm_widget *w = sink;333struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);334struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);335struct mt8183_afe_private *afe_priv = afe->platform_priv;336struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];337int cur_apll;338339/* which apll */340cur_apll = mt8183_get_apll_by_name(afe, source->name);341342return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;343}344345static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {346{"HDMI_CH0_MUX", "CH0", "HDMI"},347{"HDMI_CH0_MUX", "CH1", "HDMI"},348{"HDMI_CH0_MUX", "CH2", "HDMI"},349{"HDMI_CH0_MUX", "CH3", "HDMI"},350{"HDMI_CH0_MUX", "CH4", "HDMI"},351{"HDMI_CH0_MUX", "CH5", "HDMI"},352{"HDMI_CH0_MUX", "CH6", "HDMI"},353{"HDMI_CH0_MUX", "CH7", "HDMI"},354355{"HDMI_CH1_MUX", "CH0", "HDMI"},356{"HDMI_CH1_MUX", "CH1", "HDMI"},357{"HDMI_CH1_MUX", "CH2", "HDMI"},358{"HDMI_CH1_MUX", "CH3", "HDMI"},359{"HDMI_CH1_MUX", "CH4", "HDMI"},360{"HDMI_CH1_MUX", "CH5", "HDMI"},361{"HDMI_CH1_MUX", "CH6", "HDMI"},362{"HDMI_CH1_MUX", "CH7", "HDMI"},363364{"HDMI_CH2_MUX", "CH0", "HDMI"},365{"HDMI_CH2_MUX", "CH1", "HDMI"},366{"HDMI_CH2_MUX", "CH2", "HDMI"},367{"HDMI_CH2_MUX", "CH3", "HDMI"},368{"HDMI_CH2_MUX", "CH4", "HDMI"},369{"HDMI_CH2_MUX", "CH5", "HDMI"},370{"HDMI_CH2_MUX", "CH6", "HDMI"},371{"HDMI_CH2_MUX", "CH7", "HDMI"},372373{"HDMI_CH3_MUX", "CH0", "HDMI"},374{"HDMI_CH3_MUX", "CH1", "HDMI"},375{"HDMI_CH3_MUX", "CH2", "HDMI"},376{"HDMI_CH3_MUX", "CH3", "HDMI"},377{"HDMI_CH3_MUX", "CH4", "HDMI"},378{"HDMI_CH3_MUX", "CH5", "HDMI"},379{"HDMI_CH3_MUX", "CH6", "HDMI"},380{"HDMI_CH3_MUX", "CH7", "HDMI"},381382{"HDMI_CH4_MUX", "CH0", "HDMI"},383{"HDMI_CH4_MUX", "CH1", "HDMI"},384{"HDMI_CH4_MUX", "CH2", "HDMI"},385{"HDMI_CH4_MUX", "CH3", "HDMI"},386{"HDMI_CH4_MUX", "CH4", "HDMI"},387{"HDMI_CH4_MUX", "CH5", "HDMI"},388{"HDMI_CH4_MUX", "CH6", "HDMI"},389{"HDMI_CH4_MUX", "CH7", "HDMI"},390391{"HDMI_CH5_MUX", "CH0", "HDMI"},392{"HDMI_CH5_MUX", "CH1", "HDMI"},393{"HDMI_CH5_MUX", "CH2", "HDMI"},394{"HDMI_CH5_MUX", "CH3", "HDMI"},395{"HDMI_CH5_MUX", "CH4", "HDMI"},396{"HDMI_CH5_MUX", "CH5", "HDMI"},397{"HDMI_CH5_MUX", "CH6", "HDMI"},398{"HDMI_CH5_MUX", "CH7", "HDMI"},399400{"HDMI_CH6_MUX", "CH0", "HDMI"},401{"HDMI_CH6_MUX", "CH1", "HDMI"},402{"HDMI_CH6_MUX", "CH2", "HDMI"},403{"HDMI_CH6_MUX", "CH3", "HDMI"},404{"HDMI_CH6_MUX", "CH4", "HDMI"},405{"HDMI_CH6_MUX", "CH5", "HDMI"},406{"HDMI_CH6_MUX", "CH6", "HDMI"},407{"HDMI_CH6_MUX", "CH7", "HDMI"},408409{"HDMI_CH7_MUX", "CH0", "HDMI"},410{"HDMI_CH7_MUX", "CH1", "HDMI"},411{"HDMI_CH7_MUX", "CH2", "HDMI"},412{"HDMI_CH7_MUX", "CH3", "HDMI"},413{"HDMI_CH7_MUX", "CH4", "HDMI"},414{"HDMI_CH7_MUX", "CH5", "HDMI"},415{"HDMI_CH7_MUX", "CH6", "HDMI"},416{"HDMI_CH7_MUX", "CH7", "HDMI"},417418{"TDM", NULL, "HDMI_CH0_MUX"},419{"TDM", NULL, "HDMI_CH1_MUX"},420{"TDM", NULL, "HDMI_CH2_MUX"},421{"TDM", NULL, "HDMI_CH3_MUX"},422{"TDM", NULL, "HDMI_CH4_MUX"},423{"TDM", NULL, "HDMI_CH5_MUX"},424{"TDM", NULL, "HDMI_CH6_MUX"},425{"TDM", NULL, "HDMI_CH7_MUX"},426427{"TDM", NULL, "aud_tdm_clk"},428{"TDM", NULL, "TDM_BCK"},429{"TDM_BCK", NULL, "TDM_MCK"},430{"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},431{"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},432};433434/* dai ops */435static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,436struct mtk_afe_tdm_priv *tdm_priv,437int freq)438{439int apll;440int apll_rate;441442apll = mt8183_get_apll_by_rate(afe, freq);443apll_rate = mt8183_get_apll_rate(afe, apll);444445if (!freq || freq > apll_rate) {446dev_warn(afe->dev,447"%s(), freq(%d Hz) invalid\n", __func__, freq);448return -EINVAL;449}450451if (apll_rate % freq != 0) {452dev_warn(afe->dev,453"%s(), APLL cannot generate %d Hz", __func__, freq);454return -EINVAL;455}456457tdm_priv->mclk_rate = freq;458tdm_priv->mclk_apll = apll;459460return 0;461}462463static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,464struct snd_pcm_hw_params *params,465struct snd_soc_dai *dai)466{467struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);468struct mt8183_afe_private *afe_priv = afe->platform_priv;469int tdm_id = dai->id;470struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];471unsigned int tdm_out_mode = tdm_priv->tdm_out_mode;472unsigned int rate = params_rate(params);473unsigned int channels = params_channels(params);474unsigned int out_channels_per_sdata =475get_tdm_ch_per_sdata(tdm_out_mode, channels);476snd_pcm_format_t format = params_format(params);477unsigned int tdm_con = 0;478479/* calculate mclk_rate, if not set explicitly */480if (!tdm_priv->mclk_rate) {481tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;482mtk_dai_tdm_cal_mclk(afe,483tdm_priv,484tdm_priv->mclk_rate);485}486487/* calculate bck */488tdm_priv->bck_rate = rate *489out_channels_per_sdata *490snd_pcm_format_physical_width(format);491492if (tdm_priv->bck_rate > tdm_priv->mclk_rate)493dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__);494495if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)496dev_warn(afe->dev, "%s(), bck cannot generate", __func__);497498dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n",499__func__,500tdm_id, rate, channels, format,501tdm_priv->mclk_rate, tdm_priv->bck_rate);502dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n",503__func__, out_channels_per_sdata);504505/* set tdm */506if (tdm_priv->bck_invert)507regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,508BCK_INVERSE_MASK_SFT,5090x1 << BCK_INVERSE_SFT);510511if (tdm_priv->lck_invert)512tdm_con |= 1 << LRCK_INVERSE_SFT;513514if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) {515tdm_con |= 1 << DELAY_DATA_SFT;516tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;517} else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) {518tdm_con |= 0 << DELAY_DATA_SFT;519tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;520}521522tdm_con |= 1 << LEFT_ALIGN_SFT;523tdm_con |= get_tdm_wlen(format) << WLEN_SFT;524tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT;525tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;526regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);527528if (out_channels_per_sdata == 2) {529switch (channels) {530case 1:531case 2:532tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;533tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;534tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;535tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;536break;537case 3:538case 4:539tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;540tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;541tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;542tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;543break;544case 5:545case 6:546tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;547tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;548tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;549tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;550break;551case 7:552case 8:553tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;554tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;555tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;556tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;557break;558default:559tdm_con = 0;560}561} else {562tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;563tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;564tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;565tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;566}567568regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);569570regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,571AFE_HDMI_OUT_CH_NUM_MASK_SFT,572channels << AFE_HDMI_OUT_CH_NUM_SFT);573574regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,575AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT,576get_hdmi_wlen(format) << AFE_HDMI_OUT_BIT_WIDTH_SFT);577return 0;578}579580static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,581int cmd,582struct snd_soc_dai *dai)583{584struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);585586switch (cmd) {587case SNDRV_PCM_TRIGGER_START:588case SNDRV_PCM_TRIGGER_RESUME:589/* enable Out control */590regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,591AFE_HDMI_OUT_ON_MASK_SFT,5920x1 << AFE_HDMI_OUT_ON_SFT);593/* enable tdm */594regmap_update_bits(afe->regmap, AFE_TDM_CON1,595TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);596break;597case SNDRV_PCM_TRIGGER_STOP:598case SNDRV_PCM_TRIGGER_SUSPEND:599/* disable tdm */600regmap_update_bits(afe->regmap, AFE_TDM_CON1,601TDM_EN_MASK_SFT, 0);602/* disable Out control */603regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,604AFE_HDMI_OUT_ON_MASK_SFT,6050);606break;607default:608return -EINVAL;609}610611return 0;612}613614static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,615int clk_id, unsigned int freq, int dir)616{617struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);618struct mt8183_afe_private *afe_priv = afe->platform_priv;619struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];620621if (!tdm_priv) {622dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);623return -EINVAL;624}625626if (dir != SND_SOC_CLOCK_OUT) {627dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);628return -EINVAL;629}630631dev_info(afe->dev, "%s(), freq %d\n", __func__, freq);632633return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);634}635636static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)637{638struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);639struct mt8183_afe_private *afe_priv = afe->platform_priv;640struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];641642if (!tdm_priv) {643dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);644return -EINVAL;645}646647/* DAI mode*/648switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {649case SND_SOC_DAIFMT_I2S:650tdm_priv->tdm_out_mode = TDM_OUT_I2S;651break;652case SND_SOC_DAIFMT_DSP_A:653tdm_priv->tdm_out_mode = TDM_OUT_TDM;654break;655default:656tdm_priv->tdm_out_mode = TDM_OUT_I2S;657}658659/* DAI clock inversion*/660switch (fmt & SND_SOC_DAIFMT_INV_MASK) {661case SND_SOC_DAIFMT_NB_NF:662tdm_priv->bck_invert = TDM_BCK_NON_INV;663tdm_priv->lck_invert = TDM_LCK_NON_INV;664break;665case SND_SOC_DAIFMT_NB_IF:666tdm_priv->bck_invert = TDM_BCK_NON_INV;667tdm_priv->lck_invert = TDM_LCK_INV;668break;669case SND_SOC_DAIFMT_IB_NF:670tdm_priv->bck_invert = TDM_BCK_INV;671tdm_priv->lck_invert = TDM_LCK_NON_INV;672break;673case SND_SOC_DAIFMT_IB_IF:674default:675tdm_priv->bck_invert = TDM_BCK_INV;676tdm_priv->lck_invert = TDM_LCK_INV;677break;678}679680return 0;681}682683static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {684.hw_params = mtk_dai_tdm_hw_params,685.trigger = mtk_dai_tdm_trigger,686.set_sysclk = mtk_dai_tdm_set_sysclk,687.set_fmt = mtk_dai_tdm_set_fmt,688};689690/* dai driver */691#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\692SNDRV_PCM_RATE_88200 |\693SNDRV_PCM_RATE_96000 |\694SNDRV_PCM_RATE_176400 |\695SNDRV_PCM_RATE_192000)696697#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\698SNDRV_PCM_FMTBIT_S24_LE |\699SNDRV_PCM_FMTBIT_S32_LE)700701static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {702{703.name = "TDM",704.id = MT8183_DAI_TDM,705.playback = {706.stream_name = "TDM",707.channels_min = 2,708.channels_max = 8,709.rates = MTK_TDM_RATES,710.formats = MTK_TDM_FORMATS,711},712.ops = &mtk_dai_tdm_ops,713},714};715716int mt8183_dai_tdm_register(struct mtk_base_afe *afe)717{718struct mt8183_afe_private *afe_priv = afe->platform_priv;719struct mtk_afe_tdm_priv *tdm_priv;720struct mtk_base_afe_dai *dai;721722dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);723if (!dai)724return -ENOMEM;725726list_add(&dai->list, &afe->sub_dais);727728dai->dai_drivers = mtk_dai_tdm_driver;729dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);730731dai->dapm_widgets = mtk_dai_tdm_widgets;732dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);733dai->dapm_routes = mtk_dai_tdm_routes;734dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);735736tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),737GFP_KERNEL);738if (!tdm_priv)739return -ENOMEM;740741tdm_priv->mclk_multiple = 128;742tdm_priv->bck_id = MT8183_I2S4_BCK;743tdm_priv->mclk_id = MT8183_I2S4_MCK;744745afe_priv->dai_priv[MT8183_DAI_TDM] = tdm_priv;746return 0;747}748749750