i2c: designware: make SCL and SDA falling time configurable
authorRomain Baeriswyl <Romain.Baeriswyl@abilis.com>
Mon, 20 Jan 2014 16:43:43 +0000 (17:43 +0100)
committerWolfram Sang <wsa@the-dreams.de>
Sun, 9 Mar 2014 08:29:08 +0000 (09:29 +0100)
This patch allows to set independantly SCL and SDA falling times.
The tLOW period is computed by taking into account the SCL falling time.
The tHIGH period is computed by taking into account the SDA falling time.

For instance in case the margin on tLOW is considered too small, it can
be increased by increasing the SCL falling time which is by default set
at 300ns.

The same applies for tHIGH period with the help of SDA falling time.

Signed-off-by: Romain Baeriswyl <romainba@abilis.com>
Reviewed-by: Christian Ruppert <christian.ruppert@abilis.com>
Acked-by: Shinya Kuribayashi <skuribay@pobox.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Documentation/devicetree/bindings/i2c/i2c-designware.txt
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-platdrv.c

index 7fd7fa25e9b0f084cec79cd6a5a4c24e1a75fa77..5199b0c8cf7a46b79f722a691bf5e531b27a28a5 100644 (file)
@@ -14,6 +14,12 @@ Optional properties :
  - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
    This option is only supported in hardware blocks version 1.11a or newer.
 
+ - i2c-scl-falling-time : should contain the SCL falling time in nanoseconds.
+   This value which is by default 300ns is used to compute the tLOW period.
+
+ - i2c-sda-falling-time : should contain the SDA falling time in nanoseconds.
+   This value which is by default 300ns is used to compute the tHIGH period.
+
 Example :
 
        i2c@f0000 {
@@ -34,4 +40,6 @@ Example :
                interrupts = <12 1>;
                clock-frequency = <400000>;
                i2c-sda-hold-time-ns = <300>;
+               i2c-sda-falling-time-ns = <300>;
+               i2c-scl-falling-time-ns = <300>;
        };
index 14c4b30d4ccc174240bd455a392a3bd60c7a9230..22e92c3d3d07448cea9aa37fcc4ad6c612570e13 100644 (file)
@@ -218,7 +218,7 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
                 *
                 * If your hardware is free from tHD;STA issue, try this one.
                 */
-               return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+               return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
        else
                /*
                 * Conditional expression:
@@ -234,7 +234,8 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
                 * The reason why we need to take into account "tf" here,
                 * is the same as described in i2c_dw_scl_lcnt().
                 */
-               return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+               return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
+                       - 3 + offset;
 }
 
 static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
@@ -250,7 +251,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
         * account the fall time of SCL signal (tf).  Default tf value
         * should be 0.3 us, for safety.
         */
-       return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+       return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
 }
 
 static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
@@ -287,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        u32 input_clock_khz;
        u32 hcnt, lcnt;
        u32 reg;
+       u32 sda_falling_time, scl_falling_time;
 
        input_clock_khz = dev->get_clk_rate_khz(dev);
 
@@ -308,15 +310,18 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
        /* set standard and fast speed deviders for high/low periods */
 
+       sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
+       scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
+
        /* Standard-mode */
        hcnt = i2c_dw_scl_hcnt(input_clock_khz,
-                               40,     /* tHD;STA = tHIGH = 4.0 us */
-                               3,      /* tf = 0.3 us */
+                               4000,   /* tHD;STA = tHIGH = 4.0 us */
+                               sda_falling_time,
                                0,      /* 0: DW default, 1: Ideal */
                                0);     /* No offset */
        lcnt = i2c_dw_scl_lcnt(input_clock_khz,
-                               47,     /* tLOW = 4.7 us */
-                               3,      /* tf = 0.3 us */
+                               4700,   /* tLOW = 4.7 us */
+                               scl_falling_time,
                                0);     /* No offset */
 
        /* Allow platforms to specify the ideal HCNT and LCNT values */
@@ -330,13 +335,13 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
        /* Fast-mode */
        hcnt = i2c_dw_scl_hcnt(input_clock_khz,
-                               6,      /* tHD;STA = tHIGH = 0.6 us */
-                               3,      /* tf = 0.3 us */
+                               600,    /* tHD;STA = tHIGH = 0.6 us */
+                               sda_falling_time,
                                0,      /* 0: DW default, 1: Ideal */
                                0);     /* No offset */
        lcnt = i2c_dw_scl_lcnt(input_clock_khz,
-                               13,     /* tLOW = 1.3 us */
-                               3,      /* tf = 0.3 us */
+                               1300,   /* tLOW = 1.3 us */
+                               scl_falling_time,
                                0);     /* No offset */
 
        if (dev->fs_hcnt && dev->fs_lcnt) {
index e8a756537ed036dbabb49302bbe0eaa4ac0abfac..d66b6cbc9edcbb742079612d336cc56e093b99c4 100644 (file)
@@ -99,6 +99,8 @@ struct dw_i2c_dev {
        unsigned int            rx_fifo_depth;
        int                     rx_outstanding;
        u32                     sda_hold_time;
+       u32                     sda_falling_time;
+       u32                     scl_falling_time;
        u16                     ss_hcnt;
        u16                     ss_lcnt;
        u16                     fs_hcnt;
index d0bdac0498cebafe3def932006c1380cfc318c1f..fc243992b4b4e1f825add9e5470025d637dbfe91 100644 (file)
@@ -159,6 +159,13 @@ static int dw_i2c_probe(struct platform_device *pdev)
                                        "i2c-sda-hold-time-ns", &ht);
                dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
                                             1000000);
+
+               of_property_read_u32(pdev->dev.of_node,
+                                    "i2c-sda-falling-time-ns",
+                                    &dev->sda_falling_time);
+               of_property_read_u32(pdev->dev.of_node,
+                                    "i2c-scl-falling-time-ns",
+                                    &dev->scl_falling_time);
        }
 
        dev->functionality =
This page took 0.028285 seconds and 5 git commands to generate.