diff mbox series

[RESEND] clk: si5351: update multisynth limits

Message ID 20211208154238.71727-1-renner@efe-gmbh.de (mailing list archive)
State Changes Requested, archived
Headers show
Series [RESEND] clk: si5351: update multisynth limits | expand

Commit Message

Jens Renner Dec. 8, 2021, 3:42 p.m. UTC
The revised datasheet (rev. 1.0 and later) specifies new limits for the
multisynth dividers that lead to an extended clock output frequency
range of 2.5 kHz - 200 MHz [1].

[1] https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public
/data-sheets/Si5351-B.pdf

Signed-off-by: Jens Renner <renner@efe-gmbh.de>
---
 drivers/clk/clk-si5351.c | 15 ++++++++-------
 drivers/clk/clk-si5351.h |  8 ++++----
 2 files changed, 12 insertions(+), 11 deletions(-)

Comments

Waseem Arshad Sept. 5, 2022, 2:38 p.m. UTC | #1
Hi Jens,

I had problems generating correct frequency values with your patch.

On 12/8/21 16:42, Jens Renner wrote:

> The revised datasheet (rev. 1.0 and later) specifies new limits for the
> multisynth dividers that lead to an extended clock output frequency
> range of 2.5 kHz - 200 MHz [1].
>
> [1] https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public
> /data-sheets/Si5351-B.pdf
>
> Signed-off-by: Jens Renner <renner@efe-gmbh.de>
> ---
>   drivers/clk/clk-si5351.c | 15 ++++++++-------
>   drivers/clk/clk-si5351.h |  8 ++++----
>   2 files changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
> index 57e4597cdf4c..56bc59f91d20 100644
> --- a/drivers/clk/clk-si5351.c
> +++ b/drivers/clk/clk-si5351.c
> @@ -556,7 +556,7 @@ static const struct clk_ops si5351_pll_ops = {
>    * MS[6,7] are integer (P1) divide only, P1 = divide value,
>    * P2 and P3 are not applicable
>    *
> - * for 150MHz < fOUT <= 160MHz:
> + * for 150MHz < fOUT <= 200MHz:
>    *
>    * MSx_P1 = 0, MSx_P2 = 0, MSx_P3 = 1, MSx_INT = 1, MSx_DIVBY4 = 11b
>    */
> @@ -653,7 +653,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
>   	if (hwdata->num >= 6 && rate > SI5351_MULTISYNTH67_MAX_FREQ)
>   		rate = SI5351_MULTISYNTH67_MAX_FREQ;
>   
> -	/* multisync frequency is 1MHz .. 160MHz */
> +	/* multisync frequency is 300kHz .. 200MHz */
>   	if (rate > SI5351_MULTISYNTH_MAX_FREQ)
>   		rate = SI5351_MULTISYNTH_MAX_FREQ;
>   	if (rate < SI5351_MULTISYNTH_MIN_FREQ)
> @@ -681,8 +681,8 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
>   
>   		*parent_rate = a * rate;
>   	} else if (hwdata->num >= 6) {
> -		/* determine the closest integer divider */
> -		a = DIV_ROUND_CLOSEST(*parent_rate, rate);
> +		/* determine the closest even integer divider */
> +		a = DIV_ROUND_CLOSEST(*parent_rate/2, rate) * 2;
>   		if (a < SI5351_MULTISYNTH_A_MIN)
>   			a = SI5351_MULTISYNTH_A_MIN;
>   		if (a > SI5351_MULTISYNTH67_A_MAX)
> @@ -715,7 +715,8 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
>   
>   		b = 0;
>   		c = 1;
> -		if (rfrac)
> +		/* Smallest divider in fractional mode must be > 8 (AN619)! */
> +		if (rfrac && (a >= 8))
>   			rational_best_approximation(rfrac, denom,
>   			    SI5351_MULTISYNTH_B_MAX, SI5351_MULTISYNTH_C_MAX,
>   			    &b, &c);
> @@ -1039,11 +1040,11 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
>   		container_of(hw, struct si5351_hw_data, hw);
>   	unsigned char rdiv;
>   
> -	/* clkout6/7 can only handle output freqencies < 150MHz */
> +	/* clkout6/7 can only handle output frequencies < 150MHz */
>   	if (hwdata->num >= 6 && rate > SI5351_CLKOUT67_MAX_FREQ)
>   		rate = SI5351_CLKOUT67_MAX_FREQ;
>   
> -	/* clkout freqency is 8kHz - 160MHz */
> +	/* clkout frequency is 2.5kHz - 200MHz */
>   	if (rate > SI5351_CLKOUT_MAX_FREQ)
>   		rate = SI5351_CLKOUT_MAX_FREQ;
>   	if (rate < SI5351_CLKOUT_MIN_FREQ)
> diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h
> index 73dc8effc519..f799dc6ea8a1 100644
> --- a/drivers/clk/clk-si5351.h
> +++ b/drivers/clk/clk-si5351.h
> @@ -13,11 +13,11 @@
>   
>   #define SI5351_PLL_VCO_MIN			600000000
>   #define SI5351_PLL_VCO_MAX			900000000
> -#define SI5351_MULTISYNTH_MIN_FREQ		1000000
> +#define SI5351_MULTISYNTH_MIN_FREQ		300000

 > The lower limit should be 500KHz (AN619: 
https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/application-notes/AN619.pdf)

Changing the lower limit in your patch to 500KHz solved the problem.

>   #define SI5351_MULTISYNTH_DIVBY4_FREQ		150000000
> -#define SI5351_MULTISYNTH_MAX_FREQ		160000000
> +#define SI5351_MULTISYNTH_MAX_FREQ		200000000
>   #define SI5351_MULTISYNTH67_MAX_FREQ		SI5351_MULTISYNTH_DIVBY4_FREQ
> -#define SI5351_CLKOUT_MIN_FREQ			8000
> +#define SI5351_CLKOUT_MIN_FREQ			2500
>   #define SI5351_CLKOUT_MAX_FREQ			SI5351_MULTISYNTH_MAX_FREQ
>   #define SI5351_CLKOUT67_MAX_FREQ		SI5351_MULTISYNTH67_MAX_FREQ
>   
> @@ -26,7 +26,7 @@
>   #define SI5351_PLL_B_MAX			(SI5351_PLL_C_MAX-1)
>   #define SI5351_PLL_C_MAX			1048575
>   #define SI5351_MULTISYNTH_A_MIN			6
> -#define SI5351_MULTISYNTH_A_MAX			1800
> +#define SI5351_MULTISYNTH_A_MAX			2048
>   #define SI5351_MULTISYNTH67_A_MAX		254
>   #define SI5351_MULTISYNTH_B_MAX			(SI5351_MULTISYNTH_C_MAX-1)
>   #define SI5351_MULTISYNTH_C_MAX			1048575
Jens Renner Sept. 5, 2022, 4:55 p.m. UTC | #2
Hi Waseem,

Thanks for figuring that out.
It was a misconception on my side as I assumed that the theoretical 
limit for SI5351_MULTISYNTH_MIN_FREQ is defined by the lowest PLL 
frequency (SI5351_PLL_VCO_MIN = 600 MHz) divided by the largest 
Multisynth divider SI5351_MULTISYNTH_A_MAX of 2048 which gives a value 
of ~ 300 kHz.

Am 05.09.22 um 16:38 schrieb Waseem Arshad:
> Hi Jens,
> 
> I had problems generating correct frequency values with your patch.
> 
> On 12/8/21 16:42, Jens Renner wrote:
> 
>> The revised datasheet (rev. 1.0 and later) specifies new limits for the
>> multisynth dividers that lead to an extended clock output frequency
>> range of 2.5 kHz - 200 MHz [1].
>>
>> [1] https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public
>> /data-sheets/Si5351-B.pdf
>>
>> Signed-off-by: Jens Renner <renner@efe-gmbh.de>
>> ---
>>   drivers/clk/clk-si5351.c | 15 ++++++++-------
>>   drivers/clk/clk-si5351.h |  8 ++++----
>>   2 files changed, 12 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
>> index 57e4597cdf4c..56bc59f91d20 100644
>> --- a/drivers/clk/clk-si5351.c
>> +++ b/drivers/clk/clk-si5351.c
>> @@ -556,7 +556,7 @@ static const struct clk_ops si5351_pll_ops = {
>>    * MS[6,7] are integer (P1) divide only, P1 = divide value,
>>    * P2 and P3 are not applicable
>>    *
>> - * for 150MHz < fOUT <= 160MHz:
>> + * for 150MHz < fOUT <= 200MHz:
>>    *
>>    * MSx_P1 = 0, MSx_P2 = 0, MSx_P3 = 1, MSx_INT = 1, MSx_DIVBY4 = 11b
>>    */
>> @@ -653,7 +653,7 @@ static long si5351_msynth_round_rate(struct clk_hw 
>> *hw, unsigned long rate,
>>       if (hwdata->num >= 6 && rate > SI5351_MULTISYNTH67_MAX_FREQ)
>>           rate = SI5351_MULTISYNTH67_MAX_FREQ;
>> -    /* multisync frequency is 1MHz .. 160MHz */
>> +    /* multisync frequency is 300kHz .. 200MHz */
>>       if (rate > SI5351_MULTISYNTH_MAX_FREQ)
>>           rate = SI5351_MULTISYNTH_MAX_FREQ;
>>       if (rate < SI5351_MULTISYNTH_MIN_FREQ)
>> @@ -681,8 +681,8 @@ static long si5351_msynth_round_rate(struct clk_hw 
>> *hw, unsigned long rate,
>>           *parent_rate = a * rate;
>>       } else if (hwdata->num >= 6) {
>> -        /* determine the closest integer divider */
>> -        a = DIV_ROUND_CLOSEST(*parent_rate, rate);
>> +        /* determine the closest even integer divider */
>> +        a = DIV_ROUND_CLOSEST(*parent_rate/2, rate) * 2;
>>           if (a < SI5351_MULTISYNTH_A_MIN)
>>               a = SI5351_MULTISYNTH_A_MIN;
>>           if (a > SI5351_MULTISYNTH67_A_MAX)
>> @@ -715,7 +715,8 @@ static long si5351_msynth_round_rate(struct clk_hw 
>> *hw, unsigned long rate,
>>           b = 0;
>>           c = 1;
>> -        if (rfrac)
>> +        /* Smallest divider in fractional mode must be > 8 (AN619)! */
>> +        if (rfrac && (a >= 8))
>>               rational_best_approximation(rfrac, denom,
>>                   SI5351_MULTISYNTH_B_MAX, SI5351_MULTISYNTH_C_MAX,
>>                   &b, &c);
>> @@ -1039,11 +1040,11 @@ static long si5351_clkout_round_rate(struct 
>> clk_hw *hw, unsigned long rate,
>>           container_of(hw, struct si5351_hw_data, hw);
>>       unsigned char rdiv;
>> -    /* clkout6/7 can only handle output freqencies < 150MHz */
>> +    /* clkout6/7 can only handle output frequencies < 150MHz */
>>       if (hwdata->num >= 6 && rate > SI5351_CLKOUT67_MAX_FREQ)
>>           rate = SI5351_CLKOUT67_MAX_FREQ;
>> -    /* clkout freqency is 8kHz - 160MHz */
>> +    /* clkout frequency is 2.5kHz - 200MHz */
>>       if (rate > SI5351_CLKOUT_MAX_FREQ)
>>           rate = SI5351_CLKOUT_MAX_FREQ;
>>       if (rate < SI5351_CLKOUT_MIN_FREQ)
>> diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h
>> index 73dc8effc519..f799dc6ea8a1 100644
>> --- a/drivers/clk/clk-si5351.h
>> +++ b/drivers/clk/clk-si5351.h
>> @@ -13,11 +13,11 @@
>>   #define SI5351_PLL_VCO_MIN            600000000
>>   #define SI5351_PLL_VCO_MAX            900000000
>> -#define SI5351_MULTISYNTH_MIN_FREQ        1000000
>> +#define SI5351_MULTISYNTH_MIN_FREQ        300000
> 
>  > The lower limit should be 500KHz (AN619: 
> https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/application-notes/AN619.pdf) 

The word *about* in the sentence "The R dividers can be used to generate 
frequencies below about 500 kHz." of AN619 made me believe that 500 kHz 
is just a rough approximation and 300 kHz would be a more accurate 
limit. (It used to be 1 MHz in the beginning and they changed it later.)

I am wondering, though, why a SI5351_MULTISYNTH_MIN_FREQ of 300 kHz 
resulted in a wrong output frequency in your case. Was it a 
calculational problem (i.e. invalid register values) or did you actually 
see a wrong output frequency?


> Changing the lower limit in your patch to 500KHz solved the problem.
> 
>>   #define SI5351_MULTISYNTH_DIVBY4_FREQ        150000000
>> -#define SI5351_MULTISYNTH_MAX_FREQ        160000000
>> +#define SI5351_MULTISYNTH_MAX_FREQ        200000000
>>   #define SI5351_MULTISYNTH67_MAX_FREQ        
>> SI5351_MULTISYNTH_DIVBY4_FREQ
>> -#define SI5351_CLKOUT_MIN_FREQ            8000
>> +#define SI5351_CLKOUT_MIN_FREQ            2500
>>   #define SI5351_CLKOUT_MAX_FREQ            SI5351_MULTISYNTH_MAX_FREQ
>>   #define SI5351_CLKOUT67_MAX_FREQ        SI5351_MULTISYNTH67_MAX_FREQ
>> @@ -26,7 +26,7 @@
>>   #define SI5351_PLL_B_MAX            (SI5351_PLL_C_MAX-1)
>>   #define SI5351_PLL_C_MAX            1048575
>>   #define SI5351_MULTISYNTH_A_MIN            6
>> -#define SI5351_MULTISYNTH_A_MAX            1800
>> +#define SI5351_MULTISYNTH_A_MAX            2048
>>   #define SI5351_MULTISYNTH67_A_MAX        254
>>   #define SI5351_MULTISYNTH_B_MAX            (SI5351_MULTISYNTH_C_MAX-1)
>>   #define SI5351_MULTISYNTH_C_MAX            1048575
diff mbox series

Patch

diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index 57e4597cdf4c..56bc59f91d20 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -556,7 +556,7 @@  static const struct clk_ops si5351_pll_ops = {
  * MS[6,7] are integer (P1) divide only, P1 = divide value,
  * P2 and P3 are not applicable
  *
- * for 150MHz < fOUT <= 160MHz:
+ * for 150MHz < fOUT <= 200MHz:
  *
  * MSx_P1 = 0, MSx_P2 = 0, MSx_P3 = 1, MSx_INT = 1, MSx_DIVBY4 = 11b
  */
@@ -653,7 +653,7 @@  static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
 	if (hwdata->num >= 6 && rate > SI5351_MULTISYNTH67_MAX_FREQ)
 		rate = SI5351_MULTISYNTH67_MAX_FREQ;
 
-	/* multisync frequency is 1MHz .. 160MHz */
+	/* multisync frequency is 300kHz .. 200MHz */
 	if (rate > SI5351_MULTISYNTH_MAX_FREQ)
 		rate = SI5351_MULTISYNTH_MAX_FREQ;
 	if (rate < SI5351_MULTISYNTH_MIN_FREQ)
@@ -681,8 +681,8 @@  static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
 
 		*parent_rate = a * rate;
 	} else if (hwdata->num >= 6) {
-		/* determine the closest integer divider */
-		a = DIV_ROUND_CLOSEST(*parent_rate, rate);
+		/* determine the closest even integer divider */
+		a = DIV_ROUND_CLOSEST(*parent_rate/2, rate) * 2;
 		if (a < SI5351_MULTISYNTH_A_MIN)
 			a = SI5351_MULTISYNTH_A_MIN;
 		if (a > SI5351_MULTISYNTH67_A_MAX)
@@ -715,7 +715,8 @@  static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
 
 		b = 0;
 		c = 1;
-		if (rfrac)
+		/* Smallest divider in fractional mode must be > 8 (AN619)! */
+		if (rfrac && (a >= 8))
 			rational_best_approximation(rfrac, denom,
 			    SI5351_MULTISYNTH_B_MAX, SI5351_MULTISYNTH_C_MAX,
 			    &b, &c);
@@ -1039,11 +1040,11 @@  static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
 		container_of(hw, struct si5351_hw_data, hw);
 	unsigned char rdiv;
 
-	/* clkout6/7 can only handle output freqencies < 150MHz */
+	/* clkout6/7 can only handle output frequencies < 150MHz */
 	if (hwdata->num >= 6 && rate > SI5351_CLKOUT67_MAX_FREQ)
 		rate = SI5351_CLKOUT67_MAX_FREQ;
 
-	/* clkout freqency is 8kHz - 160MHz */
+	/* clkout frequency is 2.5kHz - 200MHz */
 	if (rate > SI5351_CLKOUT_MAX_FREQ)
 		rate = SI5351_CLKOUT_MAX_FREQ;
 	if (rate < SI5351_CLKOUT_MIN_FREQ)
diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h
index 73dc8effc519..f799dc6ea8a1 100644
--- a/drivers/clk/clk-si5351.h
+++ b/drivers/clk/clk-si5351.h
@@ -13,11 +13,11 @@ 
 
 #define SI5351_PLL_VCO_MIN			600000000
 #define SI5351_PLL_VCO_MAX			900000000
-#define SI5351_MULTISYNTH_MIN_FREQ		1000000
+#define SI5351_MULTISYNTH_MIN_FREQ		300000
 #define SI5351_MULTISYNTH_DIVBY4_FREQ		150000000
-#define SI5351_MULTISYNTH_MAX_FREQ		160000000
+#define SI5351_MULTISYNTH_MAX_FREQ		200000000
 #define SI5351_MULTISYNTH67_MAX_FREQ		SI5351_MULTISYNTH_DIVBY4_FREQ
-#define SI5351_CLKOUT_MIN_FREQ			8000
+#define SI5351_CLKOUT_MIN_FREQ			2500
 #define SI5351_CLKOUT_MAX_FREQ			SI5351_MULTISYNTH_MAX_FREQ
 #define SI5351_CLKOUT67_MAX_FREQ		SI5351_MULTISYNTH67_MAX_FREQ
 
@@ -26,7 +26,7 @@ 
 #define SI5351_PLL_B_MAX			(SI5351_PLL_C_MAX-1)
 #define SI5351_PLL_C_MAX			1048575
 #define SI5351_MULTISYNTH_A_MIN			6
-#define SI5351_MULTISYNTH_A_MAX			1800
+#define SI5351_MULTISYNTH_A_MAX			2048
 #define SI5351_MULTISYNTH67_A_MAX		254
 #define SI5351_MULTISYNTH_B_MAX			(SI5351_MULTISYNTH_C_MAX-1)
 #define SI5351_MULTISYNTH_C_MAX			1048575