1d6f3710aSGarlic Tseng /* 2d6f3710aSGarlic Tseng * mt2701-afe-clock-ctrl.c -- Mediatek 2701 afe clock ctrl 3d6f3710aSGarlic Tseng * 4d6f3710aSGarlic Tseng * Copyright (c) 2016 MediaTek Inc. 5d6f3710aSGarlic Tseng * Author: Garlic Tseng <garlic.tseng@mediatek.com> 6cf870273SRyder Lee * Ryder Lee <ryder.lee@mediatek.com> 7d6f3710aSGarlic Tseng * 8d6f3710aSGarlic Tseng * This program is free software; you can redistribute it and/or modify 9d6f3710aSGarlic Tseng * it under the terms of the GNU General Public License version 2 and 10d6f3710aSGarlic Tseng * only version 2 as published by the Free Software Foundation. 11d6f3710aSGarlic Tseng * 12d6f3710aSGarlic Tseng * This program is distributed in the hope that it will be useful, 13d6f3710aSGarlic Tseng * but WITHOUT ANY WARRANTY; without even the implied warranty of 14d6f3710aSGarlic Tseng * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15d6f3710aSGarlic Tseng * GNU General Public License for more details. 16d6f3710aSGarlic Tseng */ 17d6f3710aSGarlic Tseng 18d6f3710aSGarlic Tseng #include "mt2701-afe-common.h" 19d6f3710aSGarlic Tseng #include "mt2701-afe-clock-ctrl.h" 20d6f3710aSGarlic Tseng 21d8d99d8eSRyder Lee static const char *const base_clks[] = { 2296365d9fSRyder Lee [MT2701_INFRA_SYS_AUDIO] = "infra_sys_audio_clk", 23d8d99d8eSRyder Lee [MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel", 24d8d99d8eSRyder Lee [MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel", 2596365d9fSRyder Lee [MT2701_TOP_AUD_A1SYS] = "top_audio_a1sys_hp", 2696365d9fSRyder Lee [MT2701_TOP_AUD_A2SYS] = "top_audio_a2sys_hp", 27d8d99d8eSRyder Lee [MT2701_AUDSYS_AFE] = "audio_afe_pd", 28d8d99d8eSRyder Lee [MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd", 29d8d99d8eSRyder Lee [MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd", 30d8d99d8eSRyder Lee [MT2701_AUDSYS_A2SYS] = "audio_a2sys_pd", 31d6f3710aSGarlic Tseng }; 32d6f3710aSGarlic Tseng 33d6f3710aSGarlic Tseng int mt2701_init_clock(struct mtk_base_afe *afe) 34d6f3710aSGarlic Tseng { 35d6f3710aSGarlic Tseng struct mt2701_afe_private *afe_priv = afe->platform_priv; 36d8d99d8eSRyder Lee int i; 37d6f3710aSGarlic Tseng 38d8d99d8eSRyder Lee for (i = 0; i < MT2701_BASE_CLK_NUM; i++) { 39d8d99d8eSRyder Lee afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]); 40d8d99d8eSRyder Lee if (IS_ERR(afe_priv->base_ck[i])) { 41d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", base_clks[i]); 42d8d99d8eSRyder Lee return PTR_ERR(afe_priv->base_ck[i]); 43d6f3710aSGarlic Tseng } 44d6f3710aSGarlic Tseng } 45d6f3710aSGarlic Tseng 46d8d99d8eSRyder Lee /* Get I2S related clocks */ 47d8d99d8eSRyder Lee for (i = 0; i < MT2701_I2S_NUM; i++) { 48d8d99d8eSRyder Lee struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i]; 49*ab7b4ee9SRyder Lee struct clk *i2s_ck; 50d8d99d8eSRyder Lee char name[13]; 51d8d99d8eSRyder Lee 52d8d99d8eSRyder Lee snprintf(name, sizeof(name), "i2s%d_src_sel", i); 53d8d99d8eSRyder Lee i2s_path->sel_ck = devm_clk_get(afe->dev, name); 54d8d99d8eSRyder Lee if (IS_ERR(i2s_path->sel_ck)) { 55d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", name); 56d8d99d8eSRyder Lee return PTR_ERR(i2s_path->sel_ck); 57d8d99d8eSRyder Lee } 58d8d99d8eSRyder Lee 59d8d99d8eSRyder Lee snprintf(name, sizeof(name), "i2s%d_src_div", i); 60d8d99d8eSRyder Lee i2s_path->div_ck = devm_clk_get(afe->dev, name); 61d8d99d8eSRyder Lee if (IS_ERR(i2s_path->div_ck)) { 62d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", name); 63d8d99d8eSRyder Lee return PTR_ERR(i2s_path->div_ck); 64d8d99d8eSRyder Lee } 65d8d99d8eSRyder Lee 66d8d99d8eSRyder Lee snprintf(name, sizeof(name), "i2s%d_mclk_en", i); 67d8d99d8eSRyder Lee i2s_path->mclk_ck = devm_clk_get(afe->dev, name); 68d8d99d8eSRyder Lee if (IS_ERR(i2s_path->mclk_ck)) { 69d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", name); 70d8d99d8eSRyder Lee return PTR_ERR(i2s_path->mclk_ck); 71d8d99d8eSRyder Lee } 72d8d99d8eSRyder Lee 73d8d99d8eSRyder Lee snprintf(name, sizeof(name), "i2so%d_hop_ck", i); 74*ab7b4ee9SRyder Lee i2s_ck = devm_clk_get(afe->dev, name); 75*ab7b4ee9SRyder Lee if (IS_ERR(i2s_ck)) { 76d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", name); 77*ab7b4ee9SRyder Lee return PTR_ERR(i2s_ck); 78d8d99d8eSRyder Lee } 79*ab7b4ee9SRyder Lee i2s_path->hop_ck[SNDRV_PCM_STREAM_PLAYBACK] = i2s_ck; 80d8d99d8eSRyder Lee 81d8d99d8eSRyder Lee snprintf(name, sizeof(name), "i2si%d_hop_ck", i); 82*ab7b4ee9SRyder Lee i2s_ck = devm_clk_get(afe->dev, name); 83*ab7b4ee9SRyder Lee if (IS_ERR(i2s_ck)) { 84d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", name); 85*ab7b4ee9SRyder Lee return PTR_ERR(i2s_ck); 86d8d99d8eSRyder Lee } 87*ab7b4ee9SRyder Lee i2s_path->hop_ck[SNDRV_PCM_STREAM_CAPTURE] = i2s_ck; 88d8d99d8eSRyder Lee 89d8d99d8eSRyder Lee snprintf(name, sizeof(name), "asrc%d_out_ck", i); 90d8d99d8eSRyder Lee i2s_path->asrco_ck = devm_clk_get(afe->dev, name); 91d8d99d8eSRyder Lee if (IS_ERR(i2s_path->asrco_ck)) { 92d8d99d8eSRyder Lee dev_err(afe->dev, "failed to get %s\n", name); 93d8d99d8eSRyder Lee return PTR_ERR(i2s_path->asrco_ck); 94d8d99d8eSRyder Lee } 95d8d99d8eSRyder Lee } 96d8d99d8eSRyder Lee 97d8d99d8eSRyder Lee /* Some platforms may support BT path */ 98d8d99d8eSRyder Lee afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd"); 99d8d99d8eSRyder Lee if (IS_ERR(afe_priv->mrgif_ck)) { 100d8d99d8eSRyder Lee if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER) 101d8d99d8eSRyder Lee return -EPROBE_DEFER; 102d8d99d8eSRyder Lee 103d8d99d8eSRyder Lee afe_priv->mrgif_ck = NULL; 104d8d99d8eSRyder Lee } 105d8d99d8eSRyder Lee 106d6f3710aSGarlic Tseng return 0; 107d6f3710aSGarlic Tseng } 108d6f3710aSGarlic Tseng 109cf870273SRyder Lee int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, 110cf870273SRyder Lee struct mt2701_i2s_path *i2s_path, 111cf870273SRyder Lee int dir) 112d8d99d8eSRyder Lee { 113d8d99d8eSRyder Lee int ret; 114d8d99d8eSRyder Lee 115d8d99d8eSRyder Lee ret = clk_prepare_enable(i2s_path->asrco_ck); 116d8d99d8eSRyder Lee if (ret) { 117d8d99d8eSRyder Lee dev_err(afe->dev, "failed to enable ASRC clock %d\n", ret); 118d8d99d8eSRyder Lee return ret; 119d8d99d8eSRyder Lee } 120d8d99d8eSRyder Lee 121d8d99d8eSRyder Lee ret = clk_prepare_enable(i2s_path->hop_ck[dir]); 122d8d99d8eSRyder Lee if (ret) { 123d8d99d8eSRyder Lee dev_err(afe->dev, "failed to enable I2S clock %d\n", ret); 124d8d99d8eSRyder Lee goto err_hop_ck; 125d8d99d8eSRyder Lee } 126d8d99d8eSRyder Lee 127d8d99d8eSRyder Lee return 0; 128d8d99d8eSRyder Lee 129d8d99d8eSRyder Lee err_hop_ck: 130d8d99d8eSRyder Lee clk_disable_unprepare(i2s_path->asrco_ck); 131d8d99d8eSRyder Lee 132d8d99d8eSRyder Lee return ret; 133d8d99d8eSRyder Lee } 134d8d99d8eSRyder Lee 135cf870273SRyder Lee void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, 136cf870273SRyder Lee struct mt2701_i2s_path *i2s_path, 137cf870273SRyder Lee int dir) 138d8d99d8eSRyder Lee { 139d8d99d8eSRyder Lee clk_disable_unprepare(i2s_path->hop_ck[dir]); 140d8d99d8eSRyder Lee clk_disable_unprepare(i2s_path->asrco_ck); 141d8d99d8eSRyder Lee } 142d8d99d8eSRyder Lee 143d8d99d8eSRyder Lee int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id) 144d8d99d8eSRyder Lee { 145d8d99d8eSRyder Lee struct mt2701_afe_private *afe_priv = afe->platform_priv; 146d8d99d8eSRyder Lee struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id]; 147d8d99d8eSRyder Lee 148d8d99d8eSRyder Lee return clk_prepare_enable(i2s_path->mclk_ck); 149d8d99d8eSRyder Lee } 150d8d99d8eSRyder Lee 151d8d99d8eSRyder Lee void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id) 152d8d99d8eSRyder Lee { 153d8d99d8eSRyder Lee struct mt2701_afe_private *afe_priv = afe->platform_priv; 154d8d99d8eSRyder Lee struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id]; 155d8d99d8eSRyder Lee 156d8d99d8eSRyder Lee clk_disable_unprepare(i2s_path->mclk_ck); 157d8d99d8eSRyder Lee } 158d8d99d8eSRyder Lee 159d8d99d8eSRyder Lee int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe) 160d8d99d8eSRyder Lee { 161d8d99d8eSRyder Lee struct mt2701_afe_private *afe_priv = afe->platform_priv; 162d8d99d8eSRyder Lee 163d8d99d8eSRyder Lee return clk_prepare_enable(afe_priv->mrgif_ck); 164d8d99d8eSRyder Lee } 165d8d99d8eSRyder Lee 166d8d99d8eSRyder Lee void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe) 167d8d99d8eSRyder Lee { 168d8d99d8eSRyder Lee struct mt2701_afe_private *afe_priv = afe->platform_priv; 169d8d99d8eSRyder Lee 170d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->mrgif_ck); 171d8d99d8eSRyder Lee } 172d8d99d8eSRyder Lee 173d8d99d8eSRyder Lee static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe) 174d8d99d8eSRyder Lee { 175d8d99d8eSRyder Lee struct mt2701_afe_private *afe_priv = afe->platform_priv; 176d8d99d8eSRyder Lee int ret; 177d8d99d8eSRyder Lee 17896365d9fSRyder Lee /* Enable infra clock gate */ 17996365d9fSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]); 180d8d99d8eSRyder Lee if (ret) 181d8d99d8eSRyder Lee return ret; 182d8d99d8eSRyder Lee 18396365d9fSRyder Lee /* Enable top a1sys clock gate */ 18496365d9fSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]); 18596365d9fSRyder Lee if (ret) 18696365d9fSRyder Lee goto err_a1sys; 18796365d9fSRyder Lee 18896365d9fSRyder Lee /* Enable top a2sys clock gate */ 18996365d9fSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]); 19096365d9fSRyder Lee if (ret) 19196365d9fSRyder Lee goto err_a2sys; 19296365d9fSRyder Lee 19396365d9fSRyder Lee /* Internal clock gates */ 19496365d9fSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]); 19596365d9fSRyder Lee if (ret) 19696365d9fSRyder Lee goto err_afe; 19796365d9fSRyder Lee 198d8d99d8eSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); 199d8d99d8eSRyder Lee if (ret) 200d8d99d8eSRyder Lee goto err_audio_a1sys; 201d8d99d8eSRyder Lee 202d8d99d8eSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); 203d8d99d8eSRyder Lee if (ret) 204d8d99d8eSRyder Lee goto err_audio_a2sys; 205d8d99d8eSRyder Lee 206d8d99d8eSRyder Lee ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]); 207d8d99d8eSRyder Lee if (ret) 208d8d99d8eSRyder Lee goto err_afe_conn; 209d8d99d8eSRyder Lee 210d8d99d8eSRyder Lee return 0; 211d8d99d8eSRyder Lee 212d8d99d8eSRyder Lee err_afe_conn: 213d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); 214d8d99d8eSRyder Lee err_audio_a2sys: 215d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); 216d8d99d8eSRyder Lee err_audio_a1sys: 217d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]); 21896365d9fSRyder Lee err_afe: 21996365d9fSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]); 22096365d9fSRyder Lee err_a2sys: 22196365d9fSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]); 22296365d9fSRyder Lee err_a1sys: 22396365d9fSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]); 224d8d99d8eSRyder Lee 225d8d99d8eSRyder Lee return ret; 226d8d99d8eSRyder Lee } 227d8d99d8eSRyder Lee 228d8d99d8eSRyder Lee static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe) 229d8d99d8eSRyder Lee { 230d8d99d8eSRyder Lee struct mt2701_afe_private *afe_priv = afe->platform_priv; 231d8d99d8eSRyder Lee 232d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]); 233d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); 234d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); 235d8d99d8eSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]); 23696365d9fSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]); 23796365d9fSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]); 23896365d9fSRyder Lee clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]); 239d8d99d8eSRyder Lee } 240d8d99d8eSRyder Lee 241d6f3710aSGarlic Tseng int mt2701_afe_enable_clock(struct mtk_base_afe *afe) 242d6f3710aSGarlic Tseng { 243d8d99d8eSRyder Lee int ret; 244d6f3710aSGarlic Tseng 245d8d99d8eSRyder Lee /* Enable audio system */ 246d8d99d8eSRyder Lee ret = mt2701_afe_enable_audsys(afe); 247d6f3710aSGarlic Tseng if (ret) { 248d8d99d8eSRyder Lee dev_err(afe->dev, "failed to enable audio system %d\n", ret); 249d6f3710aSGarlic Tseng return ret; 250d6f3710aSGarlic Tseng } 251d6f3710aSGarlic Tseng 252d6f3710aSGarlic Tseng regmap_update_bits(afe->regmap, ASYS_TOP_CON, 253600b2fd4SRyder Lee ASYS_TOP_CON_ASYS_TIMING_ON, 254600b2fd4SRyder Lee ASYS_TOP_CON_ASYS_TIMING_ON); 255d6f3710aSGarlic Tseng regmap_update_bits(afe->regmap, AFE_DAC_CON0, 256d6f3710aSGarlic Tseng AFE_DAC_CON0_AFE_ON, 257d6f3710aSGarlic Tseng AFE_DAC_CON0_AFE_ON); 258d8d99d8eSRyder Lee 259d8d99d8eSRyder Lee /* Configure ASRC */ 260d8d99d8eSRyder Lee regmap_write(afe->regmap, PWR1_ASM_CON1, PWR1_ASM_CON1_INIT_VAL); 261d8d99d8eSRyder Lee regmap_write(afe->regmap, PWR2_ASM_CON1, PWR2_ASM_CON1_INIT_VAL); 262d6f3710aSGarlic Tseng 263d6f3710aSGarlic Tseng return 0; 264d6f3710aSGarlic Tseng } 265d6f3710aSGarlic Tseng 266d8d99d8eSRyder Lee int mt2701_afe_disable_clock(struct mtk_base_afe *afe) 267d6f3710aSGarlic Tseng { 268d6f3710aSGarlic Tseng regmap_update_bits(afe->regmap, ASYS_TOP_CON, 269600b2fd4SRyder Lee ASYS_TOP_CON_ASYS_TIMING_ON, 0); 270d6f3710aSGarlic Tseng regmap_update_bits(afe->regmap, AFE_DAC_CON0, 271d6f3710aSGarlic Tseng AFE_DAC_CON0_AFE_ON, 0); 272d6f3710aSGarlic Tseng 273d8d99d8eSRyder Lee mt2701_afe_disable_audsys(afe); 274d6f3710aSGarlic Tseng 275d6f3710aSGarlic Tseng return 0; 276d6f3710aSGarlic Tseng } 277d6f3710aSGarlic Tseng 278cf870273SRyder Lee int mt2701_mclk_configuration(struct mtk_base_afe *afe, int id) 279cf870273SRyder Lee 280d6f3710aSGarlic Tseng { 281d8d99d8eSRyder Lee struct mt2701_afe_private *priv = afe->platform_priv; 282d8d99d8eSRyder Lee struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id]; 283cf870273SRyder Lee int ret = -EINVAL; 284d6f3710aSGarlic Tseng 285d8d99d8eSRyder Lee /* Set mclk source */ 286cf870273SRyder Lee if (!(MT2701_PLL_DOMAIN_0_RATE % i2s_path->mclk_rate)) 287d8d99d8eSRyder Lee ret = clk_set_parent(i2s_path->sel_ck, 288d8d99d8eSRyder Lee priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]); 289cf870273SRyder Lee else if (!(MT2701_PLL_DOMAIN_1_RATE % i2s_path->mclk_rate)) 290d8d99d8eSRyder Lee ret = clk_set_parent(i2s_path->sel_ck, 291d8d99d8eSRyder Lee priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]); 292d6f3710aSGarlic Tseng 293cf870273SRyder Lee if (ret) { 294cf870273SRyder Lee dev_err(afe->dev, "failed to set mclk source\n"); 295cf870273SRyder Lee return ret; 296cf870273SRyder Lee } 297d6f3710aSGarlic Tseng 298d8d99d8eSRyder Lee /* Set mclk divider */ 299cf870273SRyder Lee ret = clk_set_rate(i2s_path->div_ck, i2s_path->mclk_rate); 300cf870273SRyder Lee if (ret) { 301d8d99d8eSRyder Lee dev_err(afe->dev, "failed to set mclk divider %d\n", ret); 302cf870273SRyder Lee return ret; 303cf870273SRyder Lee } 304cf870273SRyder Lee 305cf870273SRyder Lee return 0; 306d6f3710aSGarlic Tseng } 307