Commit 2702ea7d authored by José Roberto de Souza's avatar José Roberto de Souza Committed by Wolfram Sang

i2c: designware: wait for disable/enable only if necessary

If we aren't going to continue using the controller we can just disable
it instead of waiting for it to complete. The biggest improvement here
is when a I2C transaction is completed and it doesn't block until
the adapter is disabled. When a new transfer is needed we will disable
and wait for its completion.

This way the adapter will continue changing its state in parallel to the
execution of the thread that requested the I2C transaction saving most
of the time 25~250 usec per I2C transaction.

A simple program doing a register read (1 byte write, 1 byte read)
alternating on 2 different slaves repeated 25k times for each and
measurements taken 4 times we get:

perf stat -r4 chrt -f 10 ./i2c-test /dev/i2c-1 25000 0x40 0x6 0x1e 0x00

Before:
	30.879317977 seconds time elapsed                 ( +- 14.83% )
After:
	8.638705161 seconds time elapsed                  ( +-  5.90% )
Signed-off-by: default avatarJosé Roberto de Souza <jose.souza@intel.com>
Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
Acked-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: default avatarChristian Ruppert <christian.ruppert@alitech.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 10f8e7fb
...@@ -256,11 +256,16 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) ...@@ -256,11 +256,16 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
} }
static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
{
dw_writel(dev, enable, DW_IC_ENABLE);
}
static void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable)
{ {
int timeout = 100; int timeout = 100;
do { do {
dw_writel(dev, enable, DW_IC_ENABLE); __i2c_dw_enable(dev, enable);
if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
return; return;
...@@ -328,7 +333,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -328,7 +333,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
/* Disable the adapter */ /* Disable the adapter */
__i2c_dw_enable(dev, false); __i2c_dw_enable_and_wait(dev, false);
/* set standard and fast speed deviders for high/low periods */ /* set standard and fast speed deviders for high/low periods */
...@@ -441,7 +446,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) ...@@ -441,7 +446,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
u32 ic_con, ic_tar = 0; u32 ic_con, ic_tar = 0;
/* Disable the adapter */ /* Disable the adapter */
__i2c_dw_enable(dev, false); __i2c_dw_enable_and_wait(dev, false);
/* if the slave address is ten bit address, enable 10BITADDR */ /* if the slave address is ten bit address, enable 10BITADDR */
ic_con = dw_readl(dev, DW_IC_CON); ic_con = dw_readl(dev, DW_IC_CON);
...@@ -860,7 +865,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) ...@@ -860,7 +865,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
void i2c_dw_disable(struct dw_i2c_dev *dev) void i2c_dw_disable(struct dw_i2c_dev *dev)
{ {
/* Disable controller */ /* Disable controller */
__i2c_dw_enable(dev, false); __i2c_dw_enable_and_wait(dev, false);
/* Disable all interupts */ /* Disable all interupts */
dw_writel(dev, 0, DW_IC_INTR_MASK); dw_writel(dev, 0, DW_IC_INTR_MASK);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment