Skip to content

Commit 3203863

Browse files
TE-N-ShengjiuWangbroonie
authored andcommitted
ASoC: fsl_asrc: refine the check of available clock divider
According to RM, the clock divider range is from 1 to 8, clock prescaling ratio may be any power of 2 from 1 to 128. So the supported divider is not all the value between 1 and 1024, just limited value in that range. Create table for the supported divder and add function to check the clock divider is available by comparing with the table. Fixes: d0250cf ("ASoC: fsl_asrc: Add an option to select internal ratio mode") Signed-off-by: Shengjiu Wang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 44125fd commit 3203863

File tree

1 file changed

+58
-11
lines changed

1 file changed

+58
-11
lines changed

sound/soc/fsl/fsl_asrc.c

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "fsl_asrc.h"
2020

2121
#define IDEAL_RATIO_DECIMAL_DEPTH 26
22+
#define DIVIDER_NUM 64
2223

2324
#define pair_err(fmt, ...) \
2425
dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
@@ -101,6 +102,55 @@ static unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = {
101102
},
102103
};
103104

105+
/*
106+
* According to RM, the divider range is 1 ~ 8,
107+
* prescaler is power of 2 from 1 ~ 128.
108+
*/
109+
static int asrc_clk_divider[DIVIDER_NUM] = {
110+
1, 2, 4, 8, 16, 32, 64, 128, /* divider = 1 */
111+
2, 4, 8, 16, 32, 64, 128, 256, /* divider = 2 */
112+
3, 6, 12, 24, 48, 96, 192, 384, /* divider = 3 */
113+
4, 8, 16, 32, 64, 128, 256, 512, /* divider = 4 */
114+
5, 10, 20, 40, 80, 160, 320, 640, /* divider = 5 */
115+
6, 12, 24, 48, 96, 192, 384, 768, /* divider = 6 */
116+
7, 14, 28, 56, 112, 224, 448, 896, /* divider = 7 */
117+
8, 16, 32, 64, 128, 256, 512, 1024, /* divider = 8 */
118+
};
119+
120+
/*
121+
* Check if the divider is available for internal ratio mode
122+
*/
123+
static bool fsl_asrc_divider_avail(int clk_rate, int rate, int *div)
124+
{
125+
u32 rem, i;
126+
u64 n;
127+
128+
if (div)
129+
*div = 0;
130+
131+
if (clk_rate == 0 || rate == 0)
132+
return false;
133+
134+
n = clk_rate;
135+
rem = do_div(n, rate);
136+
137+
if (div)
138+
*div = n;
139+
140+
if (rem != 0)
141+
return false;
142+
143+
for (i = 0; i < DIVIDER_NUM; i++) {
144+
if (n == asrc_clk_divider[i])
145+
break;
146+
}
147+
148+
if (i == DIVIDER_NUM)
149+
return false;
150+
151+
return true;
152+
}
153+
104154
/**
105155
* fsl_asrc_sel_proc - Select the pre-processing and post-processing options
106156
* @inrate: input sample rate
@@ -330,12 +380,12 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
330380
enum asrc_word_width input_word_width;
331381
enum asrc_word_width output_word_width;
332382
u32 inrate, outrate, indiv, outdiv;
333-
u32 clk_index[2], div[2], rem[2];
383+
u32 clk_index[2], div[2];
334384
u64 clk_rate;
335385
int in, out, channels;
336386
int pre_proc, post_proc;
337387
struct clk *clk;
338-
bool ideal;
388+
bool ideal, div_avail;
339389

340390
if (!config) {
341391
pair_err("invalid pair config\n");
@@ -415,8 +465,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
415465
clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]];
416466

417467
clk_rate = clk_get_rate(clk);
418-
rem[IN] = do_div(clk_rate, inrate);
419-
div[IN] = (u32)clk_rate;
468+
div_avail = fsl_asrc_divider_avail(clk_rate, inrate, &div[IN]);
420469

421470
/*
422471
* The divider range is [1, 1024], defined by the hardware. For non-
@@ -425,7 +474,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
425474
* only result in different converting speeds. So remainder does not
426475
* matter, as long as we keep the divider within its valid range.
427476
*/
428-
if (div[IN] == 0 || (!ideal && (div[IN] > 1024 || rem[IN] != 0))) {
477+
if (div[IN] == 0 || (!ideal && !div_avail)) {
429478
pair_err("failed to support input sample rate %dHz by asrck_%x\n",
430479
inrate, clk_index[ideal ? OUT : IN]);
431480
return -EINVAL;
@@ -436,13 +485,12 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
436485
clk = asrc_priv->asrck_clk[clk_index[OUT]];
437486
clk_rate = clk_get_rate(clk);
438487
if (ideal && use_ideal_rate)
439-
rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE);
488+
div_avail = fsl_asrc_divider_avail(clk_rate, IDEAL_RATIO_RATE, &div[OUT]);
440489
else
441-
rem[OUT] = do_div(clk_rate, outrate);
442-
div[OUT] = clk_rate;
490+
div_avail = fsl_asrc_divider_avail(clk_rate, outrate, &div[OUT]);
443491

444492
/* Output divider has the same limitation as the input one */
445-
if (div[OUT] == 0 || (!ideal && (div[OUT] > 1024 || rem[OUT] != 0))) {
493+
if (div[OUT] == 0 || (!ideal && !div_avail)) {
446494
pair_err("failed to support output sample rate %dHz by asrck_%x\n",
447495
outrate, clk_index[OUT]);
448496
return -EINVAL;
@@ -621,8 +669,7 @@ static void fsl_asrc_select_clk(struct fsl_asrc_priv *asrc_priv,
621669
clk_index = asrc_priv->clk_map[j][i];
622670
clk_rate = clk_get_rate(asrc_priv->asrck_clk[clk_index]);
623671
/* Only match a perfect clock source with no remainder */
624-
if (clk_rate != 0 && (clk_rate / rate[j]) <= 1024 &&
625-
(clk_rate % rate[j]) == 0)
672+
if (fsl_asrc_divider_avail(clk_rate, rate[j], NULL))
626673
break;
627674
}
628675

0 commit comments

Comments
 (0)