diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-core.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-core.c | 59 | 
1 files changed, 40 insertions, 19 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index dbecf08399f..3c20e4bd6dd 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -26,7 +26,6 @@   *   */  #include <linux/export.h> -#include <linux/clk.h>  #include <linux/errno.h>  #include <linux/err.h>  #include <linux/i2c.h> @@ -98,6 +97,8 @@  #define DW_IC_ERR_TX_ABRT	0x1 +#define DW_IC_TAR_10BITADDR_MASTER BIT(12) +  /*   * status codes   */ @@ -217,7 +218,7 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)  		 *  		 * If your hardware is free from tHD;STA issue, try this one.  		 */ -		return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset; +		return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;  	else  		/*  		 * Conditional expression: @@ -233,7 +234,8 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)  		 * The reason why we need to take into account "tf" here,  		 * is the same as described in i2c_dw_scl_lcnt().  		 */ -		return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset; +		return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000 +			- 3 + offset;  }  static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) @@ -249,7 +251,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)  	 * account the fall time of SCL signal (tf).  Default tf value  	 * should be 0.3 us, for safety.  	 */ -	return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset; +	return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;  }  static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) @@ -286,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)  	u32 input_clock_khz;  	u32 hcnt, lcnt;  	u32 reg; +	u32 sda_falling_time, scl_falling_time;  	input_clock_khz = dev->get_clk_rate_khz(dev); @@ -307,15 +310,18 @@ int i2c_dw_init(struct dw_i2c_dev *dev)  	/* set standard and fast speed deviders for high/low periods */ +	sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ +	scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ +  	/* Standard-mode */  	hcnt = i2c_dw_scl_hcnt(input_clock_khz, -				40,	/* tHD;STA = tHIGH = 4.0 us */ -				3,	/* tf = 0.3 us */ +				4000,	/* tHD;STA = tHIGH = 4.0 us */ +				sda_falling_time,  				0,	/* 0: DW default, 1: Ideal */  				0);	/* No offset */  	lcnt = i2c_dw_scl_lcnt(input_clock_khz, -				47,	/* tLOW = 4.7 us */ -				3,	/* tf = 0.3 us */ +				4700,	/* tLOW = 4.7 us */ +				scl_falling_time,  				0);	/* No offset */  	/* Allow platforms to specify the ideal HCNT and LCNT values */ @@ -329,13 +335,13 @@ int i2c_dw_init(struct dw_i2c_dev *dev)  	/* Fast-mode */  	hcnt = i2c_dw_scl_hcnt(input_clock_khz, -				6,	/* tHD;STA = tHIGH = 0.6 us */ -				3,	/* tf = 0.3 us */ +				600,	/* tHD;STA = tHIGH = 0.6 us */ +				sda_falling_time,  				0,	/* 0: DW default, 1: Ideal */  				0);	/* No offset */  	lcnt = i2c_dw_scl_lcnt(input_clock_khz, -				13,	/* tLOW = 1.3 us */ -				3,	/* tf = 0.3 us */ +				1300,	/* tLOW = 1.3 us */ +				scl_falling_time,  				0);	/* No offset */  	if (dev->fs_hcnt && dev->fs_lcnt) { @@ -388,22 +394,37 @@ 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; +	u32 ic_con, ic_tar = 0;  	/* Disable the adapter */  	__i2c_dw_enable(dev, false); -	/* set the slave (target) address */ -	dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR); -  	/* 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) +	if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {  		ic_con |= DW_IC_CON_10BITADDR_MASTER; -	else +		/* +		 * 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. +		 */ +		ic_tar = DW_IC_TAR_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 +	 * if applicable. +	 */ +	dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR); + +	/* enforce disabled interrupts (due to HW issues) */ +	i2c_dw_disable_int(dev); +  	/* Enable the adapter */  	__i2c_dw_enable(dev, true); @@ -599,7 +620,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)  	mutex_lock(&dev->lock);  	pm_runtime_get_sync(dev->dev); -	INIT_COMPLETION(dev->cmd_complete); +	reinit_completion(&dev->cmd_complete);  	dev->msgs = msgs;  	dev->msgs_num = num;  	dev->cmd_err = 0;  | 
