]> Git Repo - linux.git/commitdiff
i2c: designware: determine HS tHIGH and tLOW based on HW parameters
authorMichael Wu <[email protected]>
Thu, 3 Oct 2024 11:15:24 +0000 (19:15 +0800)
committerWolfram Sang <[email protected]>
Sun, 24 Nov 2024 15:03:51 +0000 (16:03 +0100)
In commit 35eba185fd1a ("i2c: designware: Calculate SCL timing parameter
for High Speed Mode") the SCL high period count and low period count for
high speed mode are calculated based on fixed tHIGH = 160 and tLOW = 120.
However, the set of two fixed values is only applicable to the combination
of hardware parameters IC_CAP_LOADING is 400 and IC_CLK_FREQ_OPTIMIZATION
is true. Outside of this combination, the SCL frequency may not reach
3.4 MHz because the fixed tHIGH and tLOW are not small enough.

If IC_CAP_LOADING is 400, it means the bus capacitance is 400pF;
Otherwise, 100 pF. If IC_CLK_FREQ_OPTIMIZATION is true, it means that the
hardware reduces its internal clock frequency by reducing the internal
latency required to generate the high period and low period of the SCL line.

Section 3.15.4.5 in DesignWare DW_apb_i2b Databook v2.03 says that when
IC_CLK_FREQ_OPTIMIZATION = 0,

    MIN_SCL_HIGHtime = 60 ns for 3.4 Mbps, bus loading = 100pF
     = 120 ns for 3.4 Mbps, bus loading = 400pF
    MIN_SCL_LOWtime = 160 ns for 3.4 Mbps, bus loading = 100pF
    = 320 ns for 3.4 Mbps, bus loading = 400pF

and section 3.15.4.6 says that when IC_CLK_FREQ_OPTIMIZATION = 1,

    MIN_SCL_HIGHtime = 60 ns for 3.4 Mbps, bus loading = 100pF
     = 160 ns for 3.4 Mbps, bus loading = 400pF
    MIN_SCL_LOWtime = 120 ns for 3.4 Mbps, bus loading = 100pF
    = 320 ns for 3.4 Mbps, bus loading = 400pF

In order to calculate more accurate SCL high period count and low period
count for high speed mode, two hardware parameters IC_CAP_LOADING and
IC_CLK_FREQ_OPTIMIZATION must be considered together. Since there're no
registers controlliing these these two hardware parameters, users can
declare them in the device tree so that the driver can obtain them.

Signed-off-by: Michael Wu <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Acked-by: Jarkko Nikula <[email protected]>
Signed-off-by: Andi Shyti <[email protected]>
Signed-off-by: Wolfram Sang <[email protected]>
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-master.c

index 443f946acf36171d26bf578e870bb7d0d4ef56cc..857783d458fbd5bb44f7ede4ca4b6d17ba0e1227 100644 (file)
@@ -382,6 +382,11 @@ int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev)
 
        i2c_parse_fw_timings(device, t, false);
 
+       if (device_property_read_u32(device, "snps,bus-capacitance-pf", &dev->bus_capacitance_pF))
+               dev->bus_capacitance_pF = 100;
+
+       dev->clk_freq_optimized = device_property_read_bool(device, "snps,clk-freq-optimized");
+
        i2c_dw_adjust_bus_speed(dev);
 
        if (is_of_node(fwnode))
index 520f9699e3bd2016e8a9e5adba8abe030e08cb1f..347843b4f5dd7abc614fe5aa9116af8dff4cc5b5 100644 (file)
@@ -242,6 +242,10 @@ struct reset_control;
  * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing
  * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
  * @rinfo: I²C GPIO recovery information
+ * @bus_capacitance_pF: bus capacitance in picofarads
+ * @clk_freq_optimized: if this value is true, it means the hardware reduces
+ *     its internal clock frequency by reducing the internal latency required
+ *     to generate the high period and low period of SCL line.
  *
  * HCNT and LCNT parameters can be used if the platform knows more accurate
  * values than the one computed based only on the input clock frequency.
@@ -299,6 +303,8 @@ struct dw_i2c_dev {
        int                     (*set_sda_hold_time)(struct dw_i2c_dev *dev);
        int                     mode;
        struct i2c_bus_recovery_info rinfo;
+       u32                     bus_capacitance_pF;
+       bool                    clk_freq_optimized;
 };
 
 #define ACCESS_INTR_MASK                       BIT(0)
index 528b969253a7fe24c1d65c560cc4c77ba998c655..eca8998d640fb0dfcb52c23b172701c486ed97e5 100644 (file)
@@ -151,19 +151,38 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
                        dev->hs_hcnt = 0;
                        dev->hs_lcnt = 0;
                } else if (!dev->hs_hcnt || !dev->hs_lcnt) {
+                       u32 t_high, t_low;
+
+                       /*
+                        * The legal values stated in the databook for bus
+                        * capacitance are only 100pF and 400pF.
+                        * If dev->bus_capacitance_pF is greater than or equals
+                        * to 400, t_high and t_low are assumed to be
+                        * appropriate values for 400pF, otherwise 100pF.
+                        */
+                       if (dev->bus_capacitance_pF >= 400) {
+                               /* assume bus capacitance is 400pF */
+                               t_high = dev->clk_freq_optimized ? 160 : 120;
+                               t_low = 320;
+                       } else {
+                               /* assume bus capacitance is 100pF */
+                               t_high = 60;
+                               t_low = dev->clk_freq_optimized ? 120 : 160;
+                       }
+
                        ic_clk = i2c_dw_clk_rate(dev);
                        dev->hs_hcnt =
                                i2c_dw_scl_hcnt(dev,
                                                DW_IC_HS_SCL_HCNT,
                                                ic_clk,
-                                               160,    /* tHIGH = 160 ns */
+                                               t_high,
                                                sda_falling_time,
                                                0);     /* No offset */
                        dev->hs_lcnt =
                                i2c_dw_scl_lcnt(dev,
                                                DW_IC_HS_SCL_LCNT,
                                                ic_clk,
-                                               320,    /* tLOW = 320 ns */
+                                               t_low,
                                                scl_falling_time,
                                                0);     /* No offset */
                }
This page took 0.063707 seconds and 4 git commands to generate.