diff mbox series

[v2,3/4] clk: rs9: Support device specific dif bit calculation

Message ID 20230110100003.370917-3-alexander.stein@ew.tq-group.com (mailing list archive)
State Superseded, archived
Headers show
Series [v2,1/4] clk: rs9: Check for vendor/device ID | expand

Commit Message

Alexander Stein Jan. 10, 2023, 10 a.m. UTC
The calculation DIFx is BIT(n) +1 is only true for 9FGV0241. With
additional devices this is getting more complicated.
Support a base bit for the DIF calculation, currently only devices
with consecutive bits are supported, e.g. the 6-channel device needs
additional logic.

Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
---
Changes in v2:
* Use a common function instead of callback for calculating the DIF bit

 drivers/clk/clk-renesas-pcie.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

Comments

Marek Vasut Jan. 10, 2023, 10:31 a.m. UTC | #1
On 1/10/23 11:00, Alexander Stein wrote:

[...]

>   static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
>   {
>   	struct i2c_client *client = rs9->client;
> +	u8 dif = rs9_calc_dif(rs9, idx);
>   	unsigned char name[5] = "DIF0";
>   	struct device_node *np;
>   	int ret;
>   	u32 sr;
>   
>   	/* Set defaults */
> -	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);

Are you sure this line ^ should be dropped ?
Shouldn't the bitfield be cleared first and modified second?

> -	rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
> +	rs9->clk_dif_sr |= dif;
>   
>   	snprintf(name, 5, "DIF%d", idx);
>   	np = of_get_child_by_name(client->dev.of_node, name);

[...]
Alexander Stein Jan. 10, 2023, 1:22 p.m. UTC | #2
Hi Marek,

thanks for your feedback.

Am Dienstag, 10. Januar 2023, 11:31:49 CET schrieb Marek Vasut:
> On 1/10/23 11:00, Alexander Stein wrote:
> 
> [...]
> 
> >   static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
> >   {
> >   
> >   	struct i2c_client *client = rs9->client;
> > 
> > +	u8 dif = rs9_calc_dif(rs9, idx);
> > 
> >   	unsigned char name[5] = "DIF0";
> >   	struct device_node *np;
> >   	int ret;
> >   	u32 sr;
> >   	
> >   	/* Set defaults */
> > 
> > -	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
> 
> Are you sure this line ^ should be dropped ?
> Shouldn't the bitfield be cleared first and modified second?

Well, I had in my mind that this function is called upon probe with clk_dif_sr 
being cleared anyway, so this does essentially nothing. And the DIF bit is set 
unconditionally, so what is the point of masking it before?

Best regards,
Alexander

> > -	rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
> > +	rs9->clk_dif_sr |= dif;
> > 
> >   	snprintf(name, 5, "DIF%d", idx);
> >   	np = of_get_child_by_name(client->dev.of_node, name);
> 
> [...]
Marek Vasut Jan. 10, 2023, 1:37 p.m. UTC | #3
On 1/10/23 14:22, Alexander Stein wrote:
> Hi Marek,

Hi,

> thanks for your feedback.
> 
> Am Dienstag, 10. Januar 2023, 11:31:49 CET schrieb Marek Vasut:
>> On 1/10/23 11:00, Alexander Stein wrote:
>>
>> [...]
>>
>>>    static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
>>>    {
>>>    
>>>    	struct i2c_client *client = rs9->client;
>>>
>>> +	u8 dif = rs9_calc_dif(rs9, idx);
>>>
>>>    	unsigned char name[5] = "DIF0";
>>>    	struct device_node *np;
>>>    	int ret;
>>>    	u32 sr;
>>>    	
>>>    	/* Set defaults */
>>>
>>> -	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
>>
>> Are you sure this line ^ should be dropped ?
>> Shouldn't the bitfield be cleared first and modified second?
> 
> Well, I had in my mind that this function is called upon probe with clk_dif_sr
> being cleared anyway, so this does essentially nothing. And the DIF bit is set
> unconditionally, so what is the point of masking it before?

Good point, but then, what's the point of ORRing either ? Just do a 
plain assignment.
Alexander Stein Jan. 10, 2023, 1:47 p.m. UTC | #4
Hello Marek,

Am Dienstag, 10. Januar 2023, 14:37:19 CET schrieb Marek Vasut:
> On 1/10/23 14:22, Alexander Stein wrote:
> > Hi Marek,
> 
> Hi,
> 
> > thanks for your feedback.
> > 
> > Am Dienstag, 10. Januar 2023, 11:31:49 CET schrieb Marek Vasut:
> >> On 1/10/23 11:00, Alexander Stein wrote:
> >> 
> >> [...]
> >> 
> >>>    static int rs9_get_output_config(struct rs9_driver_data *rs9, int
> >>>    idx)
> >>>    {
> >>>    
> >>>    	struct i2c_client *client = rs9->client;
> >>> 
> >>> +	u8 dif = rs9_calc_dif(rs9, idx);
> >>> 
> >>>    	unsigned char name[5] = "DIF0";
> >>>    	struct device_node *np;
> >>>    	int ret;
> >>>    	u32 sr;
> >>>    	
> >>>    	/* Set defaults */
> >>> 
> >>> -	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
> >> 
> >> Are you sure this line ^ should be dropped ?
> >> Shouldn't the bitfield be cleared first and modified second?
> > 
> > Well, I had in my mind that this function is called upon probe with
> > clk_dif_sr being cleared anyway, so this does essentially nothing. And
> > the DIF bit is set unconditionally, so what is the point of masking it
> > before?
> 
> Good point, but then, what's the point of ORRing either ? Just do a
> plain assignment.

OR-ring is necessary as this function is called for each DIF output (see idx 
parameter), so plain assignment will clear the previously set bits.

Best regards,
Alexander
Marek Vasut Jan. 10, 2023, 1:51 p.m. UTC | #5
On 1/10/23 14:47, Alexander Stein wrote:
> Hello Marek,
> 
> Am Dienstag, 10. Januar 2023, 14:37:19 CET schrieb Marek Vasut:
>> On 1/10/23 14:22, Alexander Stein wrote:
>>> Hi Marek,
>>
>> Hi,
>>
>>> thanks for your feedback.
>>>
>>> Am Dienstag, 10. Januar 2023, 11:31:49 CET schrieb Marek Vasut:
>>>> On 1/10/23 11:00, Alexander Stein wrote:
>>>>
>>>> [...]
>>>>
>>>>>     static int rs9_get_output_config(struct rs9_driver_data *rs9, int
>>>>>     idx)
>>>>>     {
>>>>>     
>>>>>     	struct i2c_client *client = rs9->client;
>>>>>
>>>>> +	u8 dif = rs9_calc_dif(rs9, idx);
>>>>>
>>>>>     	unsigned char name[5] = "DIF0";
>>>>>     	struct device_node *np;
>>>>>     	int ret;
>>>>>     	u32 sr;
>>>>>     	
>>>>>     	/* Set defaults */
>>>>>
>>>>> -	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
>>>>
>>>> Are you sure this line ^ should be dropped ?
>>>> Shouldn't the bitfield be cleared first and modified second?
>>>
>>> Well, I had in my mind that this function is called upon probe with
>>> clk_dif_sr being cleared anyway, so this does essentially nothing. And
>>> the DIF bit is set unconditionally, so what is the point of masking it
>>> before?
>>
>> Good point, but then, what's the point of ORRing either ? Just do a
>> plain assignment.
> 
> OR-ring is necessary as this function is called for each DIF output (see idx
> parameter), so plain assignment will clear the previously set bits.

Ah, got it.

Reviewed-by: Marek Vasut <marex@denx.de>

Thanks !
diff mbox series

Patch

diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c
index bba09a88c2ccc..6b19186228238 100644
--- a/drivers/clk/clk-renesas-pcie.c
+++ b/drivers/clk/clk-renesas-pcie.c
@@ -18,7 +18,6 @@ 
 #include <linux/regmap.h>
 
 #define RS9_REG_OE				0x0
-#define RS9_REG_OE_DIF_OE(n)			BIT((n) + 1)
 #define RS9_REG_SS				0x1
 #define RS9_REG_SS_AMP_0V6			0x0
 #define RS9_REG_SS_AMP_0V7			0x1
@@ -31,9 +30,6 @@ 
 #define RS9_REG_SS_SSC_MASK			(3 << 3)
 #define RS9_REG_SS_SSC_LOCK			BIT(5)
 #define RS9_REG_SR				0x2
-#define RS9_REG_SR_2V0_DIF(n)			0
-#define RS9_REG_SR_3V0_DIF(n)			BIT((n) + 1)
-#define RS9_REG_SR_DIF_MASK(n)		BIT((n) + 1)
 #define RS9_REG_REF				0x3
 #define RS9_REG_REF_OE				BIT(4)
 #define RS9_REG_REF_OD				BIT(5)
@@ -160,17 +156,27 @@  static const struct regmap_config rs9_regmap_config = {
 	.reg_read = rs9_regmap_i2c_read,
 };
 
+static u8 rs9_calc_dif(const struct rs9_driver_data *rs9, int idx)
+{
+	enum rs9_model model = rs9->chip_info->model;
+
+	if (model == RENESAS_9FGV0241)
+		return BIT(idx) + 1;
+
+	return 0;
+}
+
 static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
 {
 	struct i2c_client *client = rs9->client;
+	u8 dif = rs9_calc_dif(rs9, idx);
 	unsigned char name[5] = "DIF0";
 	struct device_node *np;
 	int ret;
 	u32 sr;
 
 	/* Set defaults */
-	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
-	rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
+	rs9->clk_dif_sr |= dif;
 
 	snprintf(name, 5, "DIF%d", idx);
 	np = of_get_child_by_name(client->dev.of_node, name);
@@ -182,11 +188,9 @@  static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
 	of_node_put(np);
 	if (!ret) {
 		if (sr == 2000000) {		/* 2V/ns */
-			rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
-			rs9->clk_dif_sr |= RS9_REG_SR_2V0_DIF(idx);
+			rs9->clk_dif_sr &= ~dif;
 		} else if (sr == 3000000) {	/* 3V/ns (default) */
-			rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
-			rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
+			rs9->clk_dif_sr |= dif;
 		} else
 			ret = dev_err_probe(&client->dev, -EINVAL,
 					    "Invalid renesas,slew-rate value\n");
@@ -257,11 +261,13 @@  static void rs9_update_config(struct rs9_driver_data *rs9)
 	}
 
 	for (i = 0; i < rs9->chip_info->num_clks; i++) {
-		if (rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i))
+		u8 dif = rs9_calc_dif(rs9, i);
+
+		if (rs9->clk_dif_sr & dif)
 			continue;
 
-		regmap_update_bits(rs9->regmap, RS9_REG_SR, RS9_REG_SR_3V0_DIF(i),
-				   rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i));
+		regmap_update_bits(rs9->regmap, RS9_REG_SR, dif,
+				   rs9->clk_dif_sr & dif);
 	}
 }