diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c index 743d6a162cb9..02411be93900 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c @@ -24,6 +24,7 @@ static const char *aud_clks[MT8188_CLK_NUM] = { [MT8188_CLK_APMIXED_APLL2] = "apll2", /* divider */ + [MT8188_CLK_TOP_APLL1_D4] = "apll1_d4", [MT8188_CLK_TOP_APLL12_DIV0] = "apll12_div0", [MT8188_CLK_TOP_APLL12_DIV1] = "apll12_div1", [MT8188_CLK_TOP_APLL12_DIV2] = "apll12_div2", @@ -378,6 +379,19 @@ int mt8188_afe_get_default_mclk_source_by_rate(int rate) MT8188_MCK_SEL_APLL1 : MT8188_MCK_SEL_APLL2; } +int mt8188_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8188_AUD_PLL1 : MT8188_AUD_PLL2; +} + +int mt8188_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8188_AUD_PLL1; + + return MT8188_AUD_PLL2; +} + int mt8188_afe_init_clock(struct mtk_base_afe *afe) { struct mt8188_afe_private *afe_priv = afe->platform_priv; @@ -477,8 +491,8 @@ int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, if (clk && parent) { ret = clk_set_parent(clk, parent); if (ret) { - dev_dbg(afe->dev, "%s(), failed to set clk parent\n", - __func__); + dev_dbg(afe->dev, "%s(), failed to set clk parent %d\n", + __func__, ret); return ret; } } @@ -605,54 +619,132 @@ static int mt8188_afe_disable_afe_on(struct mtk_base_afe *afe) return 0; } -static int mt8188_afe_enable_timing_sys(struct mtk_base_afe *afe) +static int mt8188_afe_enable_a1sys(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); + if (ret) + return ret; + + return mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); +} + +static int mt8188_afe_disable_a1sys(struct mtk_base_afe *afe) { struct mt8188_afe_private *afe_priv = afe->platform_priv; - mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); - mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); + return 0; +} - mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); - mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); - mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); +static int mt8188_afe_enable_a2sys(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + if (ret) + return ret; + + return mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); +} + +static int mt8188_afe_disable_a2sys(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + + mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + return 0; +} + +int mt8188_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); + if (ret) + return ret; + + ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[MT8188_CLK_TOP_A1SYS_HP_SEL], + afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); + if (ret) + goto err_clk_parent; + + ret = mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1); + if (ret) + goto err_apll_tuner; + + ret = mt8188_afe_enable_a1sys(afe); + if (ret) + goto err_a1sys; + + return 0; + +err_a1sys: + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1); +err_apll_tuner: + mt8188_afe_set_clk_parent(afe, afe_priv->clk[MT8188_CLK_TOP_A1SYS_HP_SEL], + afe_priv->clk[MT8188_CLK_XTAL_26M]); +err_clk_parent: + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); + + return ret; +} + +int mt8188_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + + mt8188_afe_disable_a1sys(afe); + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1); + mt8188_afe_set_clk_parent(afe, afe_priv->clk[MT8188_CLK_TOP_A1SYS_HP_SEL], + afe_priv->clk[MT8188_CLK_XTAL_26M]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); return 0; } -static int mt8188_afe_disable_timing_sys(struct mtk_base_afe *afe) +int mt8188_apll2_enable(struct mtk_base_afe *afe) { - struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; - mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); - mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + ret = mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2); + if (ret) + return ret; - mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); - mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); - mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); + ret = mt8188_afe_enable_a2sys(afe); + if (ret) + goto err_a2sys; return 0; +err_a2sys: + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2); + + return ret; +} + +int mt8188_apll2_disable(struct mtk_base_afe *afe) +{ + mt8188_afe_disable_a2sys(afe); + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2); + return 0; } int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe) { - mt8188_afe_enable_timing_sys(afe); - + mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); mt8188_afe_enable_afe_on(afe); - - mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1); - mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2); - return 0; } int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe) { - mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2); - mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1); - mt8188_afe_disable_afe_on(afe); - - mt8188_afe_disable_timing_sys(afe); - + mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); return 0; } diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h index 084fdfb1d877..04cb476f0bcb 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h @@ -11,6 +11,10 @@ #ifndef _MT8188_AFE_CLK_H_ #define _MT8188_AFE_CLK_H_ +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" + enum { /* xtal */ MT8188_CLK_XTAL_26M, @@ -18,6 +22,7 @@ enum { MT8188_CLK_APMIXED_APLL1, MT8188_CLK_APMIXED_APLL2, /* divider */ + MT8188_CLK_TOP_APLL1_D4, MT8188_CLK_TOP_APLL12_DIV0, MT8188_CLK_TOP_APLL12_DIV1, MT8188_CLK_TOP_APLL12_DIV2, @@ -99,6 +104,8 @@ struct mtk_base_afe; int mt8188_afe_get_mclk_source_clk_id(int sel); int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll); int mt8188_afe_get_default_mclk_source_by_rate(int rate); +int mt8188_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8188_get_apll_by_name(struct mtk_base_afe *afe, const char *name); int mt8188_afe_init_clock(struct mtk_base_afe *afe); void mt8188_afe_deinit_clock(void *priv); int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk); @@ -107,6 +114,10 @@ int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, unsigned int rate); int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, struct clk *parent); +int mt8188_apll1_enable(struct mtk_base_afe *afe); +int mt8188_apll1_disable(struct mtk_base_afe *afe); +int mt8188_apll2_enable(struct mtk_base_afe *afe); +int mt8188_apll2_disable(struct mtk_base_afe *afe); int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe); int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe); int mt8188_afe_enable_reg_rw_clk(struct mtk_base_afe *afe); diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c index fd6e39a1e4c1..16440dd0a89c 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c @@ -22,6 +22,7 @@ #define ENUM_TO_STR(x) #x enum { + SUPPLY_SEQ_APLL, SUPPLY_SEQ_ETDM_MCLK, SUPPLY_SEQ_ETDM_CG, SUPPLY_SEQ_DPTX_EN, @@ -95,6 +96,7 @@ struct mtk_dai_etdm_priv { bool slave_mode; bool lrck_inv; bool bck_inv; + unsigned int rate; unsigned int format; unsigned int slots; unsigned int lrck_width; @@ -360,6 +362,10 @@ static int get_etdm_id_by_name(struct mtk_base_afe *afe, 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; } @@ -445,6 +451,44 @@ static int mtk_dai_etdm_disable_mclk(struct mtk_base_afe *afe, int dai_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) { @@ -520,6 +564,36 @@ static int mtk_etdm_cowork_connect(struct snd_soc_dapm_widget *source, 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 (strcmp(w->name, APLL1_W_NAME) == 0) + mt8188_apll1_enable(afe); + else + mt8188_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, 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) @@ -1231,6 +1305,16 @@ static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { 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"), }; @@ -1259,6 +1343,21 @@ static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { {"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}, @@ -1308,6 +1407,21 @@ static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { {"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"}, @@ -2004,6 +2118,7 @@ static int mtk_dai_etdm_configure(struct mtk_base_afe *afe, 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)