drm/i915: abstract i2c bit banging fallback in gmbus xfer
authorJani Nikula <jani.nikula@intel.com>
Tue, 1 Dec 2015 14:29:26 +0000 (16:29 +0200)
committerJani Nikula <jani.nikula@intel.com>
Wed, 2 Dec 2015 11:29:41 +0000 (13:29 +0200)
Choose between i2c bit banging and gmbus in a new higher level function,
and let the i2c core retry the first time we fall back to bit banging.

The i2c core imposes a timeout on -EAGAIN, but it defaults to 1 second,
and shouldn't be a problem for us.

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1448980166-23055-2-git-send-email-jani.nikula@intel.com
drivers/gpu/drm/i915/intel_i2c.c

index ccb522c176bd2fe3839ea5e7434a2d9f86229402..e26e22a72e3b0de4db710b9f2c212e14e646f966 100644 (file)
@@ -472,9 +472,7 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 }
 
 static int
-gmbus_xfer(struct i2c_adapter *adapter,
-          struct i2c_msg *msgs,
-          int num)
+do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 {
        struct intel_gmbus *bus = container_of(adapter,
                                               struct intel_gmbus,
@@ -483,14 +481,6 @@ gmbus_xfer(struct i2c_adapter *adapter,
        int i = 0, inc, try = 0;
        int ret = 0;
 
-       intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
-       mutex_lock(&dev_priv->gmbus_mutex);
-
-       if (bus->force_bit) {
-               ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
-               goto out;
-       }
-
 retry:
        I915_WRITE(GMBUS0, bus->reg0);
 
@@ -585,13 +575,34 @@ timeout:
                 bus->adapter.name, bus->reg0 & 0xff);
        I915_WRITE(GMBUS0, 0);
 
-       /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+       /*
+        * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
+        * instead. Use EAGAIN to have i2c core retry.
+        */
        bus->force_bit = 1;
-       ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
+       ret = -EAGAIN;
 
 out:
-       mutex_unlock(&dev_priv->gmbus_mutex);
+       return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+       struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
+                                              adapter);
+       struct drm_i915_private *dev_priv = bus->dev_priv;
+       int ret;
+
+       intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+       mutex_lock(&dev_priv->gmbus_mutex);
+
+       if (bus->force_bit)
+               ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
+       else
+               ret = do_gmbus_xfer(adapter, msgs, num);
 
+       mutex_unlock(&dev_priv->gmbus_mutex);
        intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
 
        return ret;