linux-i3c.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] i3c: dw: Use configured rate and bus mode for clock configuration
@ 2023-02-16  6:20 Jeremy Kerr
  2023-02-23 22:29 ` Vitor Soares
  0 siblings, 1 reply; 4+ messages in thread
From: Jeremy Kerr @ 2023-02-16  6:20 UTC (permalink / raw)
  To: linux-i3c; +Cc: linux-aspeed, Vitor Soares, Alexandre Belloni

We may have a non-typical i3c rate configured; use this (instead of
the fixed I3C_BUS_TYP_I3C_SCL_RATE) when calculating timing
characteristics. We can also expand the SCL high time based on the
presence/absence of i2c devices.

Also, since we now have bus->mode, use it to determine whether we se up
the BUS_FREE_TIMING register; rather than re-reading
DEV_CTRL_I2C_SLAVE_PRESENT from hardware.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
 drivers/i3c/master/dw-i3c-master.c | 44 ++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 14 deletions(-)

diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 51a8608203de..d73d57362b3b 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -515,7 +515,8 @@ static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr)
 	dw_i3c_master_start_xfer_locked(master);
 }
 
-static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
+static int dw_i3c_clk_cfg(struct dw_i3c_master *master, unsigned long i3c_rate,
+			  bool pure)
 {
 	unsigned long core_rate, core_period;
 	u32 scl_timing;
@@ -527,31 +528,45 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
 
 	core_period = DIV_ROUND_UP(1000000000, core_rate);
 
-	hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period) - 1;
-	if (hcnt < SCL_I3C_TIMING_CNT_MIN)
-		hcnt = SCL_I3C_TIMING_CNT_MIN;
+	/* 50% duty cycle */
+	hcnt = DIV_ROUND_UP(core_rate, i3c_rate * 2);
 
-	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_TYP_I3C_SCL_RATE) - hcnt;
-	if (lcnt < SCL_I3C_TIMING_CNT_MIN)
-		lcnt = SCL_I3C_TIMING_CNT_MIN;
+	/* In shared mode, we limit t_high, so that i3c SCL signalling is
+	 * rejected by the i2c devices' spike filter */
+	if (!pure)
+		hcnt = min_t(u8, hcnt,
+			     DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period)) - 1;
+
+	hcnt = max_t(u8, hcnt, SCL_I3C_TIMING_CNT_MIN);
+
+	lcnt = DIV_ROUND_UP(core_rate, i3c_rate) - hcnt;
+	lcnt = max_t(u8, lcnt, SCL_I3C_TIMING_CNT_MIN);
 
 	scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
 	writel(scl_timing, master->regs + SCL_I3C_PP_TIMING);
 
-	if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT))
+	if (pure)
 		writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
 
-	lcnt = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period);
+	/* open drain mode requires a minimum of OD_MIN_NS */
+	lcnt = max_t(u8, lcnt, DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period));
 	scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
 	writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
 
-	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt;
+	/* Timings for lower SDRx rates where specified by device MXDS values;
+	 * we limit these to the global max rate provided, which also prevents
+	 * weird duty cycles */
+	lcnt = max_t(u8, lcnt,
+		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt);
 	scl_timing = SCL_EXT_LCNT_1(lcnt);
-	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt;
+	lcnt = max_t(u8, lcnt,
+		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt);
 	scl_timing |= SCL_EXT_LCNT_2(lcnt);
-	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt;
+	lcnt = max_t(u8, lcnt,
+		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt);
 	scl_timing |= SCL_EXT_LCNT_3(lcnt);
-	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt;
+	lcnt = max_t(u8, lcnt,
+		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt);
 	scl_timing |= SCL_EXT_LCNT_4(lcnt);
 	writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING);
 
@@ -605,7 +620,8 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 			return ret;
 		fallthrough;
 	case I3C_BUS_MODE_PURE:
-		ret = dw_i3c_clk_cfg(master);
+		ret = dw_i3c_clk_cfg(master, bus->scl_rate.i3c,
+				     bus->mode == I3C_BUS_MODE_PURE);
 		if (ret)
 			return ret;
 		break;
-- 
2.39.1


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] i3c: dw: Use configured rate and bus mode for clock configuration
  2023-02-16  6:20 [PATCH] i3c: dw: Use configured rate and bus mode for clock configuration Jeremy Kerr
@ 2023-02-23 22:29 ` Vitor Soares
  2023-02-24  2:32   ` Jeremy Kerr
  0 siblings, 1 reply; 4+ messages in thread
From: Vitor Soares @ 2023-02-23 22:29 UTC (permalink / raw)
  To: Jeremy Kerr, linux-i3c; +Cc: linux-aspeed, Alexandre Belloni

Hi Jeremy,

Please find my comments bellow.


On 2/16/23 06:20, Jeremy Kerr wrote:
> We may have a non-typical i3c rate configured; use this (instead of
> the fixed I3C_BUS_TYP_I3C_SCL_RATE) when calculating timing
> characteristics. We can also expand the SCL high time based on the
> presence/absence of i2c devices.
>
> Also, since we now have bus->mode, use it to determine whether we se up
> the BUS_FREE_TIMING register; rather than re-reading
> DEV_CTRL_I2C_SLAVE_PRESENT from hardware.
>
> Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
> ---
>  drivers/i3c/master/dw-i3c-master.c | 44 ++++++++++++++++++++----------
>  1 file changed, 30 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
> index 51a8608203de..d73d57362b3b 100644
> --- a/drivers/i3c/master/dw-i3c-master.c
> +++ b/drivers/i3c/master/dw-i3c-master.c
> @@ -515,7 +515,8 @@ static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr)
>  	dw_i3c_master_start_xfer_locked(master);
>  }
>  
> -static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
> +static int dw_i3c_clk_cfg(struct dw_i3c_master *master, unsigned long i3c_rate,
> +			  bool pure)
>  {
>  	unsigned long core_rate, core_period;
>  	u32 scl_timing;
> @@ -527,31 +528,45 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
>  
>  	core_period = DIV_ROUND_UP(1000000000, core_rate);
>  
> -	hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period) - 1;
> -	if (hcnt < SCL_I3C_TIMING_CNT_MIN)
> -		hcnt = SCL_I3C_TIMING_CNT_MIN;
> +	/* 50% duty cycle */
> +	hcnt = DIV_ROUND_UP(core_rate, i3c_rate * 2);
>  
> -	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_TYP_I3C_SCL_RATE) - hcnt;
> -	if (lcnt < SCL_I3C_TIMING_CNT_MIN)
> -		lcnt = SCL_I3C_TIMING_CNT_MIN;
> +	/* In shared mode, we limit t_high, so that i3c SCL signalling is
> +	 * rejected by the i2c devices' spike filter */
> +	if (!pure)
> +		hcnt = min_t(u8, hcnt,
> +			     DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period)) - 1;

You are assuming that t_high may be lower than 40ns, right?
by the spec the max speed is 12.9MHz, don't think you need this min_t() here.

> +
> +	hcnt = max_t(u8, hcnt, SCL_I3C_TIMING_CNT_MIN);

I would branch this part into:

if(pure)

    hcnt= ;

else

    hcnt= ;

think this way is more readable.

> +
> +	lcnt = DIV_ROUND_UP(core_rate, i3c_rate) - hcnt;
> +	lcnt = max_t(u8, lcnt, SCL_I3C_TIMING_CNT_MIN);
>  
>  	scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
>  	writel(scl_timing, master->regs + SCL_I3C_PP_TIMING);
>  
> -	if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT))
> +	if (pure)
>  		writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
>  
> -	lcnt = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period);
> +	/* open drain mode requires a minimum of OD_MIN_NS */

My comment here would say why we need a higher OD time rather the minimum.


> +	lcnt = max_t(u8, lcnt, DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period));
>  	scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
>  	writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
>  
> -	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt;
> +	/* Timings for lower SDRx rates where specified by device MXDS values;
> +	 * we limit these to the global max rate provided, which also prevents
> +	 * weird duty cycles */

I think checkpatch complains with this comment format. I would suggest to use like in the rest of kernel.

Unfortunately, we need to address the cases in which SDRx frequency is higher than bus->scl_rate.i3c.


> +	lcnt = max_t(u8, lcnt,
> +		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt);

The lcnt within max_t() function comes from SCL_I3C_OD_TIMING, correct? Have you checked this value for
bus->scl_rate.i3c = 12.5MHz?


>  	scl_timing = SCL_EXT_LCNT_1(lcnt);
> -	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt;
> +	lcnt = max_t(u8, lcnt,
> +		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt);
>  	scl_timing |= SCL_EXT_LCNT_2(lcnt);
> -	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt;
> +	lcnt = max_t(u8, lcnt,
> +		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt);
>  	scl_timing |= SCL_EXT_LCNT_3(lcnt);
> -	lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt;
> +	lcnt = max_t(u8, lcnt,
> +		     DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt);

what about to use a for loop and only do lcnt calculation if

bus->scl_rate.i3c > I3C_BUS_SDRx_SCL_RATE ?


>  	scl_timing |= SCL_EXT_LCNT_4(lcnt);
>  	writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING);
>  
> @@ -605,7 +620,8 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
>  			return ret;
>  		fallthrough;
>  	case I3C_BUS_MODE_PURE:
> -		ret = dw_i3c_clk_cfg(master);
> +		ret = dw_i3c_clk_cfg(master, bus->scl_rate.i3c,
> +				     bus->mode == I3C_BUS_MODE_PURE);
>  		if (ret)
>  			return ret;
>  		break;


Best regards,

Vitor Soares


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] i3c: dw: Use configured rate and bus mode for clock configuration
  2023-02-23 22:29 ` Vitor Soares
@ 2023-02-24  2:32   ` Jeremy Kerr
  2023-02-24  8:22     ` Jeremy Kerr
  0 siblings, 1 reply; 4+ messages in thread
From: Jeremy Kerr @ 2023-02-24  2:32 UTC (permalink / raw)
  To: Vitor Soares, linux-i3c; +Cc: linux-aspeed, Alexandre Belloni

Hi Vitor,

> Please find my comments bellow.

Thanks for taking a look, and for the review. Some replies inline:

> > +       /* 50% duty cycle */
> > +       hcnt = DIV_ROUND_UP(core_rate, i3c_rate * 2);
> >  
> > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_TYP_I3C_SCL_RATE) - hcnt;
> > -       if (lcnt < SCL_I3C_TIMING_CNT_MIN)
> > -               lcnt = SCL_I3C_TIMING_CNT_MIN;
> > +       /* In shared mode, we limit t_high, so that i3c SCL signalling is
> > +        * rejected by the i2c devices' spike filter */
> > +       if (!pure)
> > +               hcnt = min_t(u8, hcnt,
> > +                            DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period)) - 1;
> 
> You are assuming that t_high may be lower than 40ns, right?
> by the spec the max speed is 12.9MHz, don't think you need this min_t() here.

This is to handle the case where t_high is *longer* than 41ns - from the
50% duty cycle calculation above, when using a lower bus frequency
(lower than about 12.2MHz).

Then, for mixed-mode (where we need to be compatible with i2c devices
on the bus), we reduce this to the 41ns max (and then hcnt gets
increased to fit the intended frequency).

This is to match the definitions in Table 86 of the I3C spec: the 41ns
maximum is only specified for the mixed bus case.

> > +
> > +       hcnt = max_t(u8, hcnt, SCL_I3C_TIMING_CNT_MIN);
> 
> I would branch this part into:
> 
> if(pure)
> 
>     hcnt= ;
> 
> else
> 
>     hcnt= ;
> 
> think this way is more readable.

Yeah, I've been debating min_t()/max_t() vs. conditionals; the
conditionals are more verbose, but likely easier to interpret. I'll
re-do all of these limits as conditionals.

> > +
> > +       lcnt = DIV_ROUND_UP(core_rate, i3c_rate) - hcnt;
> > +       lcnt = max_t(u8, lcnt, SCL_I3C_TIMING_CNT_MIN);
> >  
> >         scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
> >         writel(scl_timing, master->regs + SCL_I3C_PP_TIMING);
> >  
> > -       if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT))
> > +       if (pure)
> >                 writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
> >  
> > -       lcnt = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period);
> > +       /* open drain mode requires a minimum of OD_MIN_NS */
> 
> My comment here would say why we need a higher OD time rather the minimum.

OK, sounds good.

> > +       lcnt = max_t(u8, lcnt, DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period));
> >         scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
> >         writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
> >  
> > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt;
> > +       /* Timings for lower SDRx rates where specified by device MXDS values;
> > +        * we limit these to the global max rate provided, which also prevents
> > +        * weird duty cycles */
> 
> I think checkpatch complains with this comment format. I would suggest
> to use like in the rest of kernel.

Yep, will change.

> Unfortunately, we need to address the cases in which SDRx frequency is
> higher than bus->scl_rate.i3c.

I'm not sure if I'm interpreting your comment correctly, but that's
essentially what this is doing: limiting the SDRx frequencies, so that
none is higher than bus->scl_rate.i3c.

For example, if scl_rate is set at 5MHz, we should end up with:

  * default: 5MHz
  * SDR1: 5MHz
  * SDR2: 5MHz
  * SDR3: 4MHz
  * SDR4: 2MHz

Or do you mean that we should be generating timing configurations that
allow SDRx to be greater than the specified scl_rate.i3c? That would
seem to defeat the purpose of the scl_rate override - a device trying to
limit the rate through GETMXDS would result in the rate
*increasing* from the default.

Or something else?

> > +       lcnt = max_t(u8, lcnt,
> > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt);
> 
> The lcnt within max_t() function comes from SCL_I3C_OD_TIMING,
> correct? Have you checked this value for bus->scl_rate.i3c = 12.5MHz?

Good catch, I assume that this should be based on the PP value, will
update.

> >         scl_timing = SCL_EXT_LCNT_1(lcnt);
> > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt;
> > +       lcnt = max_t(u8, lcnt,
> > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt);
> >         scl_timing |= SCL_EXT_LCNT_2(lcnt);
> > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt;
> > +       lcnt = max_t(u8, lcnt,
> > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt);
> >         scl_timing |= SCL_EXT_LCNT_3(lcnt);
> > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt;
> > +       lcnt = max_t(u8, lcnt,
> > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt);
> 
> what about to use a for loop and only do lcnt calculation if
> 
> bus->scl_rate.i3c > I3C_BUS_SDRx_SCL_RATE ?

I have intended for this to be the same as the existing calculations,
just applying the limit of the global scl_rate.

We could restructure as a for-loop (which I'd suggest splitting as a
separate change, so that the calculation changes are more obvious), but
it's going to get a bit weird with the macro usage there.

Cheers,


Jeremy

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] i3c: dw: Use configured rate and bus mode for clock configuration
  2023-02-24  2:32   ` Jeremy Kerr
@ 2023-02-24  8:22     ` Jeremy Kerr
  0 siblings, 0 replies; 4+ messages in thread
From: Jeremy Kerr @ 2023-02-24  8:22 UTC (permalink / raw)
  To: Vitor Soares, linux-i3c; +Cc: linux-aspeed, Alexandre Belloni

Hi Vitor,

> > >         scl_timing = SCL_EXT_LCNT_1(lcnt);
> > > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt;
> > > +       lcnt = max_t(u8, lcnt,
> > > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt);
> > >         scl_timing |= SCL_EXT_LCNT_2(lcnt);
> > > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt;
> > > +       lcnt = max_t(u8, lcnt,
> > > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt);
> > >         scl_timing |= SCL_EXT_LCNT_3(lcnt);
> > > -       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt;
> > > +       lcnt = max_t(u8, lcnt,
> > > +                    DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt);
> > 
> > what about to use a for loop and only do lcnt calculation if
> > 
> > bus->scl_rate.i3c > I3C_BUS_SDRx_SCL_RATE ?
> 
> I have intended for this to be the same as the existing calculations,
> just applying the limit of the global scl_rate.
> 
> We could restructure as a for-loop (which I'd suggest splitting as a
> separate change, so that the calculation changes are more obvious),
> but it's going to get a bit weird with the macro usage there.

Actually, a for-loop isn't too bad:

  static const struct {
  	unsigned int freq;
  	unsigned int shift;
  } sdrs[] = {
  	{ I3C_BUS_SDR1_SCL_RATE, 0 },
  	{ I3C_BUS_SDR2_SCL_RATE, 8 },
  	{ I3C_BUS_SDR3_SCL_RATE, 16 },
  	{ I3C_BUS_SDR4_SCL_RATE, 24 },
  };
  
  static int dw_i3c_clk_cfg(struct dw_i3c_master *master, unsigned long i3c_rate,
  			  bool pure)
  {
  	/* ... */
  
  	/*
  	 * Timings for lower SDRx rates where specified by device MXDS values;
  	 * we limit these to the global max rate provided, which also prevents
  	 * weird duty cycles
  	 */
  	scl_timing = 0;
  	for (i = 0; i < ARRAY_SIZE(sdrs); i++) {
  		tmp = DIV_ROUND_UP(core_rate, sdrs[i].freq) & 0xff;
  		if (tmp < lcnt)
  			tmp = lcnt;
  		scl_timing |= tmp << sdrs[i].shift;
  	}
  	writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING);
  
  }

Is this what you were intending?

Cheers,


Jeremy


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-02-25 21:34 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-16  6:20 [PATCH] i3c: dw: Use configured rate and bus mode for clock configuration Jeremy Kerr
2023-02-23 22:29 ` Vitor Soares
2023-02-24  2:32   ` Jeremy Kerr
2023-02-24  8:22     ` Jeremy Kerr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).