]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/drm_dp_helper.c
Merge remote-tracking branch 'pci-current/for-linus'
[karo-tx-linux.git] / drivers / gpu / drm / drm_dp_helper.c
index 27671489477de6cb6c37eeb80959475d38b71bcc..08e33b8b13a433be43b0a39f462791388a856b95 100644 (file)
@@ -206,13 +206,17 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
  * i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper
  * @adapter: i2c adapter to register
  *
- * This registers an i2c adapater that uses dp aux channel as it's underlaying
+ * This registers an i2c adapter that uses dp aux channel as it's underlaying
  * transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure
  * and store it in the algo_data member of the @adapter argument. This will be
  * used by the i2c over dp aux algorithm to drive the hardware.
  *
  * RETURNS:
  * 0 on success, -ERRNO on failure.
+ *
+ * IMPORTANT:
+ * This interface is deprecated, please switch to the new dp aux helpers and
+ * drm_dp_aux_register().
  */
 int
 i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
@@ -378,7 +382,10 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
         * transactions.
         */
        for (retry = 0; retry < 7; retry++) {
+
+               mutex_lock(&aux->hw_mutex);
                err = aux->transfer(aux, &msg);
+               mutex_unlock(&aux->hw_mutex);
                if (err < 0) {
                        if (err == -EBUSY)
                                continue;
@@ -577,7 +584,9 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
 
 /*
  * Transfer a single I2C-over-AUX message and handle various error conditions,
- * retrying the transaction as appropriate.
+ * retrying the transaction as appropriate.  It is assumed that the
+ * aux->transfer function does not modify anything in the msg other than the
+ * reply field.
  */
 static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
@@ -590,7 +599,9 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
         * before giving up the AUX transaction.
         */
        for (retry = 0; retry < 7; retry++) {
+               mutex_lock(&aux->hw_mutex);
                err = aux->transfer(aux, msg);
+               mutex_unlock(&aux->hw_mutex);
                if (err < 0) {
                        if (err == -EBUSY)
                                continue;
@@ -665,11 +676,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 {
        struct drm_dp_aux *aux = adapter->algo_data;
        unsigned int i, j;
+       struct drm_dp_aux_msg msg;
+       int err = 0;
 
-       for (i = 0; i < num; i++) {
-               struct drm_dp_aux_msg msg;
-               int err;
+       memset(&msg, 0, sizeof(msg));
 
+       for (i = 0; i < num; i++) {
+               msg.address = msgs[i].addr;
+               msg.request = (msgs[i].flags & I2C_M_RD) ?
+                       DP_AUX_I2C_READ :
+                       DP_AUX_I2C_WRITE;
+               msg.request |= DP_AUX_I2C_MOT;
+               /* Send a bare address packet to start the transaction.
+                * Zero sized messages specify an address only (bare
+                * address) transaction.
+                */
+               msg.buffer = NULL;
+               msg.size = 0;
+               err = drm_dp_i2c_do_msg(aux, &msg);
+               if (err < 0)
+                       break;
                /*
                 * Many hardware implementations support FIFOs larger than a
                 * single byte, but it has been empirically determined that
@@ -678,30 +704,28 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                 * transferred byte-by-byte.
                 */
                for (j = 0; j < msgs[i].len; j++) {
-                       memset(&msg, 0, sizeof(msg));
-                       msg.address = msgs[i].addr;
-
-                       msg.request = (msgs[i].flags & I2C_M_RD) ?
-                                       DP_AUX_I2C_READ :
-                                       DP_AUX_I2C_WRITE;
-
-                       /*
-                        * All messages except the last one are middle-of-
-                        * transfer messages.
-                        */
-                       if ((i < num - 1) || (j < msgs[i].len - 1))
-                               msg.request |= DP_AUX_I2C_MOT;
-
                        msg.buffer = msgs[i].buf + j;
                        msg.size = 1;
 
                        err = drm_dp_i2c_do_msg(aux, &msg);
                        if (err < 0)
-                               return err;
+                               break;
                }
+               if (err < 0)
+                       break;
        }
+       if (err >= 0)
+               err = num;
+       /* Send a bare address packet to close out the transaction.
+        * Zero sized messages specify an address only (bare
+        * address) transaction.
+        */
+       msg.request &= ~DP_AUX_I2C_MOT;
+       msg.buffer = NULL;
+       msg.size = 0;
+       (void)drm_dp_i2c_do_msg(aux, &msg);
 
-       return num;
+       return err;
 }
 
 static const struct i2c_algorithm drm_dp_i2c_algo = {
@@ -710,13 +734,15 @@ static const struct i2c_algorithm drm_dp_i2c_algo = {
 };
 
 /**
- * drm_dp_aux_register_i2c_bus() - register an I2C adapter for I2C-over-AUX
+ * drm_dp_aux_register() - initialise and register aux channel
  * @aux: DisplayPort AUX channel
  *
  * Returns 0 on success or a negative error code on failure.
  */
-int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux)
+int drm_dp_aux_register(struct drm_dp_aux *aux)
 {
+       mutex_init(&aux->hw_mutex);
+
        aux->ddc.algo = &drm_dp_i2c_algo;
        aux->ddc.algo_data = aux;
        aux->ddc.retries = 3;
@@ -731,14 +757,14 @@ int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux)
 
        return i2c_add_adapter(&aux->ddc);
 }
-EXPORT_SYMBOL(drm_dp_aux_register_i2c_bus);
+EXPORT_SYMBOL(drm_dp_aux_register);
 
 /**
- * drm_dp_aux_unregister_i2c_bus() - unregister an I2C-over-AUX adapter
+ * drm_dp_aux_unregister() - unregister an AUX adapter
  * @aux: DisplayPort AUX channel
  */
-void drm_dp_aux_unregister_i2c_bus(struct drm_dp_aux *aux)
+void drm_dp_aux_unregister(struct drm_dp_aux *aux)
 {
        i2c_del_adapter(&aux->ddc);
 }
-EXPORT_SYMBOL(drm_dp_aux_unregister_i2c_bus);
+EXPORT_SYMBOL(drm_dp_aux_unregister);