[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",
                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;
        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;
                }
        }
        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;
 
-       mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
-       mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]);
+       ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+       if (ret)
+               return ret;
 
-       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);
+       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_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING);
+       mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
        return 0;
 }
 
-static int mt8188_afe_disable_timing_sys(struct mtk_base_afe *afe)
+static int mt8188_afe_enable_a2sys(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_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]);
+       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);
+       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_afe_enable_main_clock(struct mtk_base_afe *afe)
+int mt8188_apll1_enable(struct mtk_base_afe *afe)
 {
-       mt8188_afe_enable_timing_sys(afe);
+       struct mt8188_afe_private *afe_priv = afe->platform_priv;
+       int ret;
 
-       mt8188_afe_enable_afe_on(afe);
+       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;
 
-       mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1);
-       mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2);
+       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_afe_disable_main_clock(struct mtk_base_afe *afe)
+int mt8188_apll1_disable(struct mtk_base_afe *afe)
 {
-       mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2);
+       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]);
 
-       mt8188_afe_disable_afe_on(afe);
+       return 0;
+}
+
+int mt8188_apll2_enable(struct mtk_base_afe *afe)
+{
+       int ret;
 
-       mt8188_afe_disable_timing_sys(afe);
+       ret = mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2);
+       if (ret)
+               return ret;
 
+       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_top_cg(afe, MT8188_TOP_CG_26M_TIMING);
+       mt8188_afe_enable_afe_on(afe);
+       return 0;
+}
+
+int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe)
+{
+       mt8188_afe_disable_afe_on(afe);
+       mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING);
        return 0;
 }
 
 #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,
        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,
 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);
                            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);
 
 #define ENUM_TO_STR(x) #x
 
 enum {
+       SUPPLY_SEQ_APLL,
        SUPPLY_SEQ_ETDM_MCLK,
        SUPPLY_SEQ_ETDM_CG,
        SUPPLY_SEQ_DPTX_EN,
        bool slave_mode;
        bool lrck_inv;
        bool bck_inv;
+       unsigned int rate;
        unsigned int format;
        unsigned int slots;
        unsigned int lrck_width;
                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;
 }
        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)
 {
        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)
        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"),
 };
 
        {"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},
        {"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"},
                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)