summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@nxp.com>2017-11-17 16:29:46 +0800
committerShengjiu Wang <shengjiu.wang@nxp.com>2017-11-17 17:21:19 +0800
commit8e919f858ac5f32667c9f73cddefd1ed726f0ae2 (patch)
treecfc0782a10b768e05cb0e9c30c97079dda0cce4c
parent2eec28f1703ae0a3c025e15c179f6c663dd326e8 (diff)
MLK-16839-1: ASoC: fsl_asrc: selec a proper clock source from the clock list
In internal ratio mode, when the clock rate can't be divided with no remainder, The final convert ratio is not as expected, there is distortion in output data. So need to select a proper clock source for this mode, if can't find a good clock source, then swith to ideal ratio mode. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> (cherry picked from commit 3be302e598f41e7edfc93b820453cff5fed27b1a)
-rw-r--r--sound/soc/fsl/fsl_asrc.c58
-rw-r--r--sound/soc/fsl/fsl_asrc.h1
2 files changed, 46 insertions, 13 deletions
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index d1290fb1b020..9293f67035a9 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -50,6 +50,7 @@ static struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = {
* The following tables map the relationship between asrc_inclk/asrc_outclk in
* fsl_asrc.h and the registers of ASRCSR
*/
+#define CLK_MAP_NUM 48
static unsigned char input_clk_map_imx35[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
@@ -101,7 +102,6 @@ static unsigned char output_clk_map_imx8_1[] = {
0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
};
-static unsigned char *clk_map[2];
/**
* Request ASRC pair
@@ -358,8 +358,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool p2p_in, bool p2
}
/* Validate input and output clock sources */
- clk_index[IN] = clk_map[IN][config->inclk];
- clk_index[OUT] = clk_map[OUT][config->outclk];
+ clk_index[IN] = asrc_priv->clk_map[IN][config->inclk];
+ clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk];
/* We only have output clock for ideal ratio mode */
clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]];
@@ -539,6 +539,30 @@ struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir)
}
EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel);
+static int fsl_asrc_select_clk(struct fsl_asrc *asrc_priv, int rate, int index)
+{
+ int clk_rate;
+ int clk_index;
+ int i = 0;
+
+ /*select proper clock for asrc p2p mode*/
+ for (i = 0; i < CLK_MAP_NUM; i++) {
+ clk_index = asrc_priv->clk_map[index][i];
+ clk_rate = clk_get_rate(asrc_priv->asrck_clk[clk_index]);
+ if (clk_rate != 0 && clk_rate/rate <= 1024 &&
+ clk_rate%rate == 0)
+ break;
+ }
+
+ if (i == CLK_MAP_NUM)
+ clk_index = index ? OUTCLK_ASRCK1_CLK : INCLK_NONE;
+ else
+ clk_index = i;
+
+
+ return clk_index;
+}
+
static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -573,8 +597,6 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
config.pair = pair->index;
config.channel_num = channels;
- config.inclk = INCLK_ASRCK1_CLK;
- config.outclk = OUTCLK_ASRCK1_CLK;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
config.input_word_width = width;
@@ -582,6 +604,11 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
config.input_sample_rate = rate;
config.output_sample_rate = asrc_priv->asrc_rate;
+ config.inclk = fsl_asrc_select_clk(asrc_priv,
+ config.input_sample_rate, IN);
+ config.outclk = fsl_asrc_select_clk(asrc_priv,
+ config.output_sample_rate, OUT);
+
ret = fsl_asrc_config_pair(pair, false, true);
if (ret) {
dev_err(dai->dev, "fail to config asrc pair\n");
@@ -594,6 +621,11 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
config.input_sample_rate = asrc_priv->asrc_rate;
config.output_sample_rate = rate;
+ config.inclk = fsl_asrc_select_clk(asrc_priv,
+ config.input_sample_rate, IN);
+ config.outclk = fsl_asrc_select_clk(asrc_priv,
+ config.output_sample_rate, OUT);
+
ret = fsl_asrc_config_pair(pair, true, false);
if (ret) {
dev_err(dai->dev, "fail to config asrc pair\n");
@@ -1073,26 +1105,26 @@ static int fsl_asrc_probe(struct platform_device *pdev)
asrc_priv->channel_bits = 3;
strncpy(asrc_priv->name, "mxc_asrc",
sizeof(asrc_priv->name) - 1);
- clk_map[IN] = input_clk_map_imx35;
- clk_map[OUT] = output_clk_map_imx35;
+ asrc_priv->clk_map[IN] = input_clk_map_imx35;
+ asrc_priv->clk_map[OUT] = output_clk_map_imx35;
} else if (of_device_is_compatible(np, "fsl,imx53-asrc")) {
asrc_priv->channel_bits = 4;
strncpy(asrc_priv->name, "mxc_asrc",
sizeof(asrc_priv->name) - 1);
- clk_map[IN] = input_clk_map_imx53;
- clk_map[OUT] = output_clk_map_imx53;
+ asrc_priv->clk_map[IN] = input_clk_map_imx53;
+ asrc_priv->clk_map[OUT] = output_clk_map_imx53;
} else if (of_device_is_compatible(np, "fsl,imx8qm-asrc0")) {
asrc_priv->channel_bits = 4;
strncpy(asrc_priv->name, "mxc_asrc",
sizeof(asrc_priv->name) - 1);
- clk_map[IN] = input_clk_map_imx8_0;
- clk_map[OUT] = output_clk_map_imx8_0;
+ asrc_priv->clk_map[IN] = input_clk_map_imx8_0;
+ asrc_priv->clk_map[OUT] = output_clk_map_imx8_0;
} else if (of_device_is_compatible(np, "fsl,imx8qm-asrc1")) {
asrc_priv->channel_bits = 4;
strncpy(asrc_priv->name, "mxc_asrc1",
sizeof(asrc_priv->name) - 1);
- clk_map[IN] = input_clk_map_imx8_1;
- clk_map[OUT] = output_clk_map_imx8_1;
+ asrc_priv->clk_map[IN] = input_clk_map_imx8_1;
+ asrc_priv->clk_map[OUT] = output_clk_map_imx8_1;
}
ret = fsl_asrc_init(asrc_priv);
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 204ac19b5d52..5d2f021846c9 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -358,6 +358,7 @@ struct fsl_asrc {
struct clk *ipg_clk;
struct clk *spba_clk;
struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
+ unsigned char *clk_map[2];
spinlock_t lock;
struct snd_pcm_substream *substream[2];