diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 3 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-cadence.c | 28 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-common.c | 25 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 3 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-pcidrv.c | 2 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 17 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-eg20t.c | 1 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-fsi.c | 2 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-mlxcpld.c | 4 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-qcom-geni.c | 6 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 3 | ||||
| -rw-r--r-- | drivers/i2c/i2c-core-smbus.c | 7 | 
13 files changed, 73 insertions, 35 deletions
| diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index ef39c83aaf33..bae1dc08ec9a 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -113,11 +113,18 @@ config I2C_STUB  config I2C_SLAVE  	bool "I2C slave support" +	help +	  This enables Linux to act as an I2C slave device. Note that your I2C +	  bus master driver also needs to support this functionality. Please +	  read Documentation/i2c/slave-interface.rst for further details.  if I2C_SLAVE  config I2C_SLAVE_EEPROM  	tristate "I2C eeprom slave driver" +	help +	  This backend makes Linux behave like an I2C EEPROM. Please read +	  Documentation/i2c/slave-eeprom-backend.rst for further details.  endif diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 7f10312d1b88..388978775be0 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -314,7 +314,8 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,  			DEB2("BUS ERROR - SDA Stuck low\n");  			pca_reset(adap);  			goto out; -		case 0x90: /* Bus error - SCL stuck low */ +		case 0x78: /* Bus error - SCL stuck low (PCA9665) */ +		case 0x90: /* Bus error - SCL stuck low (PCA9564) */  			DEB2("BUS ERROR - SCL Stuck low\n");  			pca_reset(adap);  			goto out; diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 4b72398af505..e4b7f2a951ad 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -421,20 +421,21 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)  		/* Read data if receive data valid is set */  		while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &  		       CDNS_I2C_SR_RXDV) { -			/* -			 * Clear hold bit that was set for FIFO control if -			 * RX data left is less than FIFO depth, unless -			 * repeated start is selected. -			 */ -			if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) && -			    !id->bus_hold_flag) -				cdns_i2c_clear_bus_hold(id); -  			if (id->recv_count > 0) {  				*(id->p_recv_buf)++ =  					cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);  				id->recv_count--;  				id->curr_recv_count--; + +				/* +				 * Clear hold bit that was set for FIFO control +				 * if RX data left is less than or equal to +				 * FIFO DEPTH unless repeated start is selected +				 */ +				if (id->recv_count <= CDNS_I2C_FIFO_DEPTH && +				    !id->bus_hold_flag) +					cdns_i2c_clear_bus_hold(id); +  			} else {  				dev_err(id->adap.dev.parent,  					"xfer_size reg rollover. xfer aborted!\n"); @@ -594,10 +595,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)  	 * Check for the message size against FIFO depth and set the  	 * 'hold bus' bit if it is greater than FIFO depth.  	 */ -	if ((id->recv_count > CDNS_I2C_FIFO_DEPTH)  || id->bus_hold_flag) +	if (id->recv_count > CDNS_I2C_FIFO_DEPTH)  		ctrl_reg |= CDNS_I2C_CR_HOLD; -	else -		ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD;  	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); @@ -654,11 +653,8 @@ static void cdns_i2c_msend(struct cdns_i2c *id)  	 * Check for the message size against FIFO depth and set the  	 * 'hold bus' bit if it is greater than FIFO depth.  	 */ -	if ((id->send_count > CDNS_I2C_FIFO_DEPTH) || id->bus_hold_flag) +	if (id->send_count > CDNS_I2C_FIFO_DEPTH)  		ctrl_reg |= CDNS_I2C_CR_HOLD; -	else -		ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD; -  	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);  	/* Clear the interrupts in interrupt status register. */ diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index e3a8640db7da..3c19aada4b30 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -286,10 +286,8 @@ int i2c_dw_acpi_configure(struct device *device)  }  EXPORT_SYMBOL_GPL(i2c_dw_acpi_configure); -void i2c_dw_acpi_adjust_bus_speed(struct device *device) +static u32 i2c_dw_acpi_round_bus_speed(struct device *device)  { -	struct dw_i2c_dev *dev = dev_get_drvdata(device); -	struct i2c_timings *t = &dev->timings;  	u32 acpi_speed;  	int i; @@ -300,9 +298,22 @@ void i2c_dw_acpi_adjust_bus_speed(struct device *device)  	 */  	for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {  		if (acpi_speed >= supported_speeds[i]) -			break; +			return supported_speeds[i];  	} -	acpi_speed = i < ARRAY_SIZE(supported_speeds) ? supported_speeds[i] : 0; + +	return 0; +} + +#else	/* CONFIG_ACPI */ + +static inline u32 i2c_dw_acpi_round_bus_speed(struct device *device) { return 0; } + +#endif	/* CONFIG_ACPI */ + +void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) +{ +	u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev); +	struct i2c_timings *t = &dev->timings;  	/*  	 * Find bus speed from the "clock-frequency" device property, ACPI @@ -315,9 +326,7 @@ void i2c_dw_acpi_adjust_bus_speed(struct device *device)  	else  		t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;  } -EXPORT_SYMBOL_GPL(i2c_dw_acpi_adjust_bus_speed); - -#endif	/* CONFIG_ACPI */ +EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed);  u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)  { diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 556673a1f61b..eb5ef4d0f463 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -361,11 +361,10 @@ static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0;  #endif  int i2c_dw_validate_speed(struct dw_i2c_dev *dev); +void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev);  #if IS_ENABLED(CONFIG_ACPI)  int i2c_dw_acpi_configure(struct device *device); -void i2c_dw_acpi_adjust_bus_speed(struct device *device);  #else  static inline int i2c_dw_acpi_configure(struct device *device) { return -ENODEV; } -static inline void i2c_dw_acpi_adjust_bus_speed(struct device *device) {}  #endif diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 947c096f86e3..8522134f9ea9 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -240,7 +240,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,  		}  	} -	i2c_dw_acpi_adjust_bus_speed(&pdev->dev); +	i2c_dw_adjust_bus_speed(dev);  	if (has_acpi_companion(&pdev->dev))  		i2c_dw_acpi_configure(&pdev->dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0de4e302fc6a..a71bc58fc03c 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -12,6 +12,7 @@  #include <linux/clk-provider.h>  #include <linux/clk.h>  #include <linux/delay.h> +#include <linux/dmi.h>  #include <linux/err.h>  #include <linux/errno.h>  #include <linux/i2c.h> @@ -191,6 +192,17 @@ static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)  	return ret;  } +static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { +	{ +		.ident = "Qtechnology QT5222", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Qtechnology"), +			DMI_MATCH(DMI_PRODUCT_NAME, "QT5222"), +		}, +	}, +	{ } /* terminate list */ +}; +  static int dw_i2c_plat_probe(struct platform_device *pdev)  {  	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -228,7 +240,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  	else  		i2c_parse_fw_timings(&pdev->dev, t, false); -	i2c_dw_acpi_adjust_bus_speed(&pdev->dev); +	i2c_dw_adjust_bus_speed(dev);  	if (pdev->dev.of_node)  		dw_i2c_of_configure(pdev); @@ -267,7 +279,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  	adap = &dev->adapter;  	adap->owner = THIS_MODULE; -	adap->class = I2C_CLASS_DEPRECATED; +	adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ? +					I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;  	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));  	adap->dev.of_node = pdev->dev.of_node;  	adap->nr = -1; diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index bb810dee8fb5..73f139690e4e 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -180,6 +180,7 @@ static const struct pci_device_id pch_pcidev_id[] = {  	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },  	{0,}  }; +MODULE_DEVICE_TABLE(pci, pch_pcidev_id);  static irqreturn_t pch_i2c_handler(int irq, void *pData); diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index e0c256922d4f..977d6f524649 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -98,7 +98,7 @@  #define I2C_STAT_DAT_REQ	BIT(25)  #define I2C_STAT_CMD_COMP	BIT(24)  #define I2C_STAT_STOP_ERR	BIT(23) -#define I2C_STAT_MAX_PORT	GENMASK(19, 16) +#define I2C_STAT_MAX_PORT	GENMASK(22, 16)  #define I2C_STAT_ANY_INT	BIT(15)  #define I2C_STAT_SCL_IN		BIT(11)  #define I2C_STAT_SDA_IN		BIT(10) diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 2fd717d8dd30..71d7bae2cbca 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -337,9 +337,9 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)  		if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) {  			mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,  					      &datalen, 1); -			if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) { +			if (unlikely(datalen > I2C_SMBUS_BLOCK_MAX)) {  				dev_err(priv->dev, "Incorrect smbus block read message len\n"); -				return -E2BIG; +				return -EPROTO;  			}  		} else {  			datalen = priv->xfer.data_len; diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 18d1e4fd4cf3..7f130829bf01 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -367,7 +367,6 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,  		geni_se_select_mode(se, GENI_SE_FIFO);  	writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN); -	geni_se_setup_m_cmd(se, I2C_READ, m_param);  	if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {  		geni_se_select_mode(se, GENI_SE_FIFO); @@ -375,6 +374,8 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,  		dma_buf = NULL;  	} +	geni_se_setup_m_cmd(se, I2C_READ, m_param); +  	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);  	if (!time_left)  		geni_i2c_abort_xfer(gi2c); @@ -408,7 +409,6 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,  		geni_se_select_mode(se, GENI_SE_FIFO);  	writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN); -	geni_se_setup_m_cmd(se, I2C_WRITE, m_param);  	if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {  		geni_se_select_mode(se, GENI_SE_FIFO); @@ -416,6 +416,8 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,  		dma_buf = NULL;  	} +	geni_se_setup_m_cmd(se, I2C_WRITE, m_param); +  	if (!dma_buf) /* Get FIFO IRQ */  		writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index a45c4bf1ec01..2e3e1bb75013 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -868,6 +868,7 @@ static int rcar_unreg_slave(struct i2c_client *slave)  	/* disable irqs and ensure none is running before clearing ptr */  	rcar_i2c_write(priv, ICSIER, 0);  	rcar_i2c_write(priv, ICSCR, 0); +	rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */  	synchronize_irq(priv->irq);  	priv->slave = NULL; @@ -969,6 +970,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)  	if (ret < 0)  		goto out_pm_put; +	rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ +  	if (priv->devtype == I2C_RCAR_GEN3) {  		priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);  		if (!IS_ERR(priv->rstc)) { diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 56bb840142e3..f5c9787992e9 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -495,6 +495,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,  			break;  		case I2C_SMBUS_BLOCK_DATA:  		case I2C_SMBUS_BLOCK_PROC_CALL: +			if (msg[1].buf[0] > I2C_SMBUS_BLOCK_MAX) { +				dev_err(&adapter->dev, +					"Invalid block size returned: %d\n", +					msg[1].buf[0]); +				status = -EPROTO; +				goto cleanup; +			}  			for (i = 0; i < msg[1].buf[0] + 1; i++)  				data->block[i] = msg[1].buf[i];  			break; |