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:
@@ -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]);
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user