Merge "asoc: common: add lpass hw core request"

Dieser Commit ist enthalten in:
qctecmdr
2021-08-28 21:21:19 -07:00
committet von Gerrit - the friendly Code Review server
Commit 7c5ab24608
2 geänderte Dateien mit 138 neuen und 20 gelöschten Zeilen

Datei anzeigen

@@ -24,6 +24,7 @@
#include <dsp/msm_audio_ion.h>
#include <sound/info.h>
#include <dsp/audio_prm.h>
#include <dsp/digital-cdc-rsc-mgr.h>
#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,

Datei anzeigen

@@ -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);