| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * MediaTek ALSA SoC Audio DAI eTDM Control |
| * |
| * Copyright (c) 2022 MediaTek Inc. |
| * Author: Bicycle Tsai <bicycle.tsai@mediatek.com> |
| * Trevor Wu <trevor.wu@mediatek.com> |
| * Chun-Chia Chiu <chun-chia.chiu@mediatek.com> |
| */ |
| |
| #include <linux/bitfield.h> |
| #include <linux/pm_runtime.h> |
| #include <linux/regmap.h> |
| #include <sound/pcm_params.h> |
| #include "mt8188-afe-clk.h" |
| #include "mt8188-afe-common.h" |
| #include "mt8188-reg.h" |
| |
| #define MT8188_ETDM_MAX_CHANNELS 16 |
| #define MT8188_ETDM_NORMAL_MAX_BCK_RATE 24576000 |
| #define ETDM_TO_DAI_ID(x) ((x) + MT8188_AFE_IO_ETDM_START) |
| #define ENUM_TO_STR(x) #x |
| |
| enum { |
| SUPPLY_SEQ_APLL, |
| SUPPLY_SEQ_ETDM_MCLK, |
| SUPPLY_SEQ_ETDM_CG, |
| SUPPLY_SEQ_DPTX_EN, |
| SUPPLY_SEQ_ETDM_EN, |
| }; |
| |
| enum { |
| MTK_DAI_ETDM_FORMAT_I2S = 0, |
| MTK_DAI_ETDM_FORMAT_LJ, |
| MTK_DAI_ETDM_FORMAT_RJ, |
| MTK_DAI_ETDM_FORMAT_EIAJ, |
| MTK_DAI_ETDM_FORMAT_DSPA, |
| MTK_DAI_ETDM_FORMAT_DSPB, |
| }; |
| |
| enum { |
| MTK_DAI_ETDM_DATA_ONE_PIN = 0, |
| MTK_DAI_ETDM_DATA_MULTI_PIN, |
| }; |
| |
| enum { |
| ETDM_IN, |
| ETDM_OUT, |
| }; |
| |
| enum { |
| COWORK_ETDM_NONE = 0, |
| COWORK_ETDM_IN1_M = 2, |
| COWORK_ETDM_IN1_S = 3, |
| COWORK_ETDM_IN2_M = 4, |
| COWORK_ETDM_IN2_S = 5, |
| COWORK_ETDM_OUT1_M = 10, |
| COWORK_ETDM_OUT1_S = 11, |
| COWORK_ETDM_OUT2_M = 12, |
| COWORK_ETDM_OUT2_S = 13, |
| COWORK_ETDM_OUT3_M = 14, |
| COWORK_ETDM_OUT3_S = 15, |
| }; |
| |
| enum { |
| ETDM_RELATCH_TIMING_A1A2SYS, |
| ETDM_RELATCH_TIMING_A3SYS, |
| ETDM_RELATCH_TIMING_A4SYS, |
| }; |
| |
| enum { |
| ETDM_SYNC_NONE, |
| ETDM_SYNC_FROM_IN1 = 2, |
| ETDM_SYNC_FROM_IN2 = 4, |
| ETDM_SYNC_FROM_OUT1 = 10, |
| ETDM_SYNC_FROM_OUT2 = 12, |
| ETDM_SYNC_FROM_OUT3 = 14, |
| }; |
| |
| struct etdm_con_reg { |
| unsigned int con0; |
| unsigned int con1; |
| unsigned int con2; |
| unsigned int con3; |
| unsigned int con4; |
| unsigned int con5; |
| }; |
| |
| struct mtk_dai_etdm_rate { |
| unsigned int rate; |
| unsigned int reg_value; |
| }; |
| |
| struct mtk_dai_etdm_priv { |
| unsigned int data_mode; |
| bool slave_mode; |
| bool lrck_inv; |
| bool bck_inv; |
| unsigned int rate; |
| unsigned int format; |
| unsigned int slots; |
| unsigned int lrck_width; |
| unsigned int mclk_freq; |
| unsigned int mclk_fixed_apll; |
| unsigned int mclk_apll; |
| unsigned int mclk_dir; |
| int cowork_source_id; //dai id |
| unsigned int cowork_slv_count; |
| int cowork_slv_id[MT8188_AFE_IO_ETDM_NUM - 1]; //dai_id |
| bool in_disable_ch[MT8188_ETDM_MAX_CHANNELS]; |
| }; |
| |
| static const struct mtk_dai_etdm_rate mt8188_etdm_rates[] = { |
| { .rate = 8000, .reg_value = 0, }, |
| { .rate = 12000, .reg_value = 1, }, |
| { .rate = 16000, .reg_value = 2, }, |
| { .rate = 24000, .reg_value = 3, }, |
| { .rate = 32000, .reg_value = 4, }, |
| { .rate = 48000, .reg_value = 5, }, |
| { .rate = 96000, .reg_value = 7, }, |
| { .rate = 192000, .reg_value = 9, }, |
| { .rate = 384000, .reg_value = 11, }, |
| { .rate = 11025, .reg_value = 16, }, |
| { .rate = 22050, .reg_value = 17, }, |
| { .rate = 44100, .reg_value = 18, }, |
| { .rate = 88200, .reg_value = 19, }, |
| { .rate = 176400, .reg_value = 20, }, |
| { .rate = 352800, .reg_value = 21, }, |
| }; |
| |
| static int get_etdm_fs_timing(unsigned int rate) |
| { |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(mt8188_etdm_rates); i++) |
| if (mt8188_etdm_rates[i].rate == rate) |
| return mt8188_etdm_rates[i].reg_value; |
| |
| return -EINVAL; |
| } |
| |
| static unsigned int get_etdm_ch_fixup(unsigned int channels) |
| { |
| if (channels > 16) |
| return 24; |
| else if (channels > 8) |
| return 16; |
| else if (channels > 4) |
| return 8; |
| else if (channels > 2) |
| return 4; |
| else |
| return 2; |
| } |
| |
| static int get_etdm_reg(unsigned int dai_id, struct etdm_con_reg *etdm_reg) |
| { |
| switch (dai_id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| etdm_reg->con0 = ETDM_IN1_CON0; |
| etdm_reg->con1 = ETDM_IN1_CON1; |
| etdm_reg->con2 = ETDM_IN1_CON2; |
| etdm_reg->con3 = ETDM_IN1_CON3; |
| etdm_reg->con4 = ETDM_IN1_CON4; |
| etdm_reg->con5 = ETDM_IN1_CON5; |
| break; |
| case MT8188_AFE_IO_ETDM2_IN: |
| etdm_reg->con0 = ETDM_IN2_CON0; |
| etdm_reg->con1 = ETDM_IN2_CON1; |
| etdm_reg->con2 = ETDM_IN2_CON2; |
| etdm_reg->con3 = ETDM_IN2_CON3; |
| etdm_reg->con4 = ETDM_IN2_CON4; |
| etdm_reg->con5 = ETDM_IN2_CON5; |
| break; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| etdm_reg->con0 = ETDM_OUT1_CON0; |
| etdm_reg->con1 = ETDM_OUT1_CON1; |
| etdm_reg->con2 = ETDM_OUT1_CON2; |
| etdm_reg->con3 = ETDM_OUT1_CON3; |
| etdm_reg->con4 = ETDM_OUT1_CON4; |
| etdm_reg->con5 = ETDM_OUT1_CON5; |
| break; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| etdm_reg->con0 = ETDM_OUT2_CON0; |
| etdm_reg->con1 = ETDM_OUT2_CON1; |
| etdm_reg->con2 = ETDM_OUT2_CON2; |
| etdm_reg->con3 = ETDM_OUT2_CON3; |
| etdm_reg->con4 = ETDM_OUT2_CON4; |
| etdm_reg->con5 = ETDM_OUT2_CON5; |
| break; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| case MT8188_AFE_IO_DPTX: |
| etdm_reg->con0 = ETDM_OUT3_CON0; |
| etdm_reg->con1 = ETDM_OUT3_CON1; |
| etdm_reg->con2 = ETDM_OUT3_CON2; |
| etdm_reg->con3 = ETDM_OUT3_CON3; |
| etdm_reg->con4 = ETDM_OUT3_CON4; |
| etdm_reg->con5 = ETDM_OUT3_CON5; |
| break; |
| default: |
| return -EINVAL; |
| } |
| return 0; |
| } |
| |
| static int get_etdm_dir(unsigned int dai_id) |
| { |
| switch (dai_id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| case MT8188_AFE_IO_ETDM2_IN: |
| return ETDM_IN; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| case MT8188_AFE_IO_ETDM2_OUT: |
| case MT8188_AFE_IO_ETDM3_OUT: |
| return ETDM_OUT; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int get_etdm_wlen(unsigned int bitwidth) |
| { |
| return bitwidth <= 16 ? 16 : 32; |
| } |
| |
| static bool is_valid_etdm_dai(int dai_id) |
| { |
| switch (dai_id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| fallthrough; |
| case MT8188_AFE_IO_ETDM2_IN: |
| fallthrough; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| fallthrough; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| fallthrough; |
| case MT8188_AFE_IO_DPTX: |
| fallthrough; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| static int is_cowork_mode(struct snd_soc_dai *dai) |
| { |
| struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| |
| if (!is_valid_etdm_dai(dai->id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai->id]; |
| |
| return (etdm_data->cowork_slv_count > 0 || |
| etdm_data->cowork_source_id != COWORK_ETDM_NONE); |
| } |
| |
| static int sync_to_dai_id(int source_sel) |
| { |
| switch (source_sel) { |
| case ETDM_SYNC_FROM_IN1: |
| return MT8188_AFE_IO_ETDM1_IN; |
| case ETDM_SYNC_FROM_IN2: |
| return MT8188_AFE_IO_ETDM2_IN; |
| case ETDM_SYNC_FROM_OUT1: |
| return MT8188_AFE_IO_ETDM1_OUT; |
| case ETDM_SYNC_FROM_OUT2: |
| return MT8188_AFE_IO_ETDM2_OUT; |
| case ETDM_SYNC_FROM_OUT3: |
| return MT8188_AFE_IO_ETDM3_OUT; |
| default: |
| return 0; |
| } |
| } |
| |
| static int get_etdm_cowork_master_id(struct snd_soc_dai *dai) |
| { |
| struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| int dai_id; |
| |
| if (!is_valid_etdm_dai(dai->id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai->id]; |
| dai_id = etdm_data->cowork_source_id; |
| |
| if (dai_id == COWORK_ETDM_NONE) |
| dai_id = dai->id; |
| |
| return dai_id; |
| } |
| |
| static int mtk_dai_etdm_get_cg_id_by_dai_id(int dai_id) |
| { |
| switch (dai_id) { |
| case MT8188_AFE_IO_DPTX: |
| return MT8188_CLK_AUD_HDMI_OUT; |
| case MT8188_AFE_IO_ETDM1_IN: |
| return MT8188_CLK_AUD_TDM_IN; |
| case MT8188_AFE_IO_ETDM2_IN: |
| return MT8188_CLK_AUD_I2SIN; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| return MT8188_CLK_AUD_TDM_OUT; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| return MT8188_CLK_AUD_I2S_OUT; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| return MT8188_CLK_AUD_HDMI_OUT; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int mtk_dai_etdm_get_clk_id_by_dai_id(int dai_id) |
| { |
| switch (dai_id) { |
| case MT8188_AFE_IO_DPTX: |
| return MT8188_CLK_TOP_DPTX_M_SEL; |
| case MT8188_AFE_IO_ETDM1_IN: |
| return MT8188_CLK_TOP_I2SI1_M_SEL; |
| case MT8188_AFE_IO_ETDM2_IN: |
| return MT8188_CLK_TOP_I2SI2_M_SEL; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| return MT8188_CLK_TOP_I2SO1_M_SEL; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| return MT8188_CLK_TOP_I2SO2_M_SEL; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int mtk_dai_etdm_get_clkdiv_id_by_dai_id(int dai_id) |
| { |
| switch (dai_id) { |
| case MT8188_AFE_IO_DPTX: |
| return MT8188_CLK_TOP_APLL12_DIV9; |
| case MT8188_AFE_IO_ETDM1_IN: |
| return MT8188_CLK_TOP_APLL12_DIV0; |
| case MT8188_AFE_IO_ETDM2_IN: |
| return MT8188_CLK_TOP_APLL12_DIV1; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| return MT8188_CLK_TOP_APLL12_DIV2; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| return MT8188_CLK_TOP_APLL12_DIV3; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int get_etdm_id_by_name(struct mtk_base_afe *afe, |
| const char *name) |
| { |
| if (!strncmp(name, "ETDM1_IN", strlen("ETDM1_IN"))) |
| return MT8188_AFE_IO_ETDM1_IN; |
| else if (!strncmp(name, "ETDM2_IN", strlen("ETDM2_IN"))) |
| return MT8188_AFE_IO_ETDM2_IN; |
| else if (!strncmp(name, "ETDM1_OUT", strlen("ETDM1_OUT"))) |
| return MT8188_AFE_IO_ETDM1_OUT; |
| else if (!strncmp(name, "ETDM2_OUT", strlen("ETDM2_OUT"))) |
| return MT8188_AFE_IO_ETDM2_OUT; |
| else if (!strncmp(name, "ETDM3_OUT", strlen("ETDM3_OUT"))) |
| return MT8188_AFE_IO_ETDM3_OUT; |
| else if (!strncmp(name, "DPTX", strlen("DPTX"))) |
| return MT8188_AFE_IO_ETDM3_OUT; |
| else |
| return -EINVAL; |
| } |
| |
| static struct mtk_dai_etdm_priv *get_etdm_priv_by_name(struct mtk_base_afe *afe, |
| const char *name) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| int dai_id = get_etdm_id_by_name(afe, name); |
| |
| if (dai_id < MT8188_AFE_IO_ETDM_START || |
| dai_id >= MT8188_AFE_IO_ETDM_END) |
| return NULL; |
| |
| return afe_priv->dai_priv[dai_id]; |
| } |
| |
| static int mtk_dai_etdm_enable_mclk(struct mtk_base_afe *afe, int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| struct etdm_con_reg etdm_reg; |
| unsigned int val = 0; |
| unsigned int mask; |
| int clkmux_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id); |
| int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id); |
| int apll_clk_id; |
| int apll; |
| int ret; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| apll = etdm_data->mclk_apll; |
| apll_clk_id = mt8188_afe_get_mclk_source_clk_id(apll); |
| |
| if (clkmux_id < 0 || clkdiv_id < 0) |
| return -EINVAL; |
| |
| if (apll_clk_id < 0) |
| return apll_clk_id; |
| |
| ret = get_etdm_reg(dai_id, &etdm_reg); |
| if (ret < 0) |
| return ret; |
| |
| mask = ETDM_CON1_MCLK_OUTPUT; |
| if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT) |
| val = ETDM_CON1_MCLK_OUTPUT; |
| regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val); |
| |
| /* enable parent clock before select apll*/ |
| mt8188_afe_enable_clk(afe, afe_priv->clk[clkmux_id]); |
| |
| /* select apll */ |
| ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[clkmux_id], |
| afe_priv->clk[apll_clk_id]); |
| if (ret) |
| return ret; |
| |
| /* set rate */ |
| ret = mt8188_afe_set_clk_rate(afe, afe_priv->clk[clkdiv_id], |
| etdm_data->mclk_freq); |
| |
| mt8188_afe_enable_clk(afe, afe_priv->clk[clkdiv_id]); |
| |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_disable_mclk(struct mtk_base_afe *afe, int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| int clkmux_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id); |
| int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id); |
| |
| if (clkmux_id < 0 || clkdiv_id < 0) |
| return -EINVAL; |
| |
| mt8188_afe_disable_clk(afe, afe_priv->clk[clkdiv_id]); |
| mt8188_afe_disable_clk(afe, afe_priv->clk[clkmux_id]); |
| |
| return 0; |
| } |
| |
| static int mtk_afe_etdm_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_dai_etdm_priv *etdm_priv; |
| int cur_apll; |
| int need_apll; |
| |
| etdm_priv = get_etdm_priv_by_name(afe, w->name); |
| if (!etdm_priv) { |
| dev_dbg(afe->dev, "etdm_priv == NULL\n"); |
| return 0; |
| } |
| |
| cur_apll = mt8188_get_apll_by_name(afe, source->name); |
| need_apll = mt8188_get_apll_by_rate(afe, etdm_priv->rate); |
| |
| return (need_apll == cur_apll) ? 1 : 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_dai_etdm_priv *etdm_priv; |
| int cur_apll; |
| |
| etdm_priv = get_etdm_priv_by_name(afe, w->name); |
| |
| cur_apll = mt8188_get_apll_by_name(afe, source->name); |
| |
| return (etdm_priv->mclk_apll == cur_apll) ? 1 : 0; |
| } |
| |
| static int mtk_etdm_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 mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_priv; |
| int mclk_id; |
| |
| mclk_id = get_etdm_id_by_name(afe, source->name); |
| if (mclk_id < 0) { |
| dev_dbg(afe->dev, "mclk_id < 0\n"); |
| return 0; |
| } |
| |
| etdm_priv = get_etdm_priv_by_name(afe, w->name); |
| if (!etdm_priv) { |
| dev_dbg(afe->dev, "etdm_priv == NULL\n"); |
| return 0; |
| } |
| |
| if (get_etdm_id_by_name(afe, sink->name) == mclk_id) |
| return !!(etdm_priv->mclk_freq > 0); |
| |
| if (etdm_priv->cowork_source_id == mclk_id) { |
| etdm_priv = afe_priv->dai_priv[mclk_id]; |
| return !!(etdm_priv->mclk_freq > 0); |
| } |
| |
| return 0; |
| } |
| |
| static int mtk_etdm_cowork_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 mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_priv; |
| int source_id; |
| int i; |
| |
| source_id = get_etdm_id_by_name(afe, source->name); |
| if (source_id < 0) { |
| dev_dbg(afe->dev, "%s() source_id < 0\n", __func__); |
| return 0; |
| } |
| |
| etdm_priv = get_etdm_priv_by_name(afe, w->name); |
| if (!etdm_priv) { |
| dev_dbg(afe->dev, "%s() etdm_priv == NULL\n", __func__); |
| return 0; |
| } |
| |
| if (etdm_priv->cowork_source_id != COWORK_ETDM_NONE) { |
| if (etdm_priv->cowork_source_id == source_id) |
| return 1; |
| |
| etdm_priv = afe_priv->dai_priv[etdm_priv->cowork_source_id]; |
| for (i = 0; i < etdm_priv->cowork_slv_count; i++) { |
| if (etdm_priv->cowork_slv_id[i] == source_id) |
| return 1; |
| } |
| } else { |
| for (i = 0; i < etdm_priv->cowork_slv_count; i++) { |
| if (etdm_priv->cowork_slv_id[i] == source_id) |
| return 1; |
| } |
| } |
| |
| 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 (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0) |
| mt8188_apll1_enable(afe); |
| else |
| mt8188_apll2_enable(afe); |
| break; |
| case SND_SOC_DAPM_POST_PMD: |
| if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0) |
| mt8188_apll1_disable(afe); |
| else |
| mt8188_apll2_disable(afe); |
| break; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| static int mtk_etdm_mclk_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); |
| int mclk_id = get_etdm_id_by_name(afe, w->name); |
| |
| if (mclk_id < 0) { |
| dev_dbg(afe->dev, "%s() mclk_id < 0\n", __func__); |
| return 0; |
| } |
| |
| dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", |
| __func__, w->name, event); |
| |
| switch (event) { |
| case SND_SOC_DAPM_PRE_PMU: |
| mtk_dai_etdm_enable_mclk(afe, mclk_id); |
| break; |
| case SND_SOC_DAPM_POST_PMD: |
| mtk_dai_etdm_disable_mclk(afe, mclk_id); |
| break; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| static int mtk_dptx_mclk_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: |
| mtk_dai_etdm_enable_mclk(afe, MT8188_AFE_IO_DPTX); |
| break; |
| case SND_SOC_DAPM_POST_PMD: |
| mtk_dai_etdm_disable_mclk(afe, MT8188_AFE_IO_DPTX); |
| break; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| static int mtk_etdm_cg_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 mt8188_afe_private *afe_priv = afe->platform_priv; |
| int etdm_id; |
| int cg_id; |
| |
| etdm_id = get_etdm_id_by_name(afe, w->name); |
| if (etdm_id < 0) { |
| dev_dbg(afe->dev, "%s() etdm_id < 0\n", __func__); |
| return 0; |
| } |
| |
| cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(etdm_id); |
| if (cg_id < 0) { |
| dev_dbg(afe->dev, "%s() cg_id < 0\n", __func__); |
| return 0; |
| } |
| |
| dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", |
| __func__, w->name, event); |
| |
| switch (event) { |
| case SND_SOC_DAPM_PRE_PMU: |
| mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]); |
| break; |
| case SND_SOC_DAPM_POST_PMD: |
| mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]); |
| break; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| static int mtk_etdm3_cg_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 mt8188_afe_private *afe_priv = afe->platform_priv; |
| |
| dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", |
| __func__, w->name, event); |
| |
| switch (event) { |
| case SND_SOC_DAPM_PRE_PMU: |
| mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_HDMI_OUT]); |
| break; |
| case SND_SOC_DAPM_POST_PMD: |
| mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_HDMI_OUT]); |
| break; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o048_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN48, 20, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN48, 22, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN48_1, 14, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN48_2, 6, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o049_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN49, 21, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN49, 23, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN49_1, 15, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN49_2, 7, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o050_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN50, 24, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN50_1, 16, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o051_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN51, 25, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN51_1, 17, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o052_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN52, 26, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN52_1, 18, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o053_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN53, 27, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN53_1, 19, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o054_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN54, 28, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN54_1, 20, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o055_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN55, 29, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN55_1, 21, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o056_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN56, 30, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN56_1, 22, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o057_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN57, 31, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN57_1, 23, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o058_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN58_1, 0, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN58_1, 24, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o059_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN59_1, 1, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN59_1, 25, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o060_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN60_1, 2, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN60_1, 26, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o061_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN61_1, 3, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN61_1, 27, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o062_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN62_1, 4, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN62_1, 28, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o063_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN63_1, 5, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN63_1, 29, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o072_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN72, 20, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN72, 22, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN72_1, 14, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN72_2, 6, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o073_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN73, 21, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN73, 23, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN73_1, 15, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN73_2, 7, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o074_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN74, 24, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN74_1, 16, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o075_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN75, 25, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN75_1, 17, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o076_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN76, 26, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN76_1, 18, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o077_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN77, 27, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN77_1, 19, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o078_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN78, 28, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN78_1, 20, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o079_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN79, 29, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN79_1, 21, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o080_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN80, 30, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN80_1, 22, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o081_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN81, 31, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN81_1, 23, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o082_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN82_1, 0, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN82_1, 24, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o083_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN83_1, 1, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN83_1, 25, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o084_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN84_1, 2, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN84_1, 26, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o085_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN85_1, 3, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN85_1, 27, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o086_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN86_1, 4, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN86_1, 28, 1, 0), |
| }; |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_o087_mix[] = { |
| SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN87_1, 5, 1, 0), |
| SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN87_1, 29, 1, 0), |
| }; |
| |
| static const char * const mt8188_etdm_clk_src_sel_text[] = { |
| "26m", |
| "a1sys_a2sys", |
| "a3sys", |
| "a4sys", |
| }; |
| |
| static SOC_ENUM_SINGLE_EXT_DECL(etdmout_clk_src_enum, |
| mt8188_etdm_clk_src_sel_text); |
| |
| static const char * const hdmitx_dptx_mux_map[] = { |
| "Disconnect", "Connect", |
| }; |
| |
| static int hdmitx_dptx_mux_map_value[] = { |
| 0, 1, |
| }; |
| |
| /* HDMI_OUT_MUX */ |
| static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum, |
| SND_SOC_NOPM, |
| 0, |
| 1, |
| hdmitx_dptx_mux_map, |
| hdmitx_dptx_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_out_mux_control = |
| SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum); |
| |
| /* DPTX_OUT_MUX */ |
| static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum, |
| SND_SOC_NOPM, |
| 0, |
| 1, |
| hdmitx_dptx_mux_map, |
| hdmitx_dptx_mux_map_value); |
| |
| static const struct snd_kcontrol_new dptx_out_mux_control = |
| SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum); |
| |
| /* HDMI_CH0_MUX ~ HDMI_CH7_MUX */ |
| static const char *const afe_conn_hdmi_mux_map[] = { |
| "CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", |
| }; |
| |
| static int afe_conn_hdmi_mux_map_value[] = { |
| 0, 1, 2, 3, 4, 5, 6, 7, |
| }; |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 0, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch0_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 4, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch1_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 8, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch2_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 12, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch3_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 16, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch4_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 20, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch5_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 24, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch6_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum); |
| |
| static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum, |
| AFE_TDMOUT_CONN0, |
| 28, |
| 0xf, |
| afe_conn_hdmi_mux_map, |
| afe_conn_hdmi_mux_map_value); |
| |
| static const struct snd_kcontrol_new hdmi_ch7_mux_control = |
| SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum); |
| |
| static int mt8188_etdm_clk_src_sel_put(struct snd_kcontrol *kcontrol, |
| struct snd_ctl_elem_value *ucontrol) |
| { |
| struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); |
| unsigned int source = ucontrol->value.enumerated.item[0]; |
| unsigned int val; |
| unsigned int old_val; |
| unsigned int mask; |
| unsigned int reg; |
| |
| if (source >= e->items) |
| return -EINVAL; |
| |
| if (!strcmp(kcontrol->id.name, "ETDM_OUT1_Clock_Source")) { |
| reg = ETDM_OUT1_CON4; |
| mask = ETDM_OUT_CON4_CLOCK_MASK; |
| val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source); |
| } else if (!strcmp(kcontrol->id.name, "ETDM_OUT2_Clock_Source")) { |
| reg = ETDM_OUT2_CON4; |
| mask = ETDM_OUT_CON4_CLOCK_MASK; |
| val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source); |
| } else if (!strcmp(kcontrol->id.name, "ETDM_OUT3_Clock_Source")) { |
| reg = ETDM_OUT3_CON4; |
| mask = ETDM_OUT_CON4_CLOCK_MASK; |
| val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source); |
| } else if (!strcmp(kcontrol->id.name, "ETDM_IN1_Clock_Source")) { |
| reg = ETDM_IN1_CON2; |
| mask = ETDM_IN_CON2_CLOCK_MASK; |
| val = FIELD_PREP(ETDM_IN_CON2_CLOCK_MASK, source); |
| } else if (!strcmp(kcontrol->id.name, "ETDM_IN2_Clock_Source")) { |
| reg = ETDM_IN2_CON2; |
| mask = ETDM_IN_CON2_CLOCK_MASK; |
| val = FIELD_PREP(ETDM_IN_CON2_CLOCK_MASK, source); |
| } else { |
| return -EINVAL; |
| } |
| |
| regmap_read(afe->regmap, reg, &old_val); |
| old_val &= mask; |
| if (old_val == val) |
| return 0; |
| |
| regmap_update_bits(afe->regmap, reg, mask, val); |
| |
| return 1; |
| } |
| |
| static int mt8188_etdm_clk_src_sel_get(struct snd_kcontrol *kcontrol, |
| struct snd_ctl_elem_value *ucontrol) |
| { |
| struct snd_soc_component *component = |
| snd_soc_kcontrol_component(kcontrol); |
| struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); |
| unsigned int value; |
| unsigned int reg; |
| unsigned int mask; |
| unsigned int shift; |
| |
| if (!strcmp(kcontrol->id.name, "ETDM_OUT1_Clock_Source")) { |
| reg = ETDM_OUT1_CON4; |
| mask = ETDM_OUT_CON4_CLOCK_MASK; |
| shift = ETDM_OUT_CON4_CLOCK_SHIFT; |
| } else if (!strcmp(kcontrol->id.name, "ETDM_OUT2_Clock_Source")) { |
| reg = ETDM_OUT2_CON4; |
| mask = ETDM_OUT_CON4_CLOCK_MASK; |
| shift = ETDM_OUT_CON4_CLOCK_SHIFT; |
| } else if (!strcmp(kcontrol->id.name, "ETDM_OUT3_Clock_Source")) { |
| reg = ETDM_OUT3_CON4; |
| mask = ETDM_OUT_CON4_CLOCK_MASK; |
| shift = ETDM_OUT_CON4_CLOCK_SHIFT; |
| } else if (!strcmp(kcontrol->id.name, "ETDM_IN1_Clock_Source")) { |
| reg = ETDM_IN1_CON2; |
| mask = ETDM_IN_CON2_CLOCK_MASK; |
| shift = ETDM_IN_CON2_CLOCK_SHIFT; |
| } else if (!strcmp(kcontrol->id.name, "ETDM_IN2_Clock_Source")) { |
| reg = ETDM_IN2_CON2; |
| mask = ETDM_IN_CON2_CLOCK_MASK; |
| shift = ETDM_IN_CON2_CLOCK_SHIFT; |
| } else { |
| return -EINVAL; |
| } |
| |
| regmap_read(afe->regmap, reg, &value); |
| |
| value &= mask; |
| value >>= shift; |
| ucontrol->value.enumerated.item[0] = value; |
| return 0; |
| } |
| |
| static const struct snd_kcontrol_new mtk_dai_etdm_controls[] = { |
| SOC_ENUM_EXT("ETDM_OUT1_Clock_Source", etdmout_clk_src_enum, |
| mt8188_etdm_clk_src_sel_get, |
| mt8188_etdm_clk_src_sel_put), |
| SOC_ENUM_EXT("ETDM_OUT2_Clock_Source", etdmout_clk_src_enum, |
| mt8188_etdm_clk_src_sel_get, |
| mt8188_etdm_clk_src_sel_put), |
| SOC_ENUM_EXT("ETDM_OUT3_Clock_Source", etdmout_clk_src_enum, |
| mt8188_etdm_clk_src_sel_get, |
| mt8188_etdm_clk_src_sel_put), |
| SOC_ENUM_EXT("ETDM_IN1_Clock_Source", etdmout_clk_src_enum, |
| mt8188_etdm_clk_src_sel_get, |
| mt8188_etdm_clk_src_sel_put), |
| SOC_ENUM_EXT("ETDM_IN2_Clock_Source", etdmout_clk_src_enum, |
| mt8188_etdm_clk_src_sel_get, |
| mt8188_etdm_clk_src_sel_put), |
| }; |
| |
| static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { |
| /* eTDM_IN2 */ |
| SND_SOC_DAPM_MIXER("I012", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I013", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I014", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I015", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I016", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I017", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I018", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I019", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I188", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I189", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I190", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I191", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I192", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I193", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I194", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I195", SND_SOC_NOPM, 0, 0, NULL, 0), |
| |
| /* eTDM_IN1 */ |
| SND_SOC_DAPM_MIXER("I072", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I073", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I074", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I075", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I076", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I077", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I078", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I079", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I080", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I081", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I082", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I083", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I084", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I085", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I086", SND_SOC_NOPM, 0, 0, NULL, 0), |
| SND_SOC_DAPM_MIXER("I087", SND_SOC_NOPM, 0, 0, NULL, 0), |
| |
| /* eTDM_OUT2 */ |
| SND_SOC_DAPM_MIXER("O048", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o048_mix, ARRAY_SIZE(mtk_dai_etdm_o048_mix)), |
| SND_SOC_DAPM_MIXER("O049", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o049_mix, ARRAY_SIZE(mtk_dai_etdm_o049_mix)), |
| SND_SOC_DAPM_MIXER("O050", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o050_mix, ARRAY_SIZE(mtk_dai_etdm_o050_mix)), |
| SND_SOC_DAPM_MIXER("O051", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o051_mix, ARRAY_SIZE(mtk_dai_etdm_o051_mix)), |
| SND_SOC_DAPM_MIXER("O052", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o052_mix, ARRAY_SIZE(mtk_dai_etdm_o052_mix)), |
| SND_SOC_DAPM_MIXER("O053", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o053_mix, ARRAY_SIZE(mtk_dai_etdm_o053_mix)), |
| SND_SOC_DAPM_MIXER("O054", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o054_mix, ARRAY_SIZE(mtk_dai_etdm_o054_mix)), |
| SND_SOC_DAPM_MIXER("O055", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o055_mix, ARRAY_SIZE(mtk_dai_etdm_o055_mix)), |
| SND_SOC_DAPM_MIXER("O056", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o056_mix, ARRAY_SIZE(mtk_dai_etdm_o056_mix)), |
| SND_SOC_DAPM_MIXER("O057", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o057_mix, ARRAY_SIZE(mtk_dai_etdm_o057_mix)), |
| SND_SOC_DAPM_MIXER("O058", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o058_mix, ARRAY_SIZE(mtk_dai_etdm_o058_mix)), |
| SND_SOC_DAPM_MIXER("O059", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o059_mix, ARRAY_SIZE(mtk_dai_etdm_o059_mix)), |
| SND_SOC_DAPM_MIXER("O060", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o060_mix, ARRAY_SIZE(mtk_dai_etdm_o060_mix)), |
| SND_SOC_DAPM_MIXER("O061", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o061_mix, ARRAY_SIZE(mtk_dai_etdm_o061_mix)), |
| SND_SOC_DAPM_MIXER("O062", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o062_mix, ARRAY_SIZE(mtk_dai_etdm_o062_mix)), |
| SND_SOC_DAPM_MIXER("O063", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o063_mix, ARRAY_SIZE(mtk_dai_etdm_o063_mix)), |
| |
| /* eTDM_OUT1 */ |
| SND_SOC_DAPM_MIXER("O072", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o072_mix, ARRAY_SIZE(mtk_dai_etdm_o072_mix)), |
| SND_SOC_DAPM_MIXER("O073", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o073_mix, ARRAY_SIZE(mtk_dai_etdm_o073_mix)), |
| SND_SOC_DAPM_MIXER("O074", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o074_mix, ARRAY_SIZE(mtk_dai_etdm_o074_mix)), |
| SND_SOC_DAPM_MIXER("O075", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o075_mix, ARRAY_SIZE(mtk_dai_etdm_o075_mix)), |
| SND_SOC_DAPM_MIXER("O076", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o076_mix, ARRAY_SIZE(mtk_dai_etdm_o076_mix)), |
| SND_SOC_DAPM_MIXER("O077", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o077_mix, ARRAY_SIZE(mtk_dai_etdm_o077_mix)), |
| SND_SOC_DAPM_MIXER("O078", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o078_mix, ARRAY_SIZE(mtk_dai_etdm_o078_mix)), |
| SND_SOC_DAPM_MIXER("O079", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o079_mix, ARRAY_SIZE(mtk_dai_etdm_o079_mix)), |
| SND_SOC_DAPM_MIXER("O080", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o080_mix, ARRAY_SIZE(mtk_dai_etdm_o080_mix)), |
| SND_SOC_DAPM_MIXER("O081", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o081_mix, ARRAY_SIZE(mtk_dai_etdm_o081_mix)), |
| SND_SOC_DAPM_MIXER("O082", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o082_mix, ARRAY_SIZE(mtk_dai_etdm_o082_mix)), |
| SND_SOC_DAPM_MIXER("O083", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o083_mix, ARRAY_SIZE(mtk_dai_etdm_o083_mix)), |
| SND_SOC_DAPM_MIXER("O084", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o084_mix, ARRAY_SIZE(mtk_dai_etdm_o084_mix)), |
| SND_SOC_DAPM_MIXER("O085", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o085_mix, ARRAY_SIZE(mtk_dai_etdm_o085_mix)), |
| SND_SOC_DAPM_MIXER("O086", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o086_mix, ARRAY_SIZE(mtk_dai_etdm_o086_mix)), |
| SND_SOC_DAPM_MIXER("O087", SND_SOC_NOPM, 0, 0, |
| mtk_dai_etdm_o087_mix, ARRAY_SIZE(mtk_dai_etdm_o087_mix)), |
| |
| /* eTDM_OUT3 */ |
| SND_SOC_DAPM_MUX("HDMI_OUT_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_out_mux_control), |
| SND_SOC_DAPM_MUX("DPTX_OUT_MUX", SND_SOC_NOPM, 0, 0, |
| &dptx_out_mux_control), |
| |
| SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch0_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch1_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch2_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch3_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch4_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch5_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch6_mux_control), |
| SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0, |
| &hdmi_ch7_mux_control), |
| |
| /* mclk en */ |
| SND_SOC_DAPM_SUPPLY_S("ETDM1_IN_MCLK", SUPPLY_SEQ_ETDM_MCLK, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_mclk_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM2_IN_MCLK", SUPPLY_SEQ_ETDM_MCLK, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_mclk_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM1_OUT_MCLK", SUPPLY_SEQ_ETDM_MCLK, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_mclk_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM2_OUT_MCLK", SUPPLY_SEQ_ETDM_MCLK, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_mclk_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("DPTX_MCLK", SUPPLY_SEQ_ETDM_MCLK, |
| SND_SOC_NOPM, 0, 0, |
| mtk_dptx_mclk_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| |
| /* cg */ |
| SND_SOC_DAPM_SUPPLY_S("ETDM1_IN_CG", SUPPLY_SEQ_ETDM_CG, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_cg_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM2_IN_CG", SUPPLY_SEQ_ETDM_CG, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_cg_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM1_OUT_CG", SUPPLY_SEQ_ETDM_CG, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_cg_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM2_OUT_CG", SUPPLY_SEQ_ETDM_CG, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm_cg_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| SND_SOC_DAPM_SUPPLY_S("ETDM3_OUT_CG", SUPPLY_SEQ_ETDM_CG, |
| SND_SOC_NOPM, 0, 0, |
| mtk_etdm3_cg_event, |
| SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
| |
| /* en */ |
| SND_SOC_DAPM_SUPPLY_S("ETDM1_IN_EN", SUPPLY_SEQ_ETDM_EN, |
| ETDM_IN1_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), |
| SND_SOC_DAPM_SUPPLY_S("ETDM2_IN_EN", SUPPLY_SEQ_ETDM_EN, |
| ETDM_IN2_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), |
| SND_SOC_DAPM_SUPPLY_S("ETDM1_OUT_EN", SUPPLY_SEQ_ETDM_EN, |
| ETDM_OUT1_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), |
| SND_SOC_DAPM_SUPPLY_S("ETDM2_OUT_EN", SUPPLY_SEQ_ETDM_EN, |
| ETDM_OUT2_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), |
| SND_SOC_DAPM_SUPPLY_S("ETDM3_OUT_EN", SUPPLY_SEQ_ETDM_EN, |
| ETDM_OUT3_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), |
| SND_SOC_DAPM_SUPPLY_S("DPTX_EN", SUPPLY_SEQ_DPTX_EN, |
| AFE_DPTX_CON, AFE_DPTX_CON_ON_SHIFT, 0, NULL, 0), |
| |
| /* 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), |
| |
| SND_SOC_DAPM_INPUT("ETDM_INPUT"), |
| SND_SOC_DAPM_OUTPUT("ETDM_OUTPUT"), |
| }; |
| |
| static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { |
| /* mclk */ |
| {"ETDM1_IN", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM1_IN", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM1_IN", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM1_IN", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, |
| |
| {"ETDM2_IN", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM2_IN", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM2_IN", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM2_IN", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, |
| |
| {"ETDM1_OUT", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM1_OUT", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM1_OUT", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM1_OUT", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, |
| |
| {"ETDM2_OUT", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM2_OUT", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM2_OUT", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, |
| {"ETDM2_OUT", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, |
| |
| {"DPTX", NULL, "DPTX_MCLK"}, |
| |
| {"ETDM1_IN_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, |
| {"ETDM1_IN_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, |
| |
| {"ETDM2_IN_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, |
| {"ETDM2_IN_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, |
| |
| {"ETDM1_OUT_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, |
| {"ETDM1_OUT_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, |
| |
| {"ETDM2_OUT_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, |
| {"ETDM2_OUT_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, |
| |
| {"DPTX_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, |
| {"DPTX_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, |
| |
| /* cg */ |
| {"ETDM1_IN", NULL, "ETDM1_IN_CG"}, |
| {"ETDM1_IN", NULL, "ETDM2_IN_CG", mtk_etdm_cowork_connect}, |
| {"ETDM1_IN", NULL, "ETDM1_OUT_CG", mtk_etdm_cowork_connect}, |
| {"ETDM1_IN", NULL, "ETDM2_OUT_CG", mtk_etdm_cowork_connect}, |
| |
| {"ETDM2_IN", NULL, "ETDM1_IN_CG", mtk_etdm_cowork_connect}, |
| {"ETDM2_IN", NULL, "ETDM2_IN_CG"}, |
| {"ETDM2_IN", NULL, "ETDM1_OUT_CG", mtk_etdm_cowork_connect}, |
| {"ETDM2_IN", NULL, "ETDM2_OUT_CG", mtk_etdm_cowork_connect}, |
| |
| {"ETDM1_OUT", NULL, "ETDM1_IN_CG", mtk_etdm_cowork_connect}, |
| {"ETDM1_OUT", NULL, "ETDM2_IN_CG", mtk_etdm_cowork_connect}, |
| {"ETDM1_OUT", NULL, "ETDM1_OUT_CG"}, |
| {"ETDM1_OUT", NULL, "ETDM2_OUT_CG", mtk_etdm_cowork_connect}, |
| |
| {"ETDM2_OUT", NULL, "ETDM1_IN_CG", mtk_etdm_cowork_connect}, |
| {"ETDM2_OUT", NULL, "ETDM2_IN_CG", mtk_etdm_cowork_connect}, |
| {"ETDM2_OUT", NULL, "ETDM1_OUT_CG", mtk_etdm_cowork_connect}, |
| {"ETDM2_OUT", NULL, "ETDM2_OUT_CG"}, |
| |
| {"ETDM3_OUT", NULL, "ETDM3_OUT_CG"}, |
| {"DPTX", NULL, "ETDM3_OUT_CG"}, |
| |
| /* en */ |
| {"ETDM1_IN", NULL, "ETDM1_IN_EN"}, |
| {"ETDM1_IN", NULL, "ETDM2_IN_EN", mtk_etdm_cowork_connect}, |
| {"ETDM1_IN", NULL, "ETDM1_OUT_EN", mtk_etdm_cowork_connect}, |
| {"ETDM1_IN", NULL, "ETDM2_OUT_EN", mtk_etdm_cowork_connect}, |
| |
| {"ETDM2_IN", NULL, "ETDM1_IN_EN", mtk_etdm_cowork_connect}, |
| {"ETDM2_IN", NULL, "ETDM2_IN_EN"}, |
| {"ETDM2_IN", NULL, "ETDM1_OUT_EN", mtk_etdm_cowork_connect}, |
| {"ETDM2_IN", NULL, "ETDM2_OUT_EN", mtk_etdm_cowork_connect}, |
| |
| {"ETDM1_OUT", NULL, "ETDM1_IN_EN", mtk_etdm_cowork_connect}, |
| {"ETDM1_OUT", NULL, "ETDM2_IN_EN", mtk_etdm_cowork_connect}, |
| {"ETDM1_OUT", NULL, "ETDM1_OUT_EN"}, |
| {"ETDM1_OUT", NULL, "ETDM2_OUT_EN", mtk_etdm_cowork_connect}, |
| |
| {"ETDM2_OUT", NULL, "ETDM1_IN_EN", mtk_etdm_cowork_connect}, |
| {"ETDM2_OUT", NULL, "ETDM2_IN_EN", mtk_etdm_cowork_connect}, |
| {"ETDM2_OUT", NULL, "ETDM1_OUT_EN", mtk_etdm_cowork_connect}, |
| {"ETDM2_OUT", NULL, "ETDM2_OUT_EN"}, |
| |
| {"ETDM3_OUT", NULL, "ETDM3_OUT_EN"}, |
| {"DPTX", NULL, "ETDM3_OUT_EN"}, |
| {"DPTX", NULL, "DPTX_EN"}, |
| |
| {"ETDM1_IN_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, |
| {"ETDM1_IN_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, |
| |
| {"ETDM2_IN_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, |
| {"ETDM2_IN_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, |
| |
| {"ETDM1_OUT_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, |
| {"ETDM1_OUT_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, |
| |
| {"ETDM2_OUT_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, |
| {"ETDM2_OUT_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, |
| |
| {"ETDM3_OUT_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, |
| {"ETDM3_OUT_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, |
| |
| {"I012", NULL, "ETDM2_IN"}, |
| {"I013", NULL, "ETDM2_IN"}, |
| {"I014", NULL, "ETDM2_IN"}, |
| {"I015", NULL, "ETDM2_IN"}, |
| {"I016", NULL, "ETDM2_IN"}, |
| {"I017", NULL, "ETDM2_IN"}, |
| {"I018", NULL, "ETDM2_IN"}, |
| {"I019", NULL, "ETDM2_IN"}, |
| {"I188", NULL, "ETDM2_IN"}, |
| {"I189", NULL, "ETDM2_IN"}, |
| {"I190", NULL, "ETDM2_IN"}, |
| {"I191", NULL, "ETDM2_IN"}, |
| {"I192", NULL, "ETDM2_IN"}, |
| {"I193", NULL, "ETDM2_IN"}, |
| {"I194", NULL, "ETDM2_IN"}, |
| {"I195", NULL, "ETDM2_IN"}, |
| |
| {"I072", NULL, "ETDM1_IN"}, |
| {"I073", NULL, "ETDM1_IN"}, |
| {"I074", NULL, "ETDM1_IN"}, |
| {"I075", NULL, "ETDM1_IN"}, |
| {"I076", NULL, "ETDM1_IN"}, |
| {"I077", NULL, "ETDM1_IN"}, |
| {"I078", NULL, "ETDM1_IN"}, |
| {"I079", NULL, "ETDM1_IN"}, |
| {"I080", NULL, "ETDM1_IN"}, |
| {"I081", NULL, "ETDM1_IN"}, |
| {"I082", NULL, "ETDM1_IN"}, |
| {"I083", NULL, "ETDM1_IN"}, |
| {"I084", NULL, "ETDM1_IN"}, |
| {"I085", NULL, "ETDM1_IN"}, |
| {"I086", NULL, "ETDM1_IN"}, |
| {"I087", NULL, "ETDM1_IN"}, |
| |
| {"UL8", NULL, "ETDM1_IN"}, |
| {"UL3", NULL, "ETDM2_IN"}, |
| |
| {"ETDM2_OUT", NULL, "O048"}, |
| {"ETDM2_OUT", NULL, "O049"}, |
| {"ETDM2_OUT", NULL, "O050"}, |
| {"ETDM2_OUT", NULL, "O051"}, |
| {"ETDM2_OUT", NULL, "O052"}, |
| {"ETDM2_OUT", NULL, "O053"}, |
| {"ETDM2_OUT", NULL, "O054"}, |
| {"ETDM2_OUT", NULL, "O055"}, |
| {"ETDM2_OUT", NULL, "O056"}, |
| {"ETDM2_OUT", NULL, "O057"}, |
| {"ETDM2_OUT", NULL, "O058"}, |
| {"ETDM2_OUT", NULL, "O059"}, |
| {"ETDM2_OUT", NULL, "O060"}, |
| {"ETDM2_OUT", NULL, "O061"}, |
| {"ETDM2_OUT", NULL, "O062"}, |
| {"ETDM2_OUT", NULL, "O063"}, |
| |
| {"ETDM1_OUT", NULL, "O072"}, |
| {"ETDM1_OUT", NULL, "O073"}, |
| {"ETDM1_OUT", NULL, "O074"}, |
| {"ETDM1_OUT", NULL, "O075"}, |
| {"ETDM1_OUT", NULL, "O076"}, |
| {"ETDM1_OUT", NULL, "O077"}, |
| {"ETDM1_OUT", NULL, "O078"}, |
| {"ETDM1_OUT", NULL, "O079"}, |
| {"ETDM1_OUT", NULL, "O080"}, |
| {"ETDM1_OUT", NULL, "O081"}, |
| {"ETDM1_OUT", NULL, "O082"}, |
| {"ETDM1_OUT", NULL, "O083"}, |
| {"ETDM1_OUT", NULL, "O084"}, |
| {"ETDM1_OUT", NULL, "O085"}, |
| {"ETDM1_OUT", NULL, "O086"}, |
| {"ETDM1_OUT", NULL, "O087"}, |
| |
| {"O048", "I020 Switch", "I020"}, |
| {"O049", "I021 Switch", "I021"}, |
| |
| {"O048", "I022 Switch", "I022"}, |
| {"O049", "I023 Switch", "I023"}, |
| {"O050", "I024 Switch", "I024"}, |
| {"O051", "I025 Switch", "I025"}, |
| {"O052", "I026 Switch", "I026"}, |
| {"O053", "I027 Switch", "I027"}, |
| {"O054", "I028 Switch", "I028"}, |
| {"O055", "I029 Switch", "I029"}, |
| {"O056", "I030 Switch", "I030"}, |
| {"O057", "I031 Switch", "I031"}, |
| {"O058", "I032 Switch", "I032"}, |
| {"O059", "I033 Switch", "I033"}, |
| {"O060", "I034 Switch", "I034"}, |
| {"O061", "I035 Switch", "I035"}, |
| {"O062", "I036 Switch", "I036"}, |
| {"O063", "I037 Switch", "I037"}, |
| |
| {"O048", "I046 Switch", "I046"}, |
| {"O049", "I047 Switch", "I047"}, |
| {"O050", "I048 Switch", "I048"}, |
| {"O051", "I049 Switch", "I049"}, |
| {"O052", "I050 Switch", "I050"}, |
| {"O053", "I051 Switch", "I051"}, |
| {"O054", "I052 Switch", "I052"}, |
| {"O055", "I053 Switch", "I053"}, |
| {"O056", "I054 Switch", "I054"}, |
| {"O057", "I055 Switch", "I055"}, |
| {"O058", "I056 Switch", "I056"}, |
| {"O059", "I057 Switch", "I057"}, |
| {"O060", "I058 Switch", "I058"}, |
| {"O061", "I059 Switch", "I059"}, |
| {"O062", "I060 Switch", "I060"}, |
| {"O063", "I061 Switch", "I061"}, |
| |
| {"O048", "I070 Switch", "I070"}, |
| {"O049", "I071 Switch", "I071"}, |
| |
| {"O072", "I020 Switch", "I020"}, |
| {"O073", "I021 Switch", "I021"}, |
| |
| {"O072", "I022 Switch", "I022"}, |
| {"O073", "I023 Switch", "I023"}, |
| {"O074", "I024 Switch", "I024"}, |
| {"O075", "I025 Switch", "I025"}, |
| {"O076", "I026 Switch", "I026"}, |
| {"O077", "I027 Switch", "I027"}, |
| {"O078", "I028 Switch", "I028"}, |
| {"O079", "I029 Switch", "I029"}, |
| {"O080", "I030 Switch", "I030"}, |
| {"O081", "I031 Switch", "I031"}, |
| {"O082", "I032 Switch", "I032"}, |
| {"O083", "I033 Switch", "I033"}, |
| {"O084", "I034 Switch", "I034"}, |
| {"O085", "I035 Switch", "I035"}, |
| {"O086", "I036 Switch", "I036"}, |
| {"O087", "I037 Switch", "I037"}, |
| |
| {"O072", "I046 Switch", "I046"}, |
| {"O073", "I047 Switch", "I047"}, |
| {"O074", "I048 Switch", "I048"}, |
| {"O075", "I049 Switch", "I049"}, |
| {"O076", "I050 Switch", "I050"}, |
| {"O077", "I051 Switch", "I051"}, |
| {"O078", "I052 Switch", "I052"}, |
| {"O079", "I053 Switch", "I053"}, |
| {"O080", "I054 Switch", "I054"}, |
| {"O081", "I055 Switch", "I055"}, |
| {"O082", "I056 Switch", "I056"}, |
| {"O083", "I057 Switch", "I057"}, |
| {"O084", "I058 Switch", "I058"}, |
| {"O085", "I059 Switch", "I059"}, |
| {"O086", "I060 Switch", "I060"}, |
| {"O087", "I061 Switch", "I061"}, |
| |
| {"O072", "I070 Switch", "I070"}, |
| {"O073", "I071 Switch", "I071"}, |
| |
| {"HDMI_CH0_MUX", "CH0", "DL10"}, |
| {"HDMI_CH0_MUX", "CH1", "DL10"}, |
| {"HDMI_CH0_MUX", "CH2", "DL10"}, |
| {"HDMI_CH0_MUX", "CH3", "DL10"}, |
| {"HDMI_CH0_MUX", "CH4", "DL10"}, |
| {"HDMI_CH0_MUX", "CH5", "DL10"}, |
| {"HDMI_CH0_MUX", "CH6", "DL10"}, |
| {"HDMI_CH0_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH1_MUX", "CH0", "DL10"}, |
| {"HDMI_CH1_MUX", "CH1", "DL10"}, |
| {"HDMI_CH1_MUX", "CH2", "DL10"}, |
| {"HDMI_CH1_MUX", "CH3", "DL10"}, |
| {"HDMI_CH1_MUX", "CH4", "DL10"}, |
| {"HDMI_CH1_MUX", "CH5", "DL10"}, |
| {"HDMI_CH1_MUX", "CH6", "DL10"}, |
| {"HDMI_CH1_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH2_MUX", "CH0", "DL10"}, |
| {"HDMI_CH2_MUX", "CH1", "DL10"}, |
| {"HDMI_CH2_MUX", "CH2", "DL10"}, |
| {"HDMI_CH2_MUX", "CH3", "DL10"}, |
| {"HDMI_CH2_MUX", "CH4", "DL10"}, |
| {"HDMI_CH2_MUX", "CH5", "DL10"}, |
| {"HDMI_CH2_MUX", "CH6", "DL10"}, |
| {"HDMI_CH2_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH3_MUX", "CH0", "DL10"}, |
| {"HDMI_CH3_MUX", "CH1", "DL10"}, |
| {"HDMI_CH3_MUX", "CH2", "DL10"}, |
| {"HDMI_CH3_MUX", "CH3", "DL10"}, |
| {"HDMI_CH3_MUX", "CH4", "DL10"}, |
| {"HDMI_CH3_MUX", "CH5", "DL10"}, |
| {"HDMI_CH3_MUX", "CH6", "DL10"}, |
| {"HDMI_CH3_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH4_MUX", "CH0", "DL10"}, |
| {"HDMI_CH4_MUX", "CH1", "DL10"}, |
| {"HDMI_CH4_MUX", "CH2", "DL10"}, |
| {"HDMI_CH4_MUX", "CH3", "DL10"}, |
| {"HDMI_CH4_MUX", "CH4", "DL10"}, |
| {"HDMI_CH4_MUX", "CH5", "DL10"}, |
| {"HDMI_CH4_MUX", "CH6", "DL10"}, |
| {"HDMI_CH4_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH5_MUX", "CH0", "DL10"}, |
| {"HDMI_CH5_MUX", "CH1", "DL10"}, |
| {"HDMI_CH5_MUX", "CH2", "DL10"}, |
| {"HDMI_CH5_MUX", "CH3", "DL10"}, |
| {"HDMI_CH5_MUX", "CH4", "DL10"}, |
| {"HDMI_CH5_MUX", "CH5", "DL10"}, |
| {"HDMI_CH5_MUX", "CH6", "DL10"}, |
| {"HDMI_CH5_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH6_MUX", "CH0", "DL10"}, |
| {"HDMI_CH6_MUX", "CH1", "DL10"}, |
| {"HDMI_CH6_MUX", "CH2", "DL10"}, |
| {"HDMI_CH6_MUX", "CH3", "DL10"}, |
| {"HDMI_CH6_MUX", "CH4", "DL10"}, |
| {"HDMI_CH6_MUX", "CH5", "DL10"}, |
| {"HDMI_CH6_MUX", "CH6", "DL10"}, |
| {"HDMI_CH6_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_CH7_MUX", "CH0", "DL10"}, |
| {"HDMI_CH7_MUX", "CH1", "DL10"}, |
| {"HDMI_CH7_MUX", "CH2", "DL10"}, |
| {"HDMI_CH7_MUX", "CH3", "DL10"}, |
| {"HDMI_CH7_MUX", "CH4", "DL10"}, |
| {"HDMI_CH7_MUX", "CH5", "DL10"}, |
| {"HDMI_CH7_MUX", "CH6", "DL10"}, |
| {"HDMI_CH7_MUX", "CH7", "DL10"}, |
| |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH0_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH1_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH2_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH3_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH4_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH5_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH6_MUX"}, |
| {"HDMI_OUT_MUX", "Connect", "HDMI_CH7_MUX"}, |
| |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH0_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH1_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH2_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH3_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH4_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH5_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH6_MUX"}, |
| {"DPTX_OUT_MUX", "Connect", "HDMI_CH7_MUX"}, |
| |
| {"ETDM3_OUT", NULL, "HDMI_OUT_MUX"}, |
| {"DPTX", NULL, "DPTX_OUT_MUX"}, |
| |
| {"ETDM_OUTPUT", NULL, "DPTX"}, |
| {"ETDM_OUTPUT", NULL, "ETDM1_OUT"}, |
| {"ETDM_OUTPUT", NULL, "ETDM2_OUT"}, |
| {"ETDM_OUTPUT", NULL, "ETDM3_OUT"}, |
| {"ETDM1_IN", NULL, "ETDM_INPUT"}, |
| {"ETDM2_IN", NULL, "ETDM_INPUT"}, |
| }; |
| |
| static int etdm_cowork_slv_sel(int id, int slave_mode) |
| { |
| if (slave_mode) { |
| switch (id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| return COWORK_ETDM_IN1_S; |
| case MT8188_AFE_IO_ETDM2_IN: |
| return COWORK_ETDM_IN2_S; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| return COWORK_ETDM_OUT1_S; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| return COWORK_ETDM_OUT2_S; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| return COWORK_ETDM_OUT3_S; |
| default: |
| return -EINVAL; |
| } |
| } else { |
| switch (id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| return COWORK_ETDM_IN1_M; |
| case MT8188_AFE_IO_ETDM2_IN: |
| return COWORK_ETDM_IN2_M; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| return COWORK_ETDM_OUT1_M; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| return COWORK_ETDM_OUT2_M; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| return COWORK_ETDM_OUT3_M; |
| default: |
| return -EINVAL; |
| } |
| } |
| } |
| |
| static int etdm_cowork_sync_sel(int id) |
| { |
| switch (id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| return ETDM_SYNC_FROM_IN1; |
| case MT8188_AFE_IO_ETDM2_IN: |
| return ETDM_SYNC_FROM_IN2; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| return ETDM_SYNC_FROM_OUT1; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| return ETDM_SYNC_FROM_OUT2; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| return ETDM_SYNC_FROM_OUT3; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int mt8188_etdm_sync_mode_slv(struct mtk_base_afe *afe, int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| unsigned int reg = 0; |
| unsigned int mask; |
| unsigned int val; |
| int cowork_source_sel; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| cowork_source_sel = etdm_cowork_slv_sel(etdm_data->cowork_source_id, |
| true); |
| if (cowork_source_sel < 0) |
| return cowork_source_sel; |
| |
| switch (dai_id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| reg = ETDM_COWORK_CON1; |
| mask = ETDM_IN1_SLAVE_SEL_MASK; |
| val = FIELD_PREP(ETDM_IN1_SLAVE_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM2_IN: |
| reg = ETDM_COWORK_CON2; |
| mask = ETDM_IN2_SLAVE_SEL_MASK; |
| val = FIELD_PREP(ETDM_IN2_SLAVE_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| reg = ETDM_COWORK_CON0; |
| mask = ETDM_OUT1_SLAVE_SEL_MASK; |
| val = FIELD_PREP(ETDM_OUT1_SLAVE_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| reg = ETDM_COWORK_CON2; |
| mask = ETDM_OUT2_SLAVE_SEL_MASK; |
| val = FIELD_PREP(ETDM_OUT2_SLAVE_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| reg = ETDM_COWORK_CON2; |
| mask = ETDM_OUT3_SLAVE_SEL_MASK; |
| val = FIELD_PREP(ETDM_OUT3_SLAVE_SEL_MASK, cowork_source_sel); |
| break; |
| default: |
| return 0; |
| } |
| |
| regmap_update_bits(afe->regmap, reg, mask, val); |
| |
| return 0; |
| } |
| |
| static int mt8188_etdm_sync_mode_mst(struct mtk_base_afe *afe, int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| struct etdm_con_reg etdm_reg; |
| unsigned int reg = 0; |
| unsigned int mask; |
| unsigned int val; |
| int cowork_source_sel; |
| int ret; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| cowork_source_sel = etdm_cowork_sync_sel(etdm_data->cowork_source_id); |
| if (cowork_source_sel < 0) |
| return cowork_source_sel; |
| |
| switch (dai_id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| reg = ETDM_COWORK_CON1; |
| mask = ETDM_IN1_SYNC_SEL_MASK; |
| val = FIELD_PREP(ETDM_IN1_SYNC_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM2_IN: |
| reg = ETDM_COWORK_CON2; |
| mask = ETDM_IN2_SYNC_SEL_MASK; |
| val = FIELD_PREP(ETDM_IN2_SYNC_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM1_OUT: |
| reg = ETDM_COWORK_CON0; |
| mask = ETDM_OUT1_SYNC_SEL_MASK; |
| val = FIELD_PREP(ETDM_OUT1_SYNC_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM2_OUT: |
| reg = ETDM_COWORK_CON2; |
| mask = ETDM_OUT2_SYNC_SEL_MASK; |
| val = FIELD_PREP(ETDM_OUT2_SYNC_SEL_MASK, cowork_source_sel); |
| break; |
| case MT8188_AFE_IO_ETDM3_OUT: |
| reg = ETDM_COWORK_CON2; |
| mask = ETDM_OUT3_SYNC_SEL_MASK; |
| val = FIELD_PREP(ETDM_OUT3_SYNC_SEL_MASK, cowork_source_sel); |
| break; |
| default: |
| return 0; |
| } |
| |
| ret = get_etdm_reg(dai_id, &etdm_reg); |
| if (ret < 0) |
| return ret; |
| |
| regmap_update_bits(afe->regmap, reg, mask, val); |
| |
| regmap_set_bits(afe->regmap, etdm_reg.con0, ETDM_CON0_SYNC_MODE); |
| |
| return 0; |
| } |
| |
| static int mt8188_etdm_sync_mode_configure(struct mtk_base_afe *afe, int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| if (etdm_data->cowork_source_id == COWORK_ETDM_NONE) |
| return 0; |
| |
| if (etdm_data->slave_mode) |
| mt8188_etdm_sync_mode_slv(afe, dai_id); |
| else |
| mt8188_etdm_sync_mode_mst(afe, dai_id); |
| |
| return 0; |
| } |
| |
| /* dai ops */ |
| static int mtk_dai_etdm_fifo_mode(struct mtk_base_afe *afe, |
| int dai_id, unsigned int rate) |
| { |
| unsigned int mode = 0; |
| unsigned int reg = 0; |
| unsigned int val = 0; |
| unsigned int mask = (ETDM_IN_AFIFO_MODE_MASK | ETDM_IN_USE_AFIFO); |
| |
| if (rate != 0) |
| mode = mt8188_afe_fs_timing(rate); |
| |
| switch (dai_id) { |
| case MT8188_AFE_IO_ETDM1_IN: |
| reg = ETDM_IN1_AFIFO_CON; |
| if (rate == 0) |
| mode = MT8188_ETDM_IN1_1X_EN; |
| break; |
| case MT8188_AFE_IO_ETDM2_IN: |
| reg = ETDM_IN2_AFIFO_CON; |
| if (rate == 0) |
| mode = MT8188_ETDM_IN2_1X_EN; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| val = (mode | ETDM_IN_USE_AFIFO); |
| |
| regmap_update_bits(afe->regmap, reg, mask, val); |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_in_configure(struct mtk_base_afe *afe, |
| unsigned int rate, |
| unsigned int channels, |
| int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| struct etdm_con_reg etdm_reg; |
| bool slave_mode; |
| unsigned int data_mode; |
| unsigned int lrck_width; |
| unsigned int val = 0; |
| unsigned int mask = 0; |
| int ret; |
| int i; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| slave_mode = etdm_data->slave_mode; |
| data_mode = etdm_data->data_mode; |
| lrck_width = etdm_data->lrck_width; |
| |
| dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n", |
| __func__, rate, channels, dai_id); |
| |
| ret = get_etdm_reg(dai_id, &etdm_reg); |
| if (ret < 0) |
| return ret; |
| |
| /* afifo */ |
| if (slave_mode) |
| mtk_dai_etdm_fifo_mode(afe, dai_id, 0); |
| else |
| mtk_dai_etdm_fifo_mode(afe, dai_id, rate); |
| |
| /* con1 */ |
| if (lrck_width > 0) { |
| mask |= (ETDM_IN_CON1_LRCK_AUTO_MODE | |
| ETDM_IN_CON1_LRCK_WIDTH_MASK); |
| val |= FIELD_PREP(ETDM_IN_CON1_LRCK_WIDTH_MASK, lrck_width - 1); |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| /* con2 */ |
| if (!slave_mode) { |
| mask |= ETDM_IN_CON2_UPDATE_GAP_MASK; |
| if (rate == 352800 || rate == 384000) |
| val |= FIELD_PREP(ETDM_IN_CON2_UPDATE_GAP_MASK, 4); |
| else |
| val |= FIELD_PREP(ETDM_IN_CON2_UPDATE_GAP_MASK, 3); |
| } |
| mask |= (ETDM_IN_CON2_MULTI_IP_2CH_MODE | |
| ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK); |
| if (data_mode == MTK_DAI_ETDM_DATA_MULTI_PIN) { |
| val |= ETDM_IN_CON2_MULTI_IP_2CH_MODE | |
| FIELD_PREP(ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK, channels - 1); |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con2, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| /* con3 */ |
| mask |= ETDM_IN_CON3_DISABLE_OUT_MASK; |
| for (i = 0; i < channels; i += 2) { |
| if (etdm_data->in_disable_ch[i] && |
| etdm_data->in_disable_ch[i + 1]) |
| val |= ETDM_IN_CON3_DISABLE_OUT(i >> 1); |
| } |
| if (!slave_mode) { |
| mask |= ETDM_IN_CON3_FS_MASK; |
| val |= FIELD_PREP(ETDM_IN_CON3_FS_MASK, get_etdm_fs_timing(rate)); |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con3, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| /* con4 */ |
| mask |= (ETDM_IN_CON4_MASTER_LRCK_INV | ETDM_IN_CON4_MASTER_BCK_INV | |
| ETDM_IN_CON4_SLAVE_LRCK_INV | ETDM_IN_CON4_SLAVE_BCK_INV); |
| if (slave_mode) { |
| if (etdm_data->lrck_inv) |
| val |= ETDM_IN_CON4_SLAVE_LRCK_INV; |
| if (etdm_data->bck_inv) |
| val |= ETDM_IN_CON4_SLAVE_BCK_INV; |
| } else { |
| if (etdm_data->lrck_inv) |
| val |= ETDM_IN_CON4_MASTER_LRCK_INV; |
| if (etdm_data->bck_inv) |
| val |= ETDM_IN_CON4_MASTER_BCK_INV; |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con4, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| /* con5 */ |
| mask |= ETDM_IN_CON5_LR_SWAP_MASK; |
| mask |= ETDM_IN_CON5_ENABLE_ODD_MASK; |
| for (i = 0; i < channels; i += 2) { |
| if (etdm_data->in_disable_ch[i] && |
| !etdm_data->in_disable_ch[i + 1]) { |
| val |= ETDM_IN_CON5_LR_SWAP(i >> 1); |
| val |= ETDM_IN_CON5_ENABLE_ODD(i >> 1); |
| } else if (!etdm_data->in_disable_ch[i] && |
| etdm_data->in_disable_ch[i + 1]) { |
| val |= ETDM_IN_CON5_ENABLE_ODD(i >> 1); |
| } |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con5, mask, val); |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_out_configure(struct mtk_base_afe *afe, |
| unsigned int rate, |
| unsigned int channels, |
| int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| struct etdm_con_reg etdm_reg; |
| bool slave_mode; |
| unsigned int lrck_width; |
| unsigned int val = 0; |
| unsigned int mask = 0; |
| int fs = 0; |
| int ret; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| slave_mode = etdm_data->slave_mode; |
| lrck_width = etdm_data->lrck_width; |
| |
| dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n", |
| __func__, rate, channels, dai_id); |
| |
| ret = get_etdm_reg(dai_id, &etdm_reg); |
| if (ret < 0) |
| return ret; |
| |
| /* con0 */ |
| mask = ETDM_OUT_CON0_RELATCH_DOMAIN_MASK; |
| val = FIELD_PREP(ETDM_OUT_CON0_RELATCH_DOMAIN_MASK, |
| ETDM_RELATCH_TIMING_A1A2SYS); |
| regmap_update_bits(afe->regmap, etdm_reg.con0, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| /* con1 */ |
| if (lrck_width > 0) { |
| mask |= (ETDM_OUT_CON1_LRCK_AUTO_MODE | |
| ETDM_OUT_CON1_LRCK_WIDTH_MASK); |
| val |= FIELD_PREP(ETDM_OUT_CON1_LRCK_WIDTH_MASK, lrck_width - 1); |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| if (!slave_mode) { |
| /* con4 */ |
| mask |= ETDM_OUT_CON4_FS_MASK; |
| val |= FIELD_PREP(ETDM_OUT_CON4_FS_MASK, get_etdm_fs_timing(rate)); |
| } |
| |
| mask |= ETDM_OUT_CON4_RELATCH_EN_MASK; |
| if (dai_id == MT8188_AFE_IO_ETDM1_OUT) |
| fs = MT8188_ETDM_OUT1_1X_EN; |
| else if (dai_id == MT8188_AFE_IO_ETDM2_OUT) |
| fs = MT8188_ETDM_OUT2_1X_EN; |
| |
| val |= FIELD_PREP(ETDM_OUT_CON4_RELATCH_EN_MASK, fs); |
| |
| regmap_update_bits(afe->regmap, etdm_reg.con4, mask, val); |
| |
| mask = 0; |
| val = 0; |
| |
| /* con5 */ |
| mask |= (ETDM_OUT_CON5_MASTER_LRCK_INV | ETDM_OUT_CON5_MASTER_BCK_INV | |
| ETDM_OUT_CON5_SLAVE_LRCK_INV | ETDM_OUT_CON5_SLAVE_BCK_INV); |
| if (slave_mode) { |
| if (etdm_data->lrck_inv) |
| val |= ETDM_OUT_CON5_SLAVE_LRCK_INV; |
| if (etdm_data->bck_inv) |
| val |= ETDM_OUT_CON5_SLAVE_BCK_INV; |
| } else { |
| if (etdm_data->lrck_inv) |
| val |= ETDM_OUT_CON5_MASTER_LRCK_INV; |
| if (etdm_data->bck_inv) |
| val |= ETDM_OUT_CON5_MASTER_BCK_INV; |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con5, mask, val); |
| |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_configure(struct mtk_base_afe *afe, |
| unsigned int rate, |
| unsigned int channels, |
| unsigned int bit_width, |
| int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| struct etdm_con_reg etdm_reg; |
| bool slave_mode; |
| unsigned int etdm_channels; |
| unsigned int val = 0; |
| unsigned int mask = 0; |
| unsigned int bck; |
| unsigned int wlen = get_etdm_wlen(bit_width); |
| int ret; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| slave_mode = etdm_data->slave_mode; |
| etdm_data->rate = rate; |
| |
| ret = get_etdm_reg(dai_id, &etdm_reg); |
| if (ret < 0) |
| return ret; |
| |
| dev_dbg(afe->dev, "%s fmt %u data %u lrck %d-%u bck %d, slv %u\n", |
| __func__, etdm_data->format, etdm_data->data_mode, |
| etdm_data->lrck_inv, etdm_data->lrck_width, etdm_data->bck_inv, |
| etdm_data->slave_mode); |
| dev_dbg(afe->dev, "%s rate %u channels %u bitwidth %u, id %d\n", |
| __func__, rate, channels, bit_width, dai_id); |
| |
| etdm_channels = (etdm_data->data_mode == MTK_DAI_ETDM_DATA_ONE_PIN) ? |
| get_etdm_ch_fixup(channels) : 2; |
| |
| bck = rate * etdm_channels * wlen; |
| if (bck > MT8188_ETDM_NORMAL_MAX_BCK_RATE) { |
| dev_err(afe->dev, "%s bck rate %u not support\n", |
| __func__, bck); |
| return -EINVAL; |
| } |
| |
| /* con0 */ |
| mask |= ETDM_CON0_BIT_LEN_MASK; |
| val |= FIELD_PREP(ETDM_CON0_BIT_LEN_MASK, bit_width - 1); |
| mask |= ETDM_CON0_WORD_LEN_MASK; |
| val |= FIELD_PREP(ETDM_CON0_WORD_LEN_MASK, wlen - 1); |
| mask |= ETDM_CON0_FORMAT_MASK; |
| val |= FIELD_PREP(ETDM_CON0_FORMAT_MASK, etdm_data->format); |
| mask |= ETDM_CON0_CH_NUM_MASK; |
| val |= FIELD_PREP(ETDM_CON0_CH_NUM_MASK, etdm_channels - 1); |
| |
| mask |= ETDM_CON0_SLAVE_MODE; |
| if (slave_mode) { |
| if (dai_id == MT8188_AFE_IO_ETDM1_OUT) { |
| dev_err(afe->dev, "%s id %d only support master mode\n", |
| __func__, dai_id); |
| return -EINVAL; |
| } |
| val |= ETDM_CON0_SLAVE_MODE; |
| } |
| regmap_update_bits(afe->regmap, etdm_reg.con0, mask, val); |
| |
| if (get_etdm_dir(dai_id) == ETDM_IN) |
| mtk_dai_etdm_in_configure(afe, rate, channels, dai_id); |
| else |
| mtk_dai_etdm_out_configure(afe, rate, channels, dai_id); |
| |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, |
| struct snd_pcm_hw_params *params, |
| struct snd_soc_dai *dai) |
| { |
| unsigned int rate = params_rate(params); |
| unsigned int bit_width = params_width(params); |
| unsigned int channels = params_channels(params); |
| struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *mst_etdm_data; |
| int mst_dai_id; |
| int slv_dai_id; |
| int ret; |
| int i; |
| |
| dev_dbg(afe->dev, "%s '%s' period %u-%u\n", |
| __func__, snd_pcm_stream_str(substream), |
| params_period_size(params), params_periods(params)); |
| |
| if (is_cowork_mode(dai)) { |
| mst_dai_id = get_etdm_cowork_master_id(dai); |
| if (!is_valid_etdm_dai(mst_dai_id)) |
| return -EINVAL; |
| |
| mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; |
| if (mst_etdm_data->slots) |
| channels = mst_etdm_data->slots; |
| |
| ret = mtk_dai_etdm_configure(afe, rate, channels, |
| bit_width, mst_dai_id); |
| if (ret) |
| return ret; |
| |
| for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { |
| slv_dai_id = mst_etdm_data->cowork_slv_id[i]; |
| ret = mtk_dai_etdm_configure(afe, rate, channels, |
| bit_width, slv_dai_id); |
| if (ret) |
| return ret; |
| |
| ret = mt8188_etdm_sync_mode_configure(afe, slv_dai_id); |
| if (ret) |
| return ret; |
| } |
| } else { |
| if (!is_valid_etdm_dai(dai->id)) |
| return -EINVAL; |
| mst_etdm_data = afe_priv->dai_priv[dai->id]; |
| if (mst_etdm_data->slots) |
| channels = mst_etdm_data->slots; |
| |
| ret = mtk_dai_etdm_configure(afe, rate, channels, |
| bit_width, dai->id); |
| if (ret) |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_cal_mclk(struct mtk_base_afe *afe, int freq, int dai_id) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| int apll_rate; |
| int apll; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| if (freq == 0) { |
| etdm_data->mclk_freq = freq; |
| return 0; |
| } |
| |
| if (etdm_data->mclk_fixed_apll == 0) |
| apll = mt8188_afe_get_default_mclk_source_by_rate(freq); |
| else |
| apll = etdm_data->mclk_apll; |
| |
| apll_rate = mt8188_afe_get_mclk_source_rate(afe, apll); |
| |
| if (freq > apll_rate) { |
| dev_err(afe->dev, "freq %d > apll rate %d\n", freq, apll_rate); |
| return -EINVAL; |
| } |
| |
| if (apll_rate % freq != 0) { |
| dev_err(afe->dev, "APLL%d cannot generate freq Hz\n", apll); |
| return -EINVAL; |
| } |
| |
| if (etdm_data->mclk_fixed_apll == 0) |
| etdm_data->mclk_apll = apll; |
| etdm_data->mclk_freq = freq; |
| |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_set_sysclk(struct snd_soc_dai *dai, |
| int clk_id, unsigned int freq, int dir) |
| { |
| struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| int dai_id; |
| |
| dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n", |
| __func__, dai->id, freq, dir); |
| if (is_cowork_mode(dai)) |
| dai_id = get_etdm_cowork_master_id(dai); |
| else |
| dai_id = dai->id; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| etdm_data->mclk_dir = dir; |
| return mtk_dai_etdm_cal_mclk(afe, freq, dai_id); |
| } |
| |
| static int mtk_dai_etdm_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 = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| int dai_id; |
| |
| if (is_cowork_mode(dai)) |
| dai_id = get_etdm_cowork_master_id(dai); |
| else |
| dai_id = dai->id; |
| |
| if (!is_valid_etdm_dai(dai_id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| dev_dbg(dai->dev, "%s id %d slot_width %d\n", |
| __func__, dai->id, slot_width); |
| |
| etdm_data->slots = slots; |
| etdm_data->lrck_width = slot_width; |
| return 0; |
| } |
| |
| static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
| { |
| struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| |
| if (!is_valid_etdm_dai(dai->id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai->id]; |
| |
| switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| case SND_SOC_DAIFMT_I2S: |
| etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S; |
| break; |
| case SND_SOC_DAIFMT_LEFT_J: |
| etdm_data->format = MTK_DAI_ETDM_FORMAT_LJ; |
| break; |
| case SND_SOC_DAIFMT_RIGHT_J: |
| etdm_data->format = MTK_DAI_ETDM_FORMAT_RJ; |
| break; |
| case SND_SOC_DAIFMT_DSP_A: |
| etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA; |
| break; |
| case SND_SOC_DAIFMT_DSP_B: |
| etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
| case SND_SOC_DAIFMT_NB_NF: |
| etdm_data->bck_inv = false; |
| etdm_data->lrck_inv = false; |
| break; |
| case SND_SOC_DAIFMT_NB_IF: |
| etdm_data->bck_inv = false; |
| etdm_data->lrck_inv = true; |
| break; |
| case SND_SOC_DAIFMT_IB_NF: |
| etdm_data->bck_inv = true; |
| etdm_data->lrck_inv = false; |
| break; |
| case SND_SOC_DAIFMT_IB_IF: |
| etdm_data->bck_inv = true; |
| etdm_data->lrck_inv = true; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
| case SND_SOC_DAIFMT_BC_FC: |
| etdm_data->slave_mode = true; |
| break; |
| case SND_SOC_DAIFMT_BP_FP: |
| etdm_data->slave_mode = false; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static unsigned int mtk_dai_get_dptx_ch_en(unsigned int channel) |
| { |
| switch (channel) { |
| case 1 ... 2: |
| return AFE_DPTX_CON_CH_EN_2CH; |
| case 3 ... 4: |
| return AFE_DPTX_CON_CH_EN_4CH; |
| case 5 ... 6: |
| return AFE_DPTX_CON_CH_EN_6CH; |
| case 7 ... 8: |
| return AFE_DPTX_CON_CH_EN_8CH; |
| default: |
| return AFE_DPTX_CON_CH_EN_2CH; |
| } |
| } |
| |
| static unsigned int mtk_dai_get_dptx_ch(unsigned int ch) |
| { |
| return (ch > 2) ? |
| AFE_DPTX_CON_CH_NUM_8CH : AFE_DPTX_CON_CH_NUM_2CH; |
| } |
| |
| static unsigned int mtk_dai_get_dptx_wlen(snd_pcm_format_t format) |
| { |
| return snd_pcm_format_physical_width(format) <= 16 ? |
| AFE_DPTX_CON_16BIT : AFE_DPTX_CON_24BIT; |
| } |
| |
| static int mtk_dai_hdmitx_dptx_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 mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| unsigned int rate = params_rate(params); |
| unsigned int channels = params_channels(params); |
| snd_pcm_format_t format = params_format(params); |
| int width = snd_pcm_format_physical_width(format); |
| int ret; |
| |
| if (!is_valid_etdm_dai(dai->id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai->id]; |
| |
| /* dptx configure */ |
| if (dai->id == MT8188_AFE_IO_DPTX) { |
| regmap_update_bits(afe->regmap, AFE_DPTX_CON, |
| AFE_DPTX_CON_CH_EN_MASK, |
| mtk_dai_get_dptx_ch_en(channels)); |
| regmap_update_bits(afe->regmap, AFE_DPTX_CON, |
| AFE_DPTX_CON_CH_NUM_MASK, |
| mtk_dai_get_dptx_ch(channels)); |
| regmap_update_bits(afe->regmap, AFE_DPTX_CON, |
| AFE_DPTX_CON_16BIT_MASK, |
| mtk_dai_get_dptx_wlen(format)); |
| |
| if (mtk_dai_get_dptx_ch(channels) == AFE_DPTX_CON_CH_NUM_8CH) { |
| etdm_data->data_mode = MTK_DAI_ETDM_DATA_ONE_PIN; |
| channels = 8; |
| } else { |
| channels = 2; |
| } |
| } else { |
| etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN; |
| } |
| |
| ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id); |
| |
| return ret; |
| } |
| |
| static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, |
| int clk_id, |
| unsigned int freq, |
| int dir) |
| { |
| struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| |
| if (!is_valid_etdm_dai(dai->id)) |
| return -EINVAL; |
| etdm_data = afe_priv->dai_priv[dai->id]; |
| |
| dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n", |
| __func__, dai->id, freq, dir); |
| |
| etdm_data->mclk_dir = dir; |
| return mtk_dai_etdm_cal_mclk(afe, freq, dai->id); |
| } |
| |
| static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { |
| .hw_params = mtk_dai_etdm_hw_params, |
| .set_sysclk = mtk_dai_etdm_set_sysclk, |
| .set_fmt = mtk_dai_etdm_set_fmt, |
| .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, |
| }; |
| |
| static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { |
| .hw_params = mtk_dai_hdmitx_dptx_hw_params, |
| .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, |
| .set_fmt = mtk_dai_etdm_set_fmt, |
| }; |
| |
| /* dai driver */ |
| #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_192000) |
| |
| #define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ |
| SNDRV_PCM_FMTBIT_S24_LE |\ |
| SNDRV_PCM_FMTBIT_S32_LE) |
| |
| static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { |
| { |
| .name = "DPTX", |
| .id = MT8188_AFE_IO_DPTX, |
| .playback = { |
| .stream_name = "DPTX", |
| .channels_min = 1, |
| .channels_max = 8, |
| .rates = MTK_ETDM_RATES, |
| .formats = MTK_ETDM_FORMATS, |
| }, |
| .ops = &mtk_dai_hdmitx_dptx_ops, |
| }, |
| { |
| .name = "ETDM1_IN", |
| .id = MT8188_AFE_IO_ETDM1_IN, |
| .capture = { |
| .stream_name = "ETDM1_IN", |
| .channels_min = 1, |
| .channels_max = 16, |
| .rates = MTK_ETDM_RATES, |
| .formats = MTK_ETDM_FORMATS, |
| }, |
| .ops = &mtk_dai_etdm_ops, |
| }, |
| { |
| .name = "ETDM2_IN", |
| .id = MT8188_AFE_IO_ETDM2_IN, |
| .capture = { |
| .stream_name = "ETDM2_IN", |
| .channels_min = 1, |
| .channels_max = 16, |
| .rates = MTK_ETDM_RATES, |
| .formats = MTK_ETDM_FORMATS, |
| }, |
| .ops = &mtk_dai_etdm_ops, |
| }, |
| { |
| .name = "ETDM1_OUT", |
| .id = MT8188_AFE_IO_ETDM1_OUT, |
| .playback = { |
| .stream_name = "ETDM1_OUT", |
| .channels_min = 1, |
| .channels_max = 16, |
| .rates = MTK_ETDM_RATES, |
| .formats = MTK_ETDM_FORMATS, |
| }, |
| .ops = &mtk_dai_etdm_ops, |
| }, |
| { |
| .name = "ETDM2_OUT", |
| .id = MT8188_AFE_IO_ETDM2_OUT, |
| .playback = { |
| .stream_name = "ETDM2_OUT", |
| .channels_min = 1, |
| .channels_max = 16, |
| .rates = MTK_ETDM_RATES, |
| .formats = MTK_ETDM_FORMATS, |
| }, |
| .ops = &mtk_dai_etdm_ops, |
| }, |
| { |
| .name = "ETDM3_OUT", |
| .id = MT8188_AFE_IO_ETDM3_OUT, |
| .playback = { |
| .stream_name = "ETDM3_OUT", |
| .channels_min = 1, |
| .channels_max = 8, |
| .rates = MTK_ETDM_RATES, |
| .formats = MTK_ETDM_FORMATS, |
| }, |
| .ops = &mtk_dai_hdmitx_dptx_ops, |
| }, |
| }; |
| |
| static void mt8188_etdm_update_sync_info(struct mtk_base_afe *afe) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| struct mtk_dai_etdm_priv *mst_data; |
| int mst_dai_id; |
| int i; |
| |
| for (i = MT8188_AFE_IO_ETDM_START; i < MT8188_AFE_IO_ETDM_END; i++) { |
| etdm_data = afe_priv->dai_priv[i]; |
| if (etdm_data->cowork_source_id != COWORK_ETDM_NONE) { |
| mst_dai_id = etdm_data->cowork_source_id; |
| mst_data = afe_priv->dai_priv[mst_dai_id]; |
| if (mst_data->cowork_source_id != COWORK_ETDM_NONE) |
| dev_err(afe->dev, "%s [%d] wrong sync source\n", |
| __func__, i); |
| mst_data->cowork_slv_id[mst_data->cowork_slv_count] = i; |
| mst_data->cowork_slv_count++; |
| } |
| } |
| } |
| |
| static void mt8188_dai_etdm_parse_of(struct mtk_base_afe *afe) |
| { |
| const struct device_node *of_node = afe->dev->of_node; |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_data; |
| char prop[48]; |
| u8 disable_chn[MT8188_ETDM_MAX_CHANNELS]; |
| int max_chn = MT8188_ETDM_MAX_CHANNELS; |
| unsigned int sync_id; |
| u32 sel; |
| int ret; |
| int dai_id; |
| int i, j; |
| struct { |
| const char *name; |
| const unsigned int sync_id; |
| } of_afe_etdms[MT8188_AFE_IO_ETDM_NUM] = { |
| {"etdm-in1", ETDM_SYNC_FROM_IN1}, |
| {"etdm-in2", ETDM_SYNC_FROM_IN2}, |
| {"etdm-out1", ETDM_SYNC_FROM_OUT1}, |
| {"etdm-out2", ETDM_SYNC_FROM_OUT2}, |
| {"etdm-out3", ETDM_SYNC_FROM_OUT3}, |
| }; |
| |
| for (i = 0; i < MT8188_AFE_IO_ETDM_NUM; i++) { |
| dai_id = ETDM_TO_DAI_ID(i); |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| snprintf(prop, sizeof(prop), "mediatek,%s-multi-pin-mode", |
| of_afe_etdms[i].name); |
| |
| etdm_data->data_mode = of_property_read_bool(of_node, prop); |
| |
| snprintf(prop, sizeof(prop), "mediatek,%s-cowork-source", |
| of_afe_etdms[i].name); |
| |
| ret = of_property_read_u32(of_node, prop, &sel); |
| if (ret == 0) { |
| if (sel >= MT8188_AFE_IO_ETDM_NUM) { |
| dev_err(afe->dev, "%s invalid id=%d\n", |
| __func__, sel); |
| etdm_data->cowork_source_id = COWORK_ETDM_NONE; |
| } else { |
| sync_id = of_afe_etdms[sel].sync_id; |
| etdm_data->cowork_source_id = |
| sync_to_dai_id(sync_id); |
| } |
| } else { |
| etdm_data->cowork_source_id = COWORK_ETDM_NONE; |
| } |
| } |
| |
| /* etdm in only */ |
| for (i = 0; i < 2; i++) { |
| dai_id = ETDM_TO_DAI_ID(i); |
| etdm_data = afe_priv->dai_priv[dai_id]; |
| |
| snprintf(prop, sizeof(prop), "mediatek,%s-chn-disabled", |
| of_afe_etdms[i].name); |
| |
| ret = of_property_read_variable_u8_array(of_node, prop, |
| disable_chn, |
| 1, max_chn); |
| if (ret < 0) |
| continue; |
| |
| for (j = 0; j < ret; j++) { |
| if (disable_chn[j] >= MT8188_ETDM_MAX_CHANNELS) |
| dev_err(afe->dev, "%s [%d] invalid chn %u\n", |
| __func__, j, disable_chn[j]); |
| else |
| etdm_data->in_disable_ch[disable_chn[j]] = true; |
| } |
| } |
| mt8188_etdm_update_sync_info(afe); |
| } |
| |
| static int init_etdm_priv_data(struct mtk_base_afe *afe) |
| { |
| struct mt8188_afe_private *afe_priv = afe->platform_priv; |
| struct mtk_dai_etdm_priv *etdm_priv; |
| int i; |
| |
| for (i = MT8188_AFE_IO_ETDM_START; i < MT8188_AFE_IO_ETDM_END; i++) { |
| etdm_priv = devm_kzalloc(afe->dev, |
| sizeof(struct mtk_dai_etdm_priv), |
| GFP_KERNEL); |
| if (!etdm_priv) |
| return -ENOMEM; |
| |
| afe_priv->dai_priv[i] = etdm_priv; |
| } |
| |
| afe_priv->dai_priv[MT8188_AFE_IO_DPTX] = |
| afe_priv->dai_priv[MT8188_AFE_IO_ETDM3_OUT]; |
| |
| mt8188_dai_etdm_parse_of(afe); |
| return 0; |
| } |
| |
| int mt8188_dai_etdm_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_etdm_driver; |
| dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver); |
| |
| dai->dapm_widgets = mtk_dai_etdm_widgets; |
| dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets); |
| dai->dapm_routes = mtk_dai_etdm_routes; |
| dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes); |
| dai->controls = mtk_dai_etdm_controls; |
| dai->num_controls = ARRAY_SIZE(mtk_dai_etdm_controls); |
| |
| return init_etdm_priv_data(afe); |
| } |