From 789301acc793afbeee7345b36ee950be6d2db9fa Mon Sep 17 00:00:00 2001 From: Abhilash Sathyanarayana Date: Thu, 21 Sep 2023 14:59:02 +0530 Subject: [PATCH] asoc: ext-clk: Add support for configuring ext clk In the case an external clock is used to source the MCLK, configure additional clock attributes to be sent to the DSP. Introduce parsing of new DT properties about the external clock frequency which is required to find the appropriate clock attributes whilst providing backward compatibility to not send any additional clock attributes to the DSP. Change-Id: I029080fe509f9545fb9785bf4a9225e9bb7dff46 Signed-off-by: Abhilash Sathyanarayana --- asoc/codecs/audio-ext-clk-up.c | 115 ++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 25 deletions(-) diff --git a/asoc/codecs/audio-ext-clk-up.c b/asoc/codecs/audio-ext-clk-up.c index 8ce627ac86b3..45f430d5e065 100644 --- a/asoc/codecs/audio-ext-clk-up.c +++ b/asoc/codecs/audio-ext-clk-up.c @@ -57,6 +57,8 @@ struct audio_ext_clk_priv { const char *clk_name; uint32_t lpass_core_hwvote_client_handle; uint32_t lpass_audio_hwvote_client_handle; + bool supports_ext_mclk; + uint32_t ext_mclk_freq; }; static struct audio_ext_clk audio_clk_array[]; @@ -70,46 +72,75 @@ static int audio_ext_clk_prepare(struct clk_hw *hw) { struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); struct pinctrl_info *pnctrl_info = &clk_priv->audio_clk.pnctrl_info; - int ret; + int ret = 0; static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) && - (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { + (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { clk_priv->clk_cfg.enable = 1; - ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg); - if (ret < 0) { - if (__ratelimit(&rtl)) - pr_err_ratelimited("%s afe_set_digital_codec_core_clock failed\n", - __func__); - return ret; + + /* Case 1. Clock driver supports ext clk source && platform enables ext clk support + * - Use ext clk API + * Case 2. Clock driver supports ext clk source && platform has NOT enabled ext clk support + * - We try using ext clk API, it fails; we fall back to internal clk API + * Case 3. Clock driver doesn't support ext clk source + * - Use internal clk API + * + * NOTE: Platform, the machine driver, confirms ext clk support + * by registering for the 'ext_mclk_cb' callback with + * Q6AFE driver. + */ + if (clk_priv->supports_ext_mclk) { + ret = afe_set_lpass_clk_cfg_ext_mclk(IDX_RSVD_3, + &clk_priv->clk_cfg, + clk_priv->ext_mclk_freq); + if (ret == 0) { + goto prepare_pinctrl; + } else if (ret == -EOPNOTSUPP) { + pr_err_ratelimited("%s: ext mclk prepare failed; falling back to internal clk\n", + __func__); + } else { + goto err; + } } + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, + &clk_priv->clk_cfg); + if (ret < 0) + goto err; } +prepare_pinctrl: if (pnctrl_info->pinctrl) { ret = pinctrl_select_state(pnctrl_info->pinctrl, - pnctrl_info->active); + pnctrl_info->active); if (ret) { pr_err("%s: active state select failed with %d\n", __func__, ret); return -EIO; } } - if (pnctrl_info->base) iowrite32(1, pnctrl_info->base); return 0; + +err: + if (__ratelimit(&rtl)) + pr_err_ratelimited("%s: afe_set_lpass_clk_cfg_ext_mclk failed with %d\n", + __func__, ret); + return ret; + } static void audio_ext_clk_unprepare(struct clk_hw *hw) { struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); struct pinctrl_info *pnctrl_info = &clk_priv->audio_clk.pnctrl_info; - int ret; + int ret = 0; static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); if (pnctrl_info->pinctrl) { ret = pinctrl_select_state(pnctrl_info->pinctrl, - pnctrl_info->sleep); + pnctrl_info->sleep); if (ret) { pr_err("%s: active state select failed with %d\n", __func__, ret); @@ -117,19 +148,34 @@ static void audio_ext_clk_unprepare(struct clk_hw *hw) } } - if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) && - (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { - clk_priv->clk_cfg.enable = 0; - ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg); - if (ret < 0) { - if (__ratelimit(&rtl)) - pr_err_ratelimited("%s: afe_set_lpass_clk_cfg failed, ret = %d\n", - __func__, ret); - } - } - if (pnctrl_info->base) iowrite32(0, pnctrl_info->base); + + if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) && + (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { + clk_priv->clk_cfg.enable = 0; + if (clk_priv->supports_ext_mclk) { + ret = afe_set_lpass_clk_cfg_ext_mclk(IDX_RSVD_3, + &clk_priv->clk_cfg, + clk_priv->ext_mclk_freq); + if (ret == 0) { + goto exit; + } else if (ret == -EOPNOTSUPP) { + pr_err_ratelimited("%s: ext mclk unprepare failed; falling back to internal clk\n", + __func__); + } else { + goto exit; + } + } + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg); + if (ret < 0) + goto exit; + } + +exit: + if (ret && __ratelimit(&rtl)) + pr_err_ratelimited("%s: afe_set_lpass_clk_cfg failed, ret = %d\n", + __func__, ret); } static u8 audio_ext_clk_get_parent(struct clk_hw *hw) @@ -518,6 +564,7 @@ static int audio_ref_clk_probe(struct platform_device *pdev) int ret; struct audio_ext_clk_priv *clk_priv; u32 clk_freq = 0, clk_id = 0, clk_src = 0, use_pinctrl = 0; + u32 ext_mclk_src_freq = 0; clk_priv = devm_kzalloc(&pdev->dev, sizeof(*clk_priv), GFP_KERNEL); if (!clk_priv) @@ -561,9 +608,27 @@ static int audio_ref_clk_probe(struct platform_device *pdev) if (!ret) clk_priv->clk_cfg.clk_id = clk_id; + if (of_property_read_bool(pdev->dev.of_node, + "qcom,supports-ext-mclk")) + clk_priv->supports_ext_mclk = true; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,ext-mclk-src-freq", + &ext_mclk_src_freq); + if (!ret) { + clk_priv->ext_mclk_freq = ext_mclk_src_freq; + } else if (clk_priv->supports_ext_mclk) { + dev_err(&pdev->dev, "%s: qcom,ext-mclk-src-freq not defined\n", + __func__); + return ret; + } + dev_dbg(&pdev->dev, "%s: ext-clk freq: %d, lpass clk_id: %d, clk_src: %d\n", - __func__, clk_priv->clk_cfg.clk_freq_in_hz, - clk_priv->clk_cfg.clk_id, clk_priv->clk_src); + __func__, clk_priv->clk_cfg.clk_freq_in_hz, + clk_priv->clk_cfg.clk_id, clk_priv->clk_src); + dev_dbg(&pdev->dev, "%s: supports-ext-mclk: %d, ext-mclk-input-freq: %d\n", + __func__, clk_priv->supports_ext_mclk, clk_priv->ext_mclk_freq); + platform_set_drvdata(pdev, clk_priv); ret = of_property_read_string(pdev->dev.of_node, "pmic-clock-names",