diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index f71d1a909d07..e8177c3a0952 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1772,6 +1772,10 @@ Optional Properties: - qcom,msm-mi2s-master: This property is used to inform machine driver if MSM is the clock master of mi2s. 1 means master and 0 means slave. The first entry is primary mi2s; the second entry is secondary mi2s, and so on. +- qcom,msm-mi2s-ext-mclk: This property is used to inform machine driver + if MCLK from MSM is used for any external audio connections. 1 means used + as external mclk source and 0 indicate not used. The first entry is + primary mclk; the second entry is secondary mclk, and so on. - reg: This property provides the AUX PCM/MI2S mux select register addresses and size. - reg_names: This property provides the name of the AUX PCM/MI2S mux select @@ -1812,6 +1816,7 @@ Example: qcom,mi2s-audio-intf; qcom,auxpcm-audio-intf; qcom,msm-mi2s-master = <1>, <0>, <1>, <1>; + qcom,msm-mi2s-ext-mclk = <1>, <1>, <0>, <1>; reg = <0x1711a000 0x4>, <0x1711b000 0x4>, <0x1711c000 0x4>, diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c index bf5dbeb3a401..ee3cf62ee2c2 100644 --- a/sound/soc/msm/sdm660-common.c +++ b/sound/soc/msm/sdm660-common.c @@ -169,6 +169,7 @@ struct mi2s_conf { struct mutex lock; u32 ref_cnt; u32 msm_is_mi2s_master; + u32 msm_is_ext_mclk; }; struct auxpcm_conf { @@ -176,6 +177,13 @@ struct auxpcm_conf { u32 ref_cnt; }; +static u32 mi2s_ebit_clk[MI2S_MAX] = { + Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT +}; + struct msm_wsa881x_dev_info { struct device_node *of_node; u32 index; @@ -340,6 +348,43 @@ static struct afe_clk_set mi2s_clk[MI2S_MAX] = { } }; +static struct afe_clk_set mi2s_mclk[MI2S_MAX] = { + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_MCLK_1, + Q6AFE_LPASS_OSR_CLK_9_P600_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_MCLK_2, + Q6AFE_LPASS_OSR_CLK_9_P600_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_MCLK_3, + Q6AFE_LPASS_OSR_CLK_9_P600_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_MCLK_4, + Q6AFE_LPASS_OSR_CLK_9_P600_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + } +}; + + + static struct mi2s_aux_pcm_common_conf mi2s_auxpcm_conf[PCM_I2S_SEL_MAX]; static struct mi2s_conf mi2s_intf_conf[MI2S_MAX]; static struct auxpcm_conf auxpcm_intf_conf[AUX_PCM_MAX]; @@ -2095,6 +2140,7 @@ int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) int ret = 0; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int port_id = msm_get_port_id(rtd->dai_link->be_id); int index = cpu_dai->id; unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; @@ -2117,6 +2163,11 @@ int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) */ mutex_lock(&mi2s_intf_conf[index].lock); if (++mi2s_intf_conf[index].ref_cnt == 1) { + /* Check if msm needs to provide the clock to the interface */ + if (!mi2s_intf_conf[index].msm_is_mi2s_master) { + mi2s_clk[index].clk_id = mi2s_ebit_clk[index]; + fmt = SND_SOC_DAIFMT_CBM_CFM; + } ret = msm_mi2s_set_sclk(substream, true); if (IS_ERR_VALUE(ret)) { dev_err(rtd->card->dev, @@ -2136,9 +2187,6 @@ int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) ret = -EINVAL; goto clk_off; } - /* Check if msm needs to provide the clock to the interface */ - if (!mi2s_intf_conf[index].msm_is_mi2s_master) - fmt = SND_SOC_DAIFMT_CBM_CFM; ret = snd_soc_dai_set_fmt(cpu_dai, fmt); if (IS_ERR_VALUE(ret)) { dev_err(rtd->card->dev, @@ -2146,7 +2194,21 @@ int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) __func__, index, ret); goto clk_off; } + if (mi2s_intf_conf[index].msm_is_ext_mclk) { + mi2s_mclk[index].enable = 1; + pr_debug("%s: Enabling mclk, clk_freq_in_hz = %u\n", + __func__, mi2s_mclk[index].clk_freq_in_hz); + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_mclk[index]); + if (ret < 0) { + pr_err("%s: afe lpass mclk failed, err:%d\n", + __func__, ret); + goto clk_off; + } + } } + mutex_unlock(&mi2s_intf_conf[index].lock); + return 0; clk_off: if (IS_ERR_VALUE(ret)) msm_mi2s_set_sclk(substream, false); @@ -2168,6 +2230,7 @@ void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) { int ret; struct snd_soc_pcm_runtime *rtd = substream->private_data; + int port_id = msm_get_port_id(rtd->dai_link->be_id); int index = rtd->cpu_dai->id; pr_debug("%s(): substream = %s stream = %d\n", __func__, @@ -2185,6 +2248,17 @@ void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) __func__, index, ret); mi2s_intf_conf[index].ref_cnt++; } + if (mi2s_intf_conf[index].msm_is_ext_mclk) { + mi2s_mclk[index].enable = 0; + pr_debug("%s: Disabling mclk, clk_freq_in_hz = %u\n", + __func__, mi2s_mclk[index].clk_freq_in_hz); + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_mclk[index]); + if (ret < 0) { + pr_err("%s: mclk disable failed for MCLK (%d); ret=%d\n", + __func__, index, ret); + } + } } mutex_unlock(&mi2s_intf_conf[index].lock); } @@ -2601,6 +2675,7 @@ static void i2s_auxpcm_init(struct platform_device *pdev) struct resource *muxsel; int count; u32 mi2s_master_slave[MI2S_MAX]; + u32 mi2s_ext_mclk[MI2S_MAX]; int ret; char *str[PCM_I2S_SEL_MAX] = { "lpaif_pri_mode_muxsel", @@ -2634,8 +2709,8 @@ static void i2s_auxpcm_init(struct platform_device *pdev) } ret = of_property_read_u32_array(pdev->dev.of_node, - "qcom,msm-mi2s-master", - mi2s_master_slave, MI2S_MAX); + "qcom,msm-mi2s-master", + mi2s_master_slave, MI2S_MAX); if (ret) { dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n", __func__); @@ -2645,6 +2720,18 @@ static void i2s_auxpcm_init(struct platform_device *pdev) mi2s_master_slave[count]; } } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,msm-mi2s-ext-mclk", + mi2s_ext_mclk, MI2S_MAX); + if (ret) { + dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-ext-mclk in DT node\n", + __func__); + } else { + for (count = 0; count < MI2S_MAX; count++) + mi2s_intf_conf[count].msm_is_ext_mclk = + mi2s_ext_mclk[count]; + } } static void i2s_auxpcm_deinit(void) diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index aa094fe853ee..4ecf6c996e69 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -3033,7 +3033,7 @@ static int msm_internal_init(struct platform_device *pdev, AFE_API_VERSION_I2S_CONFIG; pdata->digital_cdc_core_clk.clk_id = Q6AFE_LPASS_CLK_ID_INT_MCLK_0; - pdata->digital_cdc_core_clk.clk_freq_in_hz = 0; + pdata->digital_cdc_core_clk.clk_freq_in_hz = pdata->mclk_freq; pdata->digital_cdc_core_clk.clk_attri = Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO; pdata->digital_cdc_core_clk.clk_root =