asoc: common: configure mi2s interface clocks

Add support for mi2s interface clock configuration.

Change-Id: I439de17670d9521898d8bde893255025eceab84d
Signed-off-by: Prasad Kumpatla <pkumpatl@codeaurora.org>
This commit is contained in:
Prasad Kumpatla
2021-08-05 16:42:48 +05:30
parent 043966829b
commit d8f2af06e6
2 changed files with 114 additions and 22 deletions

View File

@@ -23,7 +23,6 @@
#include <dsp/spf-core.h> #include <dsp/spf-core.h>
#include <dsp/msm_audio_ion.h> #include <dsp/msm_audio_ion.h>
#include <sound/info.h> #include <sound/info.h>
#include <dsp/apr_audio-v2.h>
#include <dsp/audio_prm.h> #include <dsp/audio_prm.h>
#include "msm_common.h" #include "msm_common.h"
@@ -46,6 +45,7 @@ struct snd_card_pdata {
#define MAX_CODEC_DAI 8 #define MAX_CODEC_DAI 8
#define TDM_SLOT_WIDTH_BITS 32 #define TDM_SLOT_WIDTH_BITS 32
#define TDM_MAX_SLOTS 8 #define TDM_MAX_SLOTS 8
#define MI2S_NUM_CHANNELS 2
static struct attribute device_state_attr = { static struct attribute device_state_attr = {
.name = "state", .name = "state",
@@ -244,28 +244,59 @@ static int get_intf_index(const char *stream_name)
return -EINVAL; return -EINVAL;
} }
static int get_intf_clk_id(int index) static int get_mi2s_clk_id(int index)
{
int clk_id;
switch(index) {
case PRI_MI2S_TDM_AUXPCM:
clk_id = CLOCK_ID_PRI_MI2S_IBIT;
break;
case SEC_MI2S_TDM_AUXPCM:
clk_id = CLOCK_ID_SEP_MI2S_IBIT;
break;
case TER_MI2S_TDM_AUXPCM:
clk_id = CLOCK_ID_TER_MI2S_IBIT;
break;
case QUAT_MI2S_TDM_AUXPCM:
clk_id = CLOCK_ID_QUAD_MI2S_IBIT;
break;
case QUIN_MI2S_TDM_AUXPCM:
clk_id = CLOCK_ID_QUI_MI2S_IBIT;
break;
case SEN_MI2S_TDM_AUXPCM:
clk_id = CLOCK_ID_SEN_MI2S_IBIT;
break;
default:
pr_err("%s: Invalid interface index: %d\n", __func__, index);
clk_id = -EINVAL;
}
pr_debug("%s: clk id: %d\n", __func__, clk_id);
return clk_id;
}
static int get_tdm_clk_id(int index)
{ {
int clk_id; int clk_id;
switch(index) { switch(index) {
case PRI_MI2S_TDM_AUXPCM: case PRI_MI2S_TDM_AUXPCM:
clk_id = Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT; clk_id = CLOCK_ID_PRI_TDM_IBIT;
break; break;
case SEC_MI2S_TDM_AUXPCM: case SEC_MI2S_TDM_AUXPCM:
clk_id = Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT; clk_id = CLOCK_ID_SEP_TDM_IBIT;
break; break;
case TER_MI2S_TDM_AUXPCM: case TER_MI2S_TDM_AUXPCM:
clk_id = Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT; clk_id = CLOCK_ID_TER_TDM_IBIT;
break; break;
case QUAT_MI2S_TDM_AUXPCM: case QUAT_MI2S_TDM_AUXPCM:
clk_id = Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT; clk_id = CLOCK_ID_QUAD_TDM_IBIT;
break; break;
case QUIN_MI2S_TDM_AUXPCM: case QUIN_MI2S_TDM_AUXPCM:
clk_id = Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT; clk_id = CLOCK_ID_QUI_TDM_IBIT;
break; break;
case SEN_MI2S_TDM_AUXPCM: case SEN_MI2S_TDM_AUXPCM:
clk_id = Q6AFE_LPASS_CLK_ID_SEN_TDM_IBIT; clk_id = CLOCK_ID_SEN_TDM_IBIT;
break; break;
default: default:
pr_err("%s: Invalid interface index: %d\n", __func__, index); pr_err("%s: Invalid interface index: %d\n", __func__, index);
@@ -281,13 +312,14 @@ int msm_common_snd_hw_params(struct snd_pcm_substream *substream,
int ret = 0; int ret = 0;
int slot_width = TDM_SLOT_WIDTH_BITS; int slot_width = TDM_SLOT_WIDTH_BITS;
int slots; int slots;
int sample_width;
unsigned int rate; unsigned int rate;
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
const char *stream_name = rtd->dai_link->stream_name; const char *stream_name = rtd->dai_link->stream_name;
struct snd_soc_card *card = rtd->card; struct snd_soc_card *card = rtd->card;
struct msm_common_pdata *pdata = msm_common_get_pdata(card); struct msm_common_pdata *pdata = msm_common_get_pdata(card);
int index = get_intf_index(stream_name); int index = get_intf_index(stream_name);
struct clk_cfg tdm_clk_cfg; struct clk_cfg intf_clk_cfg;
dev_dbg(rtd->card->dev, dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d\n", "%s: substream = %s stream = %d\n",
@@ -305,27 +337,66 @@ int msm_common_snd_hw_params(struct snd_pcm_substream *substream,
slots = pdata->tdm_max_slots; slots = pdata->tdm_max_slots;
rate = params_rate(params); rate = params_rate(params);
tdm_clk_cfg.clk_id = get_intf_clk_id(index); intf_clk_cfg.clk_id = get_tdm_clk_id(index);
if (tdm_clk_cfg.clk_id < 0) { if (intf_clk_cfg.clk_id < 0) {
ret = -EINVAL; ret = -EINVAL;
pr_err("%s: Invalid clk id %d", __func__, pr_err("%s: Invalid tdm clk id %d", __func__,
tdm_clk_cfg.clk_id); intf_clk_cfg.clk_id);
goto done; goto done;
} }
tdm_clk_cfg.clk_freq_in_hz = rate * slot_width * slots; intf_clk_cfg.clk_freq_in_hz = rate * slot_width * slots;
tdm_clk_cfg.clk_attri = Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO; intf_clk_cfg.clk_attri = CLOCK_ATTRIBUTE_COUPLE_NO;
tdm_clk_cfg.clk_root = 0; intf_clk_cfg.clk_root = 0;
pr_debug("%s: clk_id :%d clk freq %d\n", __func__, pr_debug("%s: clk_id :%d clk freq %d\n", __func__,
tdm_clk_cfg.clk_id, tdm_clk_cfg.clk_freq_in_hz); intf_clk_cfg.clk_id, intf_clk_cfg.clk_freq_in_hz);
ret = audio_prm_set_lpass_clk_cfg(&tdm_clk_cfg, 1); ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 1);
if (ret < 0) { if (ret < 0) {
pr_err("%s: prm lpass clk cfg set failed ret %d\n", pr_err("%s: prm lpass clk cfg set failed ret %d\n",
__func__, ret); __func__, ret);
goto done; goto done;
} }
} else if ((strnstr(stream_name, "MI2S", strlen(stream_name)))) {
intf_clk_cfg.clk_id = get_mi2s_clk_id(index);
if (intf_clk_cfg.clk_id < 0) {
ret = -EINVAL;
pr_err("%s: Invalid mi2s clk id %d", __func__,
intf_clk_cfg.clk_id);
goto done;
}
rate = params_rate(params);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S32_LE:
sample_width = 32;
break;
case SNDRV_PCM_FORMAT_S16_LE:
default:
sample_width = 16;
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;
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);
if (ret < 0) {
pr_err("%s: prm lpass mi2s clk cfg set failed ret %d\n",
__func__, ret);
goto done;
}
} else {
pr_err("%s: invalid stream name: %s\n", __func__,
stream_name);
} }
} }
done: done:
mutex_unlock(&pdata->lock[index]); mutex_unlock(&pdata->lock[index]);
@@ -379,9 +450,9 @@ void msm_common_snd_shutdown(struct snd_pcm_substream *substream)
struct msm_common_pdata *pdata = msm_common_get_pdata(card); struct msm_common_pdata *pdata = msm_common_get_pdata(card);
const char *stream_name = rtd->dai_link->stream_name; const char *stream_name = rtd->dai_link->stream_name;
int index = get_intf_index(stream_name); int index = get_intf_index(stream_name);
struct clk_cfg tdm_clk_cfg; struct clk_cfg intf_clk_cfg;
memset(&tdm_clk_cfg, 0, sizeof(struct clk_cfg)); memset(&intf_clk_cfg, 0, sizeof(struct clk_cfg));
pr_debug("%s(): substream = %s stream = %d\n", __func__, pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream); substream->name, substream->stream);
@@ -398,11 +469,20 @@ void msm_common_snd_shutdown(struct snd_pcm_substream *substream)
atomic_dec(&pdata->mi2s_gpio_ref_cnt[index]); atomic_dec(&pdata->mi2s_gpio_ref_cnt[index]);
if (atomic_read(&pdata->mi2s_gpio_ref_cnt[index]) == 0) { if (atomic_read(&pdata->mi2s_gpio_ref_cnt[index]) == 0) {
if ((strnstr(stream_name, "TDM", strlen(stream_name)))) { if ((strnstr(stream_name, "TDM", strlen(stream_name)))) {
tdm_clk_cfg.clk_id = get_intf_clk_id(index); intf_clk_cfg.clk_id = get_tdm_clk_id(index);
ret = audio_prm_set_lpass_clk_cfg(&tdm_clk_cfg, 0); ret = audio_prm_set_lpass_clk_cfg(&intf_clk_cfg, 0);
if (ret < 0) if (ret < 0)
pr_err("%s: prm clk cfg set failed ret %d\n", pr_err("%s: prm clk cfg set failed ret %d\n",
__func__, ret); __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);
} }
ret = msm_cdc_pinctrl_select_sleep_state( ret = msm_cdc_pinctrl_select_sleep_state(
pdata->mi2s_gpio_p[index]); pdata->mi2s_gpio_p[index]);

View File

@@ -292,6 +292,12 @@ typedef struct prm_cmd_request_hw_core_t
#define CLOCK_ID_SEN_MI2S_EBIT 0x10C #define CLOCK_ID_SEN_MI2S_EBIT 0x10C
/** Clock ID of the septenary MI2S IBIT. */
#define CLOCK_ID_SEP_MI2S_IBIT 0x10D
/** Clock ID of the septenary MI2S EBIT. */
#define CLOCK_ID_SEP_MI2S_EBIT 0x10E
/** ID of I2S IBIT clock 0 that is used with integrated codec. */ /** ID of I2S IBIT clock 0 that is used with integrated codec. */
#define CLOCK_ID_INT0_I2S_IBIT 0x10D #define CLOCK_ID_INT0_I2S_IBIT 0x10D
@@ -424,6 +430,12 @@ typedef struct prm_cmd_request_hw_core_t
#define CLOCK_ID_SEN_TDM_EBIT 0x20C #define CLOCK_ID_SEN_TDM_EBIT 0x20C
/** Clock ID of the septenary TDM IBIT. */
#define CLOCK_ID_SEP_TDM_IBIT 0x20D
/** Clock ID of the septenary TDM EBIT. */
#define CLOCK_ID_SEP_TDM_EBIT 0x20E
/** Clock ID for MCLK 1. */ /** Clock ID for MCLK 1. */
#define CLOCK_ID_MCLK_1 0x300 #define CLOCK_ID_MCLK_1 0x300