The patches were generated from the RPi repo with the following command: git format-patch v6.6.34..rpi-6.1.y Some patches needed rebasing and, as usual, the applied and reverted, wireless drivers, Github workflows, READMEs and defconfigs patches were removed. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
		
			
				
	
	
		
			78 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 6a38c69c75a94c7e9e6f434d12b5975804e93c4c Mon Sep 17 00:00:00 2001
 | 
						|
From: Phil Elwell <phil@raspberrypi.com>
 | 
						|
Date: Mon, 18 Mar 2024 12:11:07 +0000
 | 
						|
Subject: [PATCH 0971/1085] fixup! i2c: designware: Support non-standard bus
 | 
						|
 speeds
 | 
						|
 | 
						|
[1] calculates timings for arbitrary clock speeds, but it does so aiming
 | 
						|
for a 50% SCL duty cycle. This is the wrong goal, particularly for high
 | 
						|
clock speeds, because it doesn't allow the device sufficient time to
 | 
						|
pull the bus low to issue an ACK.
 | 
						|
 | 
						|
Change the algorithm to aim for the minimum SCL high time (tHIGH) for
 | 
						|
the requested speed according to the I2C Specification, using linear
 | 
						|
interpolation between the values for the standard speeds.
 | 
						|
 | 
						|
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
 | 
						|
 | 
						|
[1] commit cea76e589d79 ("i2c: designware: Support non-standard bus speeds")
 | 
						|
---
 | 
						|
 drivers/i2c/busses/i2c-designware-master.c | 37 ++++++++++++++--------
 | 
						|
 1 file changed, 24 insertions(+), 13 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/i2c/busses/i2c-designware-master.c
 | 
						|
+++ b/drivers/i2c/busses/i2c-designware-master.c
 | 
						|
@@ -38,20 +38,32 @@ static void i2c_dw_configure_fifo_master
 | 
						|
 	regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
 | 
						|
 }
 | 
						|
 
 | 
						|
-static u16 clock_calc(struct dw_i2c_dev *dev, bool want_high)
 | 
						|
+static u32 linear_interpolate(u32 x, u32 x1, u32 x2, u32 y1, u32 y2)
 | 
						|
+{
 | 
						|
+	return ((x - x1) * y2 + (x2 - x) * y1) / (x2 - x1);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static u16 u16_clamp(u32 v)
 | 
						|
+{
 | 
						|
+	return (u16)min(v, 0xffff);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void clock_calc(struct dw_i2c_dev *dev, u32 *hcnt, u32 *lcnt)
 | 
						|
 {
 | 
						|
 	struct i2c_timings *t = &dev->timings;
 | 
						|
-	u32 wanted_speed = dev->wanted_bus_speed ?: t->bus_freq_hz;
 | 
						|
+	u32 wanted_khz = (dev->wanted_bus_speed ?: t->bus_freq_hz)/1000;
 | 
						|
 	u32 clk_khz = i2c_dw_clk_rate(dev);
 | 
						|
-	u32 extra_ns = want_high ? t->scl_fall_ns : t->scl_rise_ns;
 | 
						|
-	u32 extra_cycles = (u32)div_u64((u64)clk_khz * extra_ns, 1000000);
 | 
						|
-	u32 period = div_u64((u64)clk_khz * 1000 + wanted_speed - 1, wanted_speed);
 | 
						|
-	u32 cycles = (period + want_high)/2 - extra_cycles;
 | 
						|
-
 | 
						|
-	if (cycles > 0xffff)
 | 
						|
-		cycles = 0xffff;
 | 
						|
+	u32 min_high_ns = (wanted_khz <= 100) ? 4000 :
 | 
						|
+			  (wanted_khz <= 400) ?
 | 
						|
+				linear_interpolate(wanted_khz, 100, 400, 4000, 600) :
 | 
						|
+				linear_interpolate(wanted_khz, 400, 1000, 600, 260);
 | 
						|
+	u32 high_cycles = (u32)div_u64(((u64)clk_khz * min_high_ns + 999999), 1000000) + 1;
 | 
						|
+	u32 extra_high_cycles = (u32)div_u64((u64)clk_khz * t->scl_fall_ns, 1000000);
 | 
						|
+	u32 extra_low_cycles = (u32)div_u64((u64)clk_khz * t->scl_rise_ns, 1000000);
 | 
						|
+	u32 period = div_u64((u64)clk_khz + wanted_khz - 1, wanted_khz);
 | 
						|
 
 | 
						|
-	return (u16)cycles;
 | 
						|
+	*hcnt = u16_clamp(high_cycles - extra_high_cycles);
 | 
						|
+	*lcnt = u16_clamp(period - high_cycles - extra_low_cycles);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
 | 
						|
@@ -77,8 +89,7 @@ static int i2c_dw_set_timings_master(str
 | 
						|
 	sda_falling_time = t->sda_fall_ns ?: 300; /* ns */
 | 
						|
 	scl_falling_time = t->scl_fall_ns ?: 300; /* ns */
 | 
						|
 
 | 
						|
-	hcnt = clock_calc(dev, true);
 | 
						|
-	lcnt = clock_calc(dev, false);
 | 
						|
+	clock_calc(dev, &hcnt, &lcnt);
 | 
						|
 
 | 
						|
 	/* Calculate SCL timing parameters for standard mode if not set */
 | 
						|
 	if (!dev->ss_hcnt || !dev->ss_lcnt) {
 |