From 7277bb11712a954b5504a88771d575c99bf7d209 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Sun, 15 Aug 2021 22:40:33 +0530 Subject: [PATCH] asoc: common: add lpass hw core request add lpass hw core request before request for the set clk cfg in the case of primary and tertiary interface along with fractional sample rate related clock request. Change-Id: I273e6963ee39e350c44e5bcf35427327b7189cd1 Signed-off-by: Prasad Kumpatla --- asoc/msm_common.c | 154 ++++++++++++++++++++++++++++++++++++++++------ asoc/msm_common.h | 4 ++ 2 files changed, 138 insertions(+), 20 deletions(-) diff --git a/asoc/msm_common.c b/asoc/msm_common.c index 002ef98607..438a5f3c1e 100644 --- a/asoc/msm_common.c +++ b/asoc/msm_common.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "msm_common.h" @@ -47,6 +48,11 @@ struct snd_card_pdata { #define TDM_MAX_SLOTS 8 #define MI2S_NUM_CHANNELS 2 +#define SAMPLING_RATE_44P1KHZ 44100 +#define SAMPLING_RATE_88P2KHZ 88200 +#define SAMPLING_RATE_176P4KHZ 176400 +#define SAMPLING_RATE_352P8KHZ 352800 + static struct attribute device_state_attr = { .name = "state", .mode = 0660, @@ -244,6 +250,20 @@ static int get_intf_index(const char *stream_name) return -EINVAL; } +static bool is_fractional_sample_rate(unsigned int sample_rate) +{ + switch (sample_rate) { + case SAMPLING_RATE_44P1KHZ: + case SAMPLING_RATE_88P2KHZ: + case SAMPLING_RATE_176P4KHZ: + case SAMPLING_RATE_352P8KHZ: + return true; + default: + return false; + } + return false; +} + static int get_mi2s_clk_id(int index) { int clk_id; @@ -306,6 +326,38 @@ static int get_tdm_clk_id(int index) return clk_id; } +int mi2s_tdm_hw_vote_req(struct msm_common_pdata *pdata, int enable) +{ + int ret = 0; + + if (!pdata || (pdata->lpass_audio_hw_vote == NULL)) { + pr_err("%s: pdata or lpass audio hw vote node NULL", __func__); + return -EINVAL; + } + + pr_debug("%s: lpass audio hw vote for fractional sample rate enable: %d\n", + __func__, enable); + + if (enable) { + if (atomic_read(&pdata->lpass_audio_hw_vote_ref_cnt) == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(pdata->lpass_audio_hw_vote); + if (ret < 0) { + pr_err("%s lpass audio hw vote enable failed %d\n", + __func__, ret); + return ret; + } + } + atomic_inc(&pdata->lpass_audio_hw_vote_ref_cnt); + } else { + atomic_dec(&pdata->lpass_audio_hw_vote_ref_cnt); + if (atomic_read(&pdata->lpass_audio_hw_vote_ref_cnt) == 0) + digital_cdc_rsc_mgr_hw_vote_disable(pdata->lpass_audio_hw_vote); + else if (atomic_read(&pdata->lpass_audio_hw_vote_ref_cnt) < 0) + atomic_set(&pdata->lpass_audio_hw_vote_ref_cnt, 0); + } + return ret; +} + int msm_common_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -332,7 +384,7 @@ int msm_common_snd_hw_params(struct snd_pcm_substream *substream, if (index >= 0) { mutex_lock(&pdata->lock[index]); - if (pdata->mi2s_gpio_p[index]) { + if (atomic_read(&pdata->lpass_intf_clk_ref_cnt[index]) == 0) { if ((strnstr(stream_name, "TDM", strlen(stream_name)))) { slots = pdata->tdm_max_slots; rate = params_rate(params); @@ -349,6 +401,15 @@ int msm_common_snd_hw_params(struct snd_pcm_substream *substream, intf_clk_cfg.clk_attri = CLOCK_ATTRIBUTE_COUPLE_NO; intf_clk_cfg.clk_root = 0; + if (pdata->is_audio_hw_vote_required[index] && + is_fractional_sample_rate(rate)) { + ret = mi2s_tdm_hw_vote_req(pdata, 1); + if (ret < 0) { + pr_err("%s lpass audio hw vote enable failed %d\n", + __func__, ret); + goto done; + } + } pr_debug("%s: clk_id :%d clk freq %d\n", __func__, intf_clk_cfg.clk_id, intf_clk_cfg.clk_freq_in_hz); ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 1); @@ -379,11 +440,21 @@ int msm_common_snd_hw_params(struct snd_pcm_substream *substream, pr_debug("%s: bitwidth set to default : %d\n", __func__, sample_width); } + intf_clk_cfg.clk_freq_in_hz = rate * MI2S_NUM_CHANNELS * sample_width; intf_clk_cfg.clk_attri = CLOCK_ATTRIBUTE_COUPLE_NO; intf_clk_cfg.clk_root = CLOCK_ROOT_DEFAULT; + if (pdata->is_audio_hw_vote_required[index] && + is_fractional_sample_rate(rate)) { + ret = mi2s_tdm_hw_vote_req(pdata, 1); + if (ret < 0) { + pr_err("%s lpass audio hw vote enable failed %d\n", + __func__, ret); + goto done; + } + } pr_debug("%s: mi2s clk_id :%d clk freq %d\n", __func__, intf_clk_cfg.clk_id, intf_clk_cfg.clk_freq_in_hz); ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 1); @@ -396,8 +467,8 @@ int msm_common_snd_hw_params(struct snd_pcm_substream *substream, pr_err("%s: invalid stream name: %s\n", __func__, stream_name); } - } + atomic_inc(&pdata->lpass_intf_clk_ref_cnt[index]); done: mutex_unlock(&pdata->lock[index]); } @@ -448,9 +519,11 @@ void msm_common_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct msm_common_pdata *pdata = msm_common_get_pdata(card); + struct snd_pcm_runtime *runtime = substream->runtime; const char *stream_name = rtd->dai_link->stream_name; int index = get_intf_index(stream_name); struct clk_cfg intf_clk_cfg; + unsigned int rate = runtime->rate; memset(&intf_clk_cfg, 0, sizeof(struct clk_cfg)); pr_debug("%s(): substream = %s stream = %d\n", __func__, @@ -465,31 +538,46 @@ void msm_common_snd_shutdown(struct snd_pcm_substream *substream) if (index >= 0) { mutex_lock(&pdata->lock[index]); + atomic_dec(&pdata->lpass_intf_clk_ref_cnt[index]); + if (atomic_read(&pdata->lpass_intf_clk_ref_cnt[index]) == 0) { + if ((strnstr(stream_name, "TDM", strlen(stream_name)))) { + intf_clk_cfg.clk_id = get_tdm_clk_id(index); + pr_debug("%s: Disable clock ID: %d\n", __func__, intf_clk_cfg.clk_id); + ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 0); + if (ret < 0) + pr_err("%s: prm clk cfg set failed ret %d\n", + __func__, ret); + } else if((strnstr(stream_name, "MI2S", strlen(stream_name)))) { + intf_clk_cfg.clk_id = get_mi2s_clk_id(index); + pr_debug("%s: Disable clock ID: %d\n", __func__, intf_clk_cfg.clk_id); + ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 0); + if (ret < 0) + pr_err("%s: prm mi2s clk cfg disable failed ret %d\n", + __func__, ret); + } else { + pr_err("%s: invalid stream name: %s\n", + __func__, stream_name); + } + + if (pdata->is_audio_hw_vote_required[index] && + is_fractional_sample_rate(rate)) { + ret = mi2s_tdm_hw_vote_req(pdata, 0); + } + } else if (atomic_read(&pdata->lpass_intf_clk_ref_cnt[index]) < 0) { + atomic_set(&pdata->lpass_intf_clk_ref_cnt[index], 0); + } + if (pdata->mi2s_gpio_p[index]) { atomic_dec(&pdata->mi2s_gpio_ref_cnt[index]); - if (atomic_read(&pdata->mi2s_gpio_ref_cnt[index]) == 0) { - if ((strnstr(stream_name, "TDM", strlen(stream_name)))) { - intf_clk_cfg.clk_id = get_tdm_clk_id(index); - ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 0); - if (ret < 0) - pr_err("%s: prm clk cfg set failed ret %d\n", - __func__, ret); - } else if((strnstr(stream_name, "MI2S", strlen(stream_name)))) { - intf_clk_cfg.clk_id = get_mi2s_clk_id(index); - ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 0); - if (ret < 0) - pr_err("%s: prm mi2s clk cfg disable failed ret %d\n", - __func__, ret); - } else { - pr_err("%s: invalid stream name: %s\n", - __func__, stream_name); - } + if (atomic_read(&pdata->mi2s_gpio_ref_cnt[index]) == 0) { ret = msm_cdc_pinctrl_select_sleep_state( - pdata->mi2s_gpio_p[index]); + pdata->mi2s_gpio_p[index]); if (ret) dev_err(card->dev, "%s: pinctrl set actv fail %d\n", __func__, ret); + } else if (atomic_read(&pdata->mi2s_gpio_ref_cnt[index]) < 0) { + atomic_set(&pdata->mi2s_gpio_ref_cnt[index], 0); } } mutex_unlock(&pdata->lock[index]); @@ -500,6 +588,8 @@ int msm_common_snd_init(struct platform_device *pdev, struct snd_soc_card *card) { struct msm_common_pdata *common_pdata = NULL; int count, ret = 0; + uint32_t lpass_audio_hw_vote_required[MI2S_TDM_AUXPCM_MAX] = {0}; + struct clk *lpass_audio_hw_vote = NULL; common_pdata = kcalloc(1, sizeof(struct msm_common_pdata), GFP_KERNEL); if (!common_pdata) @@ -523,6 +613,30 @@ int msm_common_snd_init(struct platform_device *pdev, struct snd_soc_card *card) __func__, common_pdata->tdm_max_slots); } + /* Register LPASS audio hw vote */ + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + common_pdata->lpass_audio_hw_vote = lpass_audio_hw_vote; + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,mi2s-tdm-is-hw-vote-needed", + lpass_audio_hw_vote_required, MI2S_TDM_AUXPCM_MAX); + if (ret) { + dev_dbg(&pdev->dev, "%s:no qcom,mi2s-tdm-is-hw-vote-needed in DT node\n", + __func__); + } else { + for (count = 0; count < MI2S_TDM_AUXPCM_MAX; count++) { + common_pdata->is_audio_hw_vote_required[count] = + lpass_audio_hw_vote_required[count]; + } + } + common_pdata->mi2s_gpio_p[PRI_MI2S_TDM_AUXPCM] = of_parse_phandle(pdev->dev.of_node, "qcom,pri-mi2s-gpios", 0); common_pdata->mi2s_gpio_p[SEC_MI2S_TDM_AUXPCM] = of_parse_phandle(pdev->dev.of_node, diff --git a/asoc/msm_common.h b/asoc/msm_common.h index 7a091f3c6d..2df9193f95 100644 --- a/asoc/msm_common.h +++ b/asoc/msm_common.h @@ -40,6 +40,10 @@ struct msm_common_pdata { struct mutex lock[MI2S_TDM_AUXPCM_MAX]; u32 tdm_max_slots; /* Max TDM slots used */ atomic_t mi2s_gpio_ref_cnt[MI2S_TDM_AUXPCM_MAX]; + atomic_t lpass_intf_clk_ref_cnt[MI2S_TDM_AUXPCM_MAX]; + atomic_t lpass_audio_hw_vote_ref_cnt; + struct clk *lpass_audio_hw_vote; + uint32_t is_audio_hw_vote_required[MI2S_TDM_AUXPCM_MAX]; }; int snd_card_notify_user(int card_status);