Re: [PATCH V6 1/2] i2c/adapter: Add bus recovery infrastructure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Wolfram/Paul,

I have tried to fix my patches as per review comments from you.
Following is diff of the new changes i have made, I am sending a
new complete version separately:

commit 62cf40359c63ac028b3e8a6395f9440f6a3b0162
Author: Viresh Kumar <viresh.kumar@xxxxxxxxxx>
Date:   Mon Dec 3 08:12:55 2012 +0530

    fixup! i2c/adapter: Add bus recovery infrastructure
---
 drivers/i2c/i2c-core.c | 42 +++++++++++++++++++++++++++---------------
 include/linux/i2c.h    | 19 +++++++++++--------
 2 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d100276..9b6a1a6 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -109,15 +109,22 @@ static int i2c_device_uevent(struct device *dev,
struct kobj_uevent_env *env)
 /* i2c bus recovery routines */
 #define RECOVERY_CLK_CNT       9
 #define DEFAULT_CLK_RATE       100     /* KHz */
+/* 10^6/KHz for delay in ns */
+unsigned long clk_delay = DIV_ROUND_UP(1000000, DEFAULT_CLK_RATE * 2);

-static void set_scl_gpio_value(struct i2c_adapter *adap, int val)
+static int get_sda_gpio_value(struct i2c_adapter *adap)
 {
-       gpio_set_value(adap->bus_recovery_info->scl_gpio, val);
+       return gpio_get_value(adap->bus_recovery_info->sda_gpio);
 }

-static int get_sda_gpio_value(struct i2c_adapter *adap)
+static int get_scl_gpio_value(struct i2c_adapter *adap)
 {
-       return gpio_get_value(adap->bus_recovery_info->sda_gpio);
+       return gpio_get_value(adap->bus_recovery_info->scl_gpio);
+}
+
+static void set_scl_gpio_value(struct i2c_adapter *adap, int val)
+{
+       gpio_set_value(adap->bus_recovery_info->scl_gpio, val);
 }

 static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap)
@@ -158,28 +165,37 @@ static void i2c_put_gpios_for_recovery(struct
i2c_adapter *adap)
 static int i2c_generic_recovery(struct i2c_adapter *adap)
 {
        struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
-       unsigned long delay = 1000000; /* 10^6/KHz for delay in ns */
        int i, val = 0;

        if (bri->prepare_recovery)
                bri->prepare_recovery(bri);

+       /* SCL shouldn't be low here */
+       if (!bri->get_scl(adap)) {
+               dev_err(&adap->dev, "SCL is stuck Low, exiting recovery.\n");
+               goto unprepare;
+       }
+
        /*
         * By this time SCL is high, as we need to give 9 falling-rising edges
         */
-
-       delay = DIV_ROUND_UP(delay, bri->clock_rate_khz * 2);
-
        for (i = 0; i < RECOVERY_CLK_CNT * 2; i++, val = !val) {
                bri->set_scl(adap, val);
-               ndelay(delay);
+               ndelay(clk_delay);

                /* break if sda got high, check only when scl line is high */
                if (!bri->skip_sda_polling && val)
-                       if (unlikely(bri->get_sda(adap)))
+                       /* Check SCL again to see fault condition */
+                       if (!bri->get_scl(adap)) {
+                               dev_err(&adap->dev, "SCL is stuck Low
during recovery, exiting recovery.\n");
+                               goto unprepare;
+                       }
+
+                       if (bri->get_sda(adap))
                                break;
        }

+unprepare:
        if (bri->unprepare_recovery)
                bri->unprepare_recovery(bri);

@@ -1008,13 +1024,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                        goto exit_recovery;
                }

-               if (!bri->clock_rate_khz) {
-                       dev_warn(&adap->dev, "default clk rate used: 100KHz\n");
-                       bri->clock_rate_khz = DEFAULT_CLK_RATE;
-               }
-
                /* GPIO recovery */
                if (bri->recover_bus == i2c_generic_gpio_recovery) {
+                       bri->get_scl = get_scl_gpio_value;
                        bri->set_scl = set_scl_gpio_value;

                        if (!bri->skip_sda_polling)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 63acd9d..165282f 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -373,14 +373,17 @@ struct i2c_algorithm {
  * @recover_bus: Recover routine. Either pass driver's recover_bus()
routine, or
  *     i2c_generic_scl_recovery() or i2c_generic_gpio_recovery().
  * @skip_sda_polling: if true, bus recovery will not poll sda line to check if
- *     it became high or not. Only required if recover_bus == NULL.
- * @clock_rate_khz: clock rate of dummy clock in khz. Required for
both gpio and
- *     scl type recovery.
- * @set_scl: This sets/clears scl line. For GPIO recovery set_scl_gpio_value()
- *     is used here otherwise controller specific routine must be passed.
+ *     it became high or not. Platforms/controllers which don't have
+ *     configuration registers to control sda line must set this. Only required
+ *     if recover_bus == NULL.
  * @get_sda: This gets current value of sda line. For GPIO recovery
  *     get_sda_gpio_value() is used here otherwise controller specific routine
  *     must be passed.
+ * @get_scl: This gets current value of scl line. For GPIO recovery
+ *     get_scl_gpio_value() is used here otherwise controller specific routine
+ *     must be passed.
+ * @set_scl: This sets/clears scl line. For GPIO recovery set_scl_gpio_value()
+ *     is used here otherwise controller specific routine must be passed.
  * @prepare_recovery: This will be called before starting recovery.
Platform may
  *     configure padmux here for sda/scl line or something else they want.
  * @unprepare_recovery: This will be called after completing recovery. Platform
@@ -391,15 +394,15 @@ struct i2c_algorithm {
 struct i2c_bus_recovery_info {
        int (*recover_bus)(struct i2c_adapter *);
        bool skip_sda_polling;
-       u32 clock_rate_khz;

        /*
         * Fn pointers for recovery, will point either to:
-        * - set_scl_gpio_value and get_sda_gpio_value for gpio recovery
+        * - set_scl_gpio_value and get_[scl]sda_gpio_value for gpio recovery
         * - Controller specific routines, otherwise
         */
-       void (*set_scl)(struct i2c_adapter *, int val);
        int (*get_sda)(struct i2c_adapter *);
+       int (*get_scl)(struct i2c_adapter *);
+       void (*set_scl)(struct i2c_adapter *, int val);

        void (*prepare_recovery)(struct i2c_bus_recovery_info *bri);
        void (*unprepare_recovery)(struct i2c_bus_recovery_info *bri);
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux