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