i2c: designware: detect when dynamic tar update is possible
authorLucas De Marchi <lucas.demarchi@intel.com>
Tue, 23 Aug 2016 22:18:55 +0000 (19:18 -0300)
committerWolfram Sang <wsa@the-dreams.de>
Thu, 25 Aug 2016 22:42:15 +0000 (00:42 +0200)
This adapter can be synthesized with dynamic tar update enabled or disabled.
When enabled it is not necessary to disable the adapter to change the slave
address in some situations, which saves some time per transaction.

There is no direct register to know if this feature is enabled but we can do it
indirectly by writing to the 10BIT_ADDR field in IC_CON: this field is
read only when dynamic tar update is enabled.

Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Christian Ruppert <christian.ruppert@alitech.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-core.h

index 2bf4f60..e1f1b75 100644 (file)
@@ -460,27 +460,29 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
 static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
-       u32 ic_con, ic_tar = 0;
+       u32 ic_tar = 0;
 
        /* Disable the adapter */
        __i2c_dw_enable_and_wait(dev, false);
 
        /* if the slave address is ten bit address, enable 10BITADDR */
-       ic_con = dw_readl(dev, DW_IC_CON);
-       if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
-               ic_con |= DW_IC_CON_10BITADDR_MASTER;
+       if (dev->dynamic_tar_update_enabled) {
                /*
                 * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
-                * mode has to be enabled via bit 12 of IC_TAR register.
-                * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be
-                * detected from registers.
+                * mode has to be enabled via bit 12 of IC_TAR register,
+                * otherwise bit 4 of IC_CON is used.
                 */
-               ic_tar = DW_IC_TAR_10BITADDR_MASTER;
+               if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+                       ic_tar = DW_IC_TAR_10BITADDR_MASTER;
        } else {
-               ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
-       }
+               u32 ic_con = dw_readl(dev, DW_IC_CON);
 
-       dw_writel(dev, ic_con, DW_IC_CON);
+               if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+                       ic_con |= DW_IC_CON_10BITADDR_MASTER;
+               else
+                       ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+               dw_writel(dev, ic_con, DW_IC_CON);
+       }
 
        /*
         * Set the slave (target) address and enable 10-bit addressing mode
@@ -901,6 +903,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
 {
        struct i2c_adapter *adap = &dev->adapter;
        int r;
+       u32 reg;
 
        init_completion(&dev->cmd_complete);
 
@@ -908,6 +911,26 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
        if (r)
                return r;
 
+       r = i2c_dw_acquire_lock(dev);
+       if (r)
+               return r;
+
+       /*
+        * Test if dynamic TAR update is enabled in this controller by writing
+        * to IC_10BITADDR_MASTER field in IC_CON: when it is enabled this
+        * field is read-only so it should not succeed
+        */
+       reg = dw_readl(dev, DW_IC_CON);
+       dw_writel(dev, reg ^ DW_IC_CON_10BITADDR_MASTER, DW_IC_CON);
+
+       if ((dw_readl(dev, DW_IC_CON) & DW_IC_CON_10BITADDR_MASTER) ==
+           (reg & DW_IC_CON_10BITADDR_MASTER)) {
+               dev->dynamic_tar_update_enabled = true;
+               dev_dbg(dev->dev, "Dynamic TAR update enabled");
+       }
+
+       i2c_dw_release_lock(dev);
+
        snprintf(adap->name, sizeof(adap->name),
                 "Synopsys DesignWare I2C adapter");
        adap->retries = 3;
index 22bfbe1..0d44d2a 100644 (file)
@@ -117,6 +117,7 @@ struct dw_i2c_dev {
        int                     (*acquire_lock)(struct dw_i2c_dev *dev);
        void                    (*release_lock)(struct dw_i2c_dev *dev);
        bool                    pm_runtime_disabled;
+       bool                    dynamic_tar_update_enabled;
 };
 
 #define ACCESS_SWAP            0x00000001