diff options
Diffstat (limited to 'drivers/i2c')
44 files changed, 2628 insertions, 657 deletions
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 72c94c60fdd1..bed6ba63c983 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -18,4 +18,3 @@ obj-$(CONFIG_I2C_STUB)		+= i2c-stub.o  obj-$(CONFIG_I2C_SLAVE_EEPROM)	+= i2c-slave-eeprom.o  ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG -CFLAGS_i2c-core-base.o := -Wno-deprecated-declarations diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4f8df2ec87b1..451d4ae50e66 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -116,24 +116,21 @@ config I2C_I801  	    DH89xxCC (PCH)  	    Panther Point (PCH)  	    Lynx Point (PCH) -	    Lynx Point-LP (PCH)  	    Avoton (SOC)  	    Wellsburg (PCH)  	    Coleto Creek (PCH)  	    Wildcat Point (PCH) -	    Wildcat Point-LP (PCH)  	    BayTrail (SOC)  	    Braswell (SOC) -	    Sunrise Point-H (PCH) -	    Sunrise Point-LP (PCH) -	    Kaby Lake-H (PCH) +	    Sunrise Point (PCH) +	    Kaby Lake (PCH)  	    DNV (SOC)  	    Broxton (SOC)  	    Lewisburg (PCH)  	    Gemini Lake (SOC) -	    Cannon Lake-H (PCH) -	    Cannon Lake-LP (PCH) +	    Cannon Lake (PCH)  	    Cedar Fork (PCH) +	    Ice Lake (PCH)  	  This driver can also be built as a module.  If so, the module  	  will be called i2c-i801. @@ -762,6 +759,13 @@ config I2C_OMAP  	  Like OMAP1510/1610/1710/5912 and OMAP242x.  	  For details see http://www.ti.com/omap. +config I2C_OWL +	tristate "Actions Semiconductor Owl I2C Controller" +	depends on ARCH_ACTIONS || COMPILE_TEST +	help +	  Say Y here if you want to use the I2C bus controller on +	  the Actions Semiconductor Owl SoC's. +  config I2C_PASEMI  	tristate "PA Semi SMBus interface"  	depends on PPC_PASEMI && PCI @@ -828,6 +832,19 @@ config I2C_PXA_SLAVE  	  is necessary for systems where the PXA may be a target on the  	  I2C bus. +config I2C_QCOM_GENI +	tristate "Qualcomm Technologies Inc.'s GENI based I2C controller" +	depends on ARCH_QCOM || COMPILE_TEST +	depends on QCOM_GENI_SE +	help +	  This driver supports GENI serial engine based I2C controller in +	  master mode on the Qualcomm Technologies Inc.'s SoCs. If you say +	  yes to this option, support will be included for the built-in I2C +	  interface on the Qualcomm Technologies Inc.'s SoCs. + +	  This driver can also be built as a module.  If so, the module +	  will be called i2c-qcom-geni. +  config I2C_QUP  	tristate "Qualcomm QUP based I2C controller"  	depends on ARCH_QCOM @@ -1330,4 +1347,15 @@ config I2C_ZX2967  	  This driver can also be built as a module. If so, the module will be  	  called i2c-zx2967. +config I2C_FSI +	tristate "FSI I2C driver" +	depends on FSI +	help +	  Driver for FSI bus attached I2C masters. These are I2C masters that +	  are connected to the system over an FSI bus, instead of the more +	  common PCI or MMIO interface. + +	  This driver can also be built as a module. If so, the module will be +	  called as i2c-fsi. +  endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 5a869144a0c5..18b26af82b1c 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_I2C_MXS)		+= i2c-mxs.o  obj-$(CONFIG_I2C_NOMADIK)	+= i2c-nomadik.o  obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o  obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o +obj-$(CONFIG_I2C_OWL)		+= i2c-owl.o  obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o  obj-$(CONFIG_I2C_PCA_PLATFORM)	+= i2c-pca-platform.o  obj-$(CONFIG_I2C_PMCMSP)	+= i2c-pmcmsp.o @@ -83,6 +84,7 @@ obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o  obj-$(CONFIG_I2C_PUV3)		+= i2c-puv3.o  obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o  obj-$(CONFIG_I2C_PXA_PCI)	+= i2c-pxa-pci.o +obj-$(CONFIG_I2C_QCOM_GENI)	+= i2c-qcom-geni.o  obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o  obj-$(CONFIG_I2C_RIIC)		+= i2c-riic.o  obj-$(CONFIG_I2C_RK3X)		+= i2c-rk3x.o @@ -137,5 +139,6 @@ obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o  obj-$(CONFIG_I2C_SIBYTE)	+= i2c-sibyte.o  obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o  obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o +obj-$(CONFIG_I2C_FSI)		+= i2c-fsi.o  ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 95a80a8f81b5..134567f3019f 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -384,6 +384,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,  			if (status)  				return status;  			len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); +			/* fall through */  		case I2C_SMBUS_I2C_BLOCK_DATA:  			for (i = 0; i < len; i++) {  				status = amd_ec_read(smbus, AMD_SMB_DATA + i, diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 60e4d0e939a3..a4f956c6d567 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -111,22 +111,22 @@  #define ASPEED_I2CD_DEV_ADDR_MASK			GENMASK(6, 0)  enum aspeed_i2c_master_state { +	ASPEED_I2C_MASTER_INACTIVE,  	ASPEED_I2C_MASTER_START,  	ASPEED_I2C_MASTER_TX_FIRST,  	ASPEED_I2C_MASTER_TX,  	ASPEED_I2C_MASTER_RX_FIRST,  	ASPEED_I2C_MASTER_RX,  	ASPEED_I2C_MASTER_STOP, -	ASPEED_I2C_MASTER_INACTIVE,  };  enum aspeed_i2c_slave_state { +	ASPEED_I2C_SLAVE_STOP,  	ASPEED_I2C_SLAVE_START,  	ASPEED_I2C_SLAVE_READ_REQUESTED,  	ASPEED_I2C_SLAVE_READ_PROCESSED,  	ASPEED_I2C_SLAVE_WRITE_REQUESTED,  	ASPEED_I2C_SLAVE_WRITE_RECEIVED, -	ASPEED_I2C_SLAVE_STOP,  };  struct aspeed_i2c_bus { @@ -234,7 +234,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)  	bool irq_handled = true;  	u8 value; -	spin_lock(&bus->lock);  	if (!slave) {  		irq_handled = false;  		goto out; @@ -325,7 +324,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)  	writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);  out: -	spin_unlock(&bus->lock);  	return irq_handled;  }  #endif /* CONFIG_I2C_SLAVE */ @@ -389,7 +387,6 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  	u8 recv_byte;  	int ret; -	spin_lock(&bus->lock);  	irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);  	/* Ack all interrupt bits. */  	writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG); @@ -407,7 +404,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  	 */  	ret = aspeed_i2c_is_irq_error(irq_status);  	if (ret < 0) { -		dev_dbg(bus->dev, "received error interrupt: 0x%08x", +		dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",  			irq_status);  		bus->cmd_err = ret;  		bus->master_state = ASPEED_I2C_MASTER_INACTIVE; @@ -416,7 +413,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  	/* We are in an invalid state; reset bus to a known state. */  	if (!bus->msgs) { -		dev_err(bus->dev, "bus in unknown state"); +		dev_err(bus->dev, "bus in unknown state\n");  		bus->cmd_err = -EIO;  		if (bus->master_state != ASPEED_I2C_MASTER_STOP)  			aspeed_i2c_do_stop(bus); @@ -431,7 +428,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  	 */  	if (bus->master_state == ASPEED_I2C_MASTER_START) {  		if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { -			pr_devel("no slave present at %02x", msg->addr); +			pr_devel("no slave present at %02x\n", msg->addr);  			status_ack |= ASPEED_I2CD_INTR_TX_NAK;  			bus->cmd_err = -ENXIO;  			aspeed_i2c_do_stop(bus); @@ -451,11 +448,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  	switch (bus->master_state) {  	case ASPEED_I2C_MASTER_TX:  		if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) { -			dev_dbg(bus->dev, "slave NACKed TX"); +			dev_dbg(bus->dev, "slave NACKed TX\n");  			status_ack |= ASPEED_I2CD_INTR_TX_NAK;  			goto error_and_stop;  		} else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { -			dev_err(bus->dev, "slave failed to ACK TX"); +			dev_err(bus->dev, "slave failed to ACK TX\n");  			goto error_and_stop;  		}  		status_ack |= ASPEED_I2CD_INTR_TX_ACK; @@ -478,7 +475,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  		/* fallthrough intended */  	case ASPEED_I2C_MASTER_RX:  		if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) { -			dev_err(bus->dev, "master failed to RX"); +			dev_err(bus->dev, "master failed to RX\n");  			goto error_and_stop;  		}  		status_ack |= ASPEED_I2CD_INTR_RX_DONE; @@ -509,7 +506,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  		goto out_no_complete;  	case ASPEED_I2C_MASTER_STOP:  		if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) { -			dev_err(bus->dev, "master failed to STOP"); +			dev_err(bus->dev, "master failed to STOP\n");  			bus->cmd_err = -EIO;  			/* Do not STOP as we have already tried. */  		} else { @@ -520,7 +517,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)  		goto out_complete;  	case ASPEED_I2C_MASTER_INACTIVE:  		dev_err(bus->dev, -			"master received interrupt 0x%08x, but is inactive", +			"master received interrupt 0x%08x, but is inactive\n",  			irq_status);  		bus->cmd_err = -EIO;  		/* Do not STOP as we should be inactive. */ @@ -547,22 +544,29 @@ out_no_complete:  		dev_err(bus->dev,  			"irq handled != irq. expected 0x%08x, but was 0x%08x\n",  			irq_status, status_ack); -	spin_unlock(&bus->lock);  	return !!irq_status;  }  static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)  {  	struct aspeed_i2c_bus *bus = dev_id; +	bool ret; + +	spin_lock(&bus->lock);  #if IS_ENABLED(CONFIG_I2C_SLAVE)  	if (aspeed_i2c_slave_irq(bus)) {  		dev_dbg(bus->dev, "irq handled by slave.\n"); -		return IRQ_HANDLED; +		ret = true; +		goto out;  	}  #endif /* CONFIG_I2C_SLAVE */ -	return aspeed_i2c_master_irq(bus) ? IRQ_HANDLED : IRQ_NONE; +	ret = aspeed_i2c_master_irq(bus); + +out: +	spin_unlock(&bus->lock); +	return ret ? IRQ_HANDLED : IRQ_NONE;  }  static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, @@ -851,7 +855,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)  	bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL);  	if (IS_ERR(bus->rst)) {  		dev_err(&pdev->dev, -			"missing or invalid reset controller device tree entry"); +			"missing or invalid reset controller device tree entry\n");  		return PTR_ERR(bus->rst);  	}  	reset_control_deassert(bus->rst); @@ -868,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)  	if (!match)  		bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;  	else -		bus->get_clk_reg_val = match->data; +		bus->get_clk_reg_val = (u32 (*)(u32))match->data;  	/* Initialize the I2C adapter */  	spin_lock_init(&bus->lock); diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 78792b4d6437..826d32049996 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -689,9 +689,9 @@ static int brcmstb_i2c_suspend(struct device *dev)  {  	struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); -	i2c_lock_adapter(&i2c_dev->adapter); +	i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);  	i2c_dev->is_suspended = true; -	i2c_unlock_adapter(&i2c_dev->adapter); +	i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);  	return 0;  } @@ -700,10 +700,10 @@ static int brcmstb_i2c_resume(struct device *dev)  {  	struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); -	i2c_lock_adapter(&i2c_dev->adapter); +	i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);  	brcmstb_i2c_set_bsc_reg_defaults(i2c_dev);  	i2c_dev->is_suspended = false; -	i2c_unlock_adapter(&i2c_dev->adapter); +	i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);  	return 0;  } diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 7379043711df..11caafa0e050 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -718,14 +718,14 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,  	dev = container_of(nb, struct davinci_i2c_dev, freq_transition); -	i2c_lock_adapter(&dev->adapter); +	i2c_lock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER);  	if (val == CPUFREQ_PRECHANGE) {  		davinci_i2c_reset_ctrl(dev, 0);  	} else if (val == CPUFREQ_POSTCHANGE) {  		i2c_davinci_calc_clk_dividers(dev);  		davinci_i2c_reset_ctrl(dev, 1);  	} -	i2c_unlock_adapter(&dev->adapter); +	i2c_unlock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER);  	return 0;  } diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index dbda8c9c8a1c..a2a275cfc1f6 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Intel BayTrail PMIC I2C bus semaphore implementaion   * Copyright (c) 2014, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for - * more details.   */  #include <linux/delay.h>  #include <linux/device.h> diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 48914dfc8ce8..69ec4a791f23 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * Synopsys DesignWare I2C adapter driver.   * @@ -6,20 +7,6 @@   * Copyright (C) 2006 Texas Instruments.   * Copyright (C) 2007 MontaVista Software Inc.   * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - *   */  #include <linux/clk.h>  #include <linux/delay.h> @@ -31,6 +18,7 @@  #include <linux/io.h>  #include <linux/module.h>  #include <linux/pm_runtime.h> +#include <linux/swab.h>  #include "i2c-designware-core.h" @@ -94,6 +82,40 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)  	}  } +/** + * i2c_dw_set_reg_access() - Set register access flags + * @dev: device private data + * + * Autodetects needed register access mode and sets access flags accordingly. + * This must be called before doing any other register access. + */ +int i2c_dw_set_reg_access(struct dw_i2c_dev *dev) +{ +	u32 reg; +	int ret; + +	ret = i2c_dw_acquire_lock(dev); +	if (ret) +		return ret; + +	reg = dw_readl(dev, DW_IC_COMP_TYPE); +	i2c_dw_release_lock(dev); + +	if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) { +		/* Configure register endianess access */ +		dev->flags |= ACCESS_SWAP; +	} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { +		/* Configure register access mode 16bit */ +		dev->flags |= ACCESS_16BIT; +	} else if (reg != DW_IC_COMP_TYPE_VALUE) { +		dev_err(dev->dev, +			"Unknown Synopsys component type: 0x%08x\n", reg); +		return -ENODEV; +	} + +	return 0; +} +  u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)  {  	/* @@ -149,6 +171,47 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)  	return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;  } +int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) +{ +	u32 reg; +	int ret; + +	ret = i2c_dw_acquire_lock(dev); +	if (ret) +		return ret; + +	/* Configure SDA Hold Time if required */ +	reg = dw_readl(dev, DW_IC_COMP_VERSION); +	if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { +		if (!dev->sda_hold_time) { +			/* Keep previous hold time setting if no one set it */ +			dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); +		} + +		/* +		 * Workaround for avoiding TX arbitration lost in case I2C +		 * slave pulls SDA down "too quickly" after falling egde of +		 * SCL by enabling non-zero SDA RX hold. Specification says it +		 * extends incoming SDA low to high transition while SCL is +		 * high but it apprears to help also above issue. +		 */ +		if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) +			dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; + +		dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n", +			dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK, +			dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT); +	} else if (dev->sda_hold_time) { +		dev_warn(dev->dev, +			"Hardware too old to adjust SDA hold time.\n"); +		dev->sda_hold_time = 0; +	} + +	i2c_dw_release_lock(dev); + +	return 0; +} +  void __i2c_dw_disable(struct dw_i2c_dev *dev)  {  	int timeout = 100; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index d690e648bc01..e367b1af4ab2 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */  /*   * Synopsys DesignWare I2C adapter driver.   * @@ -6,20 +7,6 @@   * Copyright (C) 2006 Texas Instruments.   * Copyright (C) 2007 MontaVista Software Inc.   * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - *   */  #include <linux/i2c.h> @@ -212,7 +199,8 @@   * @tx_fifo_depth: depth of the hardware tx fifo   * @rx_fifo_depth: depth of the hardware rx fifo   * @rx_outstanding: current master-rx elements in tx fifo - * @clk_freq: bus clock frequency + * @timings: bus clock frequency, SDA hold and other timings + * @sda_hold_time: SDA hold value   * @ss_hcnt: standard speed HCNT value   * @ss_lcnt: standard speed LCNT value   * @fs_hcnt: fast speed HCNT value @@ -264,10 +252,8 @@ struct dw_i2c_dev {  	unsigned int		tx_fifo_depth;  	unsigned int		rx_fifo_depth;  	int			rx_outstanding; -	u32			clk_freq; +	struct i2c_timings	timings;  	u32			sda_hold_time; -	u32			sda_falling_time; -	u32			scl_falling_time;  	u16			ss_hcnt;  	u16			ss_lcnt;  	u16			fs_hcnt; @@ -295,8 +281,10 @@ struct dw_i2c_dev {  u32 dw_readl(struct dw_i2c_dev *dev, int offset);  void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); +int i2c_dw_set_reg_access(struct dw_i2c_dev *dev);  u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);  u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); +int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);  unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);  int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);  int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 27436a937492..e18442b9973a 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * Synopsys DesignWare I2C adapter driver (master only).   * @@ -6,20 +7,6 @@   * Copyright (C) 2006 Texas Instruments.   * Copyright (C) 2007 MontaVista Software Inc.   * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - *   */  #include <linux/delay.h>  #include <linux/err.h> @@ -45,90 +32,79 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)  	dw_writel(dev, dev->master_cfg, DW_IC_CON);  } -/** - * i2c_dw_init() - Initialize the designware I2C master hardware - * @dev: device private data - * - * This functions configures and enables the I2C master. - * This function is called during I2C init function, and in case of timeout at - * run time. - */ -static int i2c_dw_init_master(struct dw_i2c_dev *dev) +static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)  { -	u32 hcnt, lcnt; -	u32 reg, comp_param1; +	u32 ic_clk = i2c_dw_clk_rate(dev); +	const char *mode_str, *fp_str = ""; +	u32 comp_param1;  	u32 sda_falling_time, scl_falling_time; +	struct i2c_timings *t = &dev->timings;  	int ret;  	ret = i2c_dw_acquire_lock(dev);  	if (ret)  		return ret; - -	reg = dw_readl(dev, DW_IC_COMP_TYPE); -	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { -		/* Configure register endianess access */ -		dev->flags |= ACCESS_SWAP; -	} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { -		/* Configure register access mode 16bit */ -		dev->flags |= ACCESS_16BIT; -	} else if (reg != DW_IC_COMP_TYPE_VALUE) { -		dev_err(dev->dev, -			"Unknown Synopsys component type: 0x%08x\n", reg); -		i2c_dw_release_lock(dev); -		return -ENODEV; -	} -  	comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); +	i2c_dw_release_lock(dev); -	/* Disable the adapter */ -	__i2c_dw_disable(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 */ +	/* Set standard and fast speed dividers for high/low periods */ +	sda_falling_time = t->sda_fall_ns ?: 300; /* ns */ +	scl_falling_time = t->scl_fall_ns ?: 300; /* ns */ -	/* Set SCL timing parameters for standard-mode */ -	if (dev->ss_hcnt && dev->ss_lcnt) { -		hcnt = dev->ss_hcnt; -		lcnt = dev->ss_lcnt; -	} else { -		hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), +	/* Calculate SCL timing parameters for standard mode if not set */ +	if (!dev->ss_hcnt || !dev->ss_lcnt) { +		dev->ss_hcnt = +			i2c_dw_scl_hcnt(ic_clk,  					4000,	/* tHD;STA = tHIGH = 4.0 us */  					sda_falling_time,  					0,	/* 0: DW default, 1: Ideal */  					0);	/* No offset */ -		lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), +		dev->ss_lcnt = +			i2c_dw_scl_lcnt(ic_clk,  					4700,	/* tLOW = 4.7 us */  					scl_falling_time,  					0);	/* No offset */  	} -	dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); -	dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); -	dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - -	/* Set SCL timing parameters for fast-mode or fast-mode plus */ -	if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { -		hcnt = dev->fp_hcnt; -		lcnt = dev->fp_lcnt; -	} else if (dev->fs_hcnt && dev->fs_lcnt) { -		hcnt = dev->fs_hcnt; -		lcnt = dev->fs_lcnt; -	} else { -		hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), +	dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n", +		dev->ss_hcnt, dev->ss_lcnt); + +	/* +	 * Set SCL timing parameters for fast mode or fast mode plus. Only +	 * difference is the timing parameter values since the registers are +	 * the same. +	 */ +	if (t->bus_freq_hz == 1000000) { +		/* +		 * Check are fast mode plus parameters available and use +		 * fast mode if not. +		 */ +		if (dev->fp_hcnt && dev->fp_lcnt) { +			dev->fs_hcnt = dev->fp_hcnt; +			dev->fs_lcnt = dev->fp_lcnt; +			fp_str = " Plus"; +		} +	} +	/* +	 * Calculate SCL timing parameters for fast mode if not set. They are +	 * needed also in high speed mode. +	 */ +	if (!dev->fs_hcnt || !dev->fs_lcnt) { +		dev->fs_hcnt = +			i2c_dw_scl_hcnt(ic_clk,  					600,	/* tHD;STA = tHIGH = 0.6 us */  					sda_falling_time,  					0,	/* 0: DW default, 1: Ideal */  					0);	/* No offset */ -		lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), +		dev->fs_lcnt = +			i2c_dw_scl_lcnt(ic_clk,  					1300,	/* tLOW = 1.3 us */  					scl_falling_time,  					0);	/* No offset */  	} -	dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); -	dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); -	dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); +	dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n", +		fp_str, dev->fs_hcnt, dev->fs_lcnt); +	/* Check is high speed possible and fall back to fast mode if not */  	if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==  		DW_IC_CON_SPEED_HIGH) {  		if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) @@ -136,37 +112,70 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)  			dev_err(dev->dev, "High Speed not supported!\n");  			dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;  			dev->master_cfg |= DW_IC_CON_SPEED_FAST; +			dev->hs_hcnt = 0; +			dev->hs_lcnt = 0;  		} else if (dev->hs_hcnt && dev->hs_lcnt) { -			hcnt = dev->hs_hcnt; -			lcnt = dev->hs_lcnt; -			dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); -			dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); -			dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", -				hcnt, lcnt); +			dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n", +				dev->hs_hcnt, dev->hs_lcnt);  		}  	} -	/* Configure SDA Hold Time if required */ -	reg = dw_readl(dev, DW_IC_COMP_VERSION); -	if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { -		if (!dev->sda_hold_time) { -			/* Keep previous hold time setting if no one set it */ -			dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); -		} -		/* -		 * Workaround for avoiding TX arbitration lost in case I2C -		 * slave pulls SDA down "too quickly" after falling egde of -		 * SCL by enabling non-zero SDA RX hold. Specification says it -		 * extends incoming SDA low to high transition while SCL is -		 * high but it apprears to help also above issue. -		 */ -		if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) -			dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; -		dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); -	} else if (dev->sda_hold_time) { -		dev_warn(dev->dev, -			"Hardware too old to adjust SDA hold time.\n"); +	ret = i2c_dw_set_sda_hold(dev); +	if (ret) +		goto out; + +	switch (dev->master_cfg & DW_IC_CON_SPEED_MASK) { +	case DW_IC_CON_SPEED_STD: +		mode_str = "Standard Mode"; +		break; +	case DW_IC_CON_SPEED_HIGH: +		mode_str = "High Speed Mode"; +		break; +	default: +		mode_str = "Fast Mode";  	} +	dev_dbg(dev->dev, "Bus speed: %s%s\n", mode_str, fp_str); + +out: +	return ret; +} + +/** + * i2c_dw_init() - Initialize the designware I2C master hardware + * @dev: device private data + * + * This functions configures and enables the I2C master. + * This function is called during I2C init function, and in case of timeout at + * run time. + */ +static int i2c_dw_init_master(struct dw_i2c_dev *dev) +{ +	int ret; + +	ret = i2c_dw_acquire_lock(dev); +	if (ret) +		return ret; + +	/* Disable the adapter */ +	__i2c_dw_disable(dev); + +	/* Write standard speed timing parameters */ +	dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT); +	dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT); + +	/* Write fast mode/fast mode plus timing parameters */ +	dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT); +	dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT); + +	/* Write high speed timing parameters if supported */ +	if (dev->hs_hcnt && dev->hs_lcnt) { +		dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT); +		dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT); +	} + +	/* Write SDA hold time if supported */ +	if (dev->sda_hold_time) +		dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);  	i2c_dw_configure_fifo_master(dev);  	i2c_dw_release_lock(dev); @@ -253,13 +262,6 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)  			break;  		} -		if (msgs[dev->msg_write_idx].len == 0) { -			dev_err(dev->dev, -				"%s: invalid message length\n", __func__); -			dev->msg_err = -EINVAL; -			break; -		} -  		if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {  			/* new i2c_msg */  			buf = msgs[dev->msg_write_idx].buf; @@ -502,6 +504,10 @@ static const struct i2c_algorithm i2c_dw_algo = {  	.functionality = i2c_dw_func,  }; +static const struct i2c_adapter_quirks i2c_dw_quirks = { +	.flags = I2C_AQ_NO_ZERO_LEN, +}; +  static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)  {  	u32 stat; @@ -681,6 +687,14 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)  	dev->disable = i2c_dw_disable;  	dev->disable_int = i2c_dw_disable_int; +	ret = i2c_dw_set_reg_access(dev); +	if (ret) +		return ret; + +	ret = i2c_dw_set_timings_master(dev); +	if (ret) +		return ret; +  	ret = dev->init(dev);  	if (ret)  		return ret; @@ -689,6 +703,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)  		 "Synopsys DesignWare I2C adapter");  	adap->retries = 3;  	adap->algo = &i2c_dw_algo; +	adap->quirks = &i2c_dw_quirks;  	adap->dev.parent = dev->dev;  	i2c_set_adapdata(adap, dev); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 86e1bd0b82e9..d50f80487214 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * Synopsys DesignWare I2C adapter driver (master only).   * @@ -7,22 +8,7 @@   * Copyright (C) 2007 MontaVista Software Inc.   * Copyright (C) 2009 Provigent Ltd.   * Copyright (C) 2011, 2015, 2016 Intel Corporation. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - *   */ -  #include <linux/acpi.h>  #include <linux/delay.h>  #include <linux/err.h> @@ -105,6 +91,7 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)  	case 0x0817:  		c->bus_cfg &= ~DW_IC_CON_SPEED_MASK;  		c->bus_cfg |= DW_IC_CON_SPEED_STD; +		/* fall through */  	case 0x0818:  	case 0x0819:  		c->bus_num = pdev->device - 0x817 + 3; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 5660daf6c92e..1a8d2da5b000 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * Synopsys DesignWare I2C adapter driver.   * @@ -6,20 +7,6 @@   * Copyright (C) 2006 Texas Instruments.   * Copyright (C) 2007 MontaVista Software Inc.   * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - *   */  #include <linux/acpi.h>  #include <linux/clk-provider.h> @@ -96,6 +83,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],  static int dw_i2c_acpi_configure(struct platform_device *pdev)  {  	struct dw_i2c_dev *dev = platform_get_drvdata(pdev); +	struct i2c_timings *t = &dev->timings;  	u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;  	acpi_handle handle = ACPI_HANDLE(&pdev->dev);  	const struct acpi_device_id *id; @@ -115,7 +103,7 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)  	dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht);  	dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht); -	switch (dev->clk_freq) { +	switch (t->bus_freq_hz) {  	case 100000:  		dev->sda_hold_time = ss_ht;  		break; @@ -175,6 +163,8 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)  static void i2c_dw_configure_master(struct dw_i2c_dev *dev)  { +	struct i2c_timings *t = &dev->timings; +  	dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;  	dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | @@ -182,7 +172,7 @@ static void i2c_dw_configure_master(struct dw_i2c_dev *dev)  	dev->mode = DW_IC_MASTER; -	switch (dev->clk_freq) { +	switch (t->bus_freq_hz) {  	case 100000:  		dev->master_cfg |= DW_IC_CON_SPEED_STD;  		break; @@ -240,7 +230,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct i2c_adapter *adap;  	struct dw_i2c_dev *dev; -	u32 acpi_speed, ht = 0; +	struct i2c_timings *t; +	u32 acpi_speed;  	struct resource *mem;  	int i, irq, ret;  	static const int supported_speeds[] = { @@ -272,18 +263,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  		reset_control_deassert(dev->rst);  	} -	if (pdata) { -		dev->clk_freq = pdata->i2c_scl_freq; -	} else { -		device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", -					 &ht); -		device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns", -					 &dev->sda_falling_time); -		device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns", -					 &dev->scl_falling_time); -		device_property_read_u32(&pdev->dev, "clock-frequency", -					 &dev->clk_freq); -	} +	t = &dev->timings; +	if (pdata) +		t->bus_freq_hz = pdata->i2c_scl_freq; +	else +		i2c_parse_fw_timings(&pdev->dev, t, false);  	acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);  	/* @@ -300,12 +284,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  	 * Find bus speed from the "clock-frequency" device property, ACPI  	 * or by using fast mode if neither is set.  	 */ -	if (acpi_speed && dev->clk_freq) -		dev->clk_freq = min(dev->clk_freq, acpi_speed); -	else if (acpi_speed || dev->clk_freq) -		dev->clk_freq = max(dev->clk_freq, acpi_speed); +	if (acpi_speed && t->bus_freq_hz) +		t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed); +	else if (acpi_speed || t->bus_freq_hz) +		t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);  	else -		dev->clk_freq = 400000; +		t->bus_freq_hz = 400000;  	if (has_acpi_companion(&pdev->dev))  		dw_i2c_acpi_configure(pdev); @@ -314,11 +298,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  	 * Only standard mode at 100kHz, fast mode at 400kHz,  	 * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.  	 */ -	if (dev->clk_freq != 100000 && dev->clk_freq != 400000 -	    && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { +	if (t->bus_freq_hz != 100000 && t->bus_freq_hz != 400000 && +	    t->bus_freq_hz != 1000000 && t->bus_freq_hz != 3400000) {  		dev_err(&pdev->dev,  			"%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n", -			dev->clk_freq); +			t->bus_freq_hz);  		ret = -EINVAL;  		goto exit_reset;  	} @@ -334,12 +318,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)  	dev->clk = devm_clk_get(&pdev->dev, NULL);  	if (!i2c_dw_prepare_clk(dev, true)) { +		u64 clk_khz; +  		dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; +		clk_khz = dev->get_clk_rate_khz(dev); -		if (!dev->sda_hold_time && ht) -			dev->sda_hold_time = div_u64( -				(u64)dev->get_clk_rate_khz(dev) * ht + 500000, -				1000000); +		if (!dev->sda_hold_time && t->sda_hold_ns) +			dev->sda_hold_time = +				div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000);  	}  	dw_i2c_set_fifo_size(dev, pdev->id); diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index 8ce2cd368477..e7f9305b2dd9 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Synopsys DesignWare I2C adapter driver (slave only).   *   * Based on the Synopsys DesignWare I2C adapter driver (master).   *   * Copyright (C) 2016 Synopsys Inc. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - *   */  #include <linux/delay.h>  #include <linux/err.h> @@ -51,53 +38,18 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)   */  static int i2c_dw_init_slave(struct dw_i2c_dev *dev)  { -	u32 reg, comp_param1;  	int ret;  	ret = i2c_dw_acquire_lock(dev);  	if (ret)  		return ret; -	reg = dw_readl(dev, DW_IC_COMP_TYPE); -	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { -		/* Configure register endianness access. */ -		dev->flags |= ACCESS_SWAP; -	} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { -		/* Configure register access mode 16bit. */ -		dev->flags |= ACCESS_16BIT; -	} else if (reg != DW_IC_COMP_TYPE_VALUE) { -		dev_err(dev->dev, -			"Unknown Synopsys component type: 0x%08x\n", reg); -		i2c_dw_release_lock(dev); -		return -ENODEV; -	} - -	comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); -  	/* Disable the adapter. */  	__i2c_dw_disable(dev); -	/* Configure SDA Hold Time if required. */ -	reg = dw_readl(dev, DW_IC_COMP_VERSION); -	if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { -		if (!dev->sda_hold_time) { -			/* Keep previous hold time setting if no one set it. */ -			dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); -		} -		/* -		 * Workaround for avoiding TX arbitration lost in case I2C -		 * slave pulls SDA down "too quickly" after falling egde of -		 * SCL by enabling non-zero SDA RX hold. Specification says it -		 * extends incoming SDA low to high transition while SCL is -		 * high but it apprears to help also above issue. -		 */ -		if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) -			dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; +	/* Write SDA hold time if supported */ +	if (dev->sda_hold_time)  		dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); -	} else { -		dev_warn(dev->dev, -			 "Hardware too old to adjust SDA hold time.\n"); -	}  	i2c_dw_configure_fifo_slave(dev);  	i2c_dw_release_lock(dev); @@ -299,6 +251,14 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)  	dev->disable = i2c_dw_disable;  	dev->disable_int = i2c_dw_disable_int; +	ret = i2c_dw_set_reg_access(dev); +	if (ret) +		return ret; + +	ret = i2c_dw_set_sda_hold(dev); +	if (ret) +		return ret; +  	ret = dev->init(dev);  	if (ret)  		return ret; diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index ba9b6ea48a31..35b302d983e0 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * I2C driver for the Renesas EMEV2 SoC   *   * Copyright (C) 2015 Wolfram Sang <[email protected]>   * Copyright 2013 Codethink Ltd.   * Copyright 2010-2015 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation.   */  #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index de82ad8ff534..c1ce2299a76e 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -176,7 +176,10 @@  #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100)) -#define HSI2C_EXYNOS7	BIT(0) +enum i2c_type_exynos { +	I2C_TYPE_EXYNOS5, +	I2C_TYPE_EXYNOS7, +};  struct exynos5_i2c {  	struct i2c_adapter	adap; @@ -212,27 +215,30 @@ struct exynos5_i2c {  /**   * struct exynos_hsi2c_variant - platform specific HSI2C driver data   * @fifo_depth: the fifo depth supported by the HSI2C module + * @hw: the hardware variant of Exynos I2C controller   *   * Specifies platform specific configuration of HSI2C module.   * Note: A structure for driver specific platform data is used for future   * expansion of its usage.   */  struct exynos_hsi2c_variant { -	unsigned int	fifo_depth; -	unsigned int	hw; +	unsigned int		fifo_depth; +	enum i2c_type_exynos	hw;  };  static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {  	.fifo_depth	= 64, +	.hw		= I2C_TYPE_EXYNOS5,  };  static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {  	.fifo_depth	= 16, +	.hw		= I2C_TYPE_EXYNOS5,  };  static const struct exynos_hsi2c_variant exynos7_hsi2c_data = {  	.fifo_depth	= 16, -	.hw		= HSI2C_EXYNOS7, +	.hw		= I2C_TYPE_EXYNOS7,  };  static const struct of_device_id exynos5_i2c_match[] = { @@ -300,7 +306,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)  	 */  	t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;  	temp = clkin / op_clk - 8 - t_ftl_cycle; -	if (i2c->variant->hw != HSI2C_EXYNOS7) +	if (i2c->variant->hw != I2C_TYPE_EXYNOS7)  		temp -= t_ftl_cycle;  	div = temp / 512;  	clk_cycle = temp / (div + 1) - 2; @@ -424,7 +430,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)  	writel(int_status, i2c->regs + HSI2C_INT_STATUS);  	/* handle interrupt related to the transfer status */ -	if (i2c->variant->hw == HSI2C_EXYNOS7) { +	if (i2c->variant->hw == I2C_TYPE_EXYNOS7) {  		if (int_status & HSI2C_INT_TRANS_DONE) {  			i2c->trans_done = 1;  			i2c->state = 0; @@ -571,7 +577,7 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c)  {  	unsigned long timeout; -	if (i2c->variant->hw != HSI2C_EXYNOS7) +	if (i2c->variant->hw != I2C_TYPE_EXYNOS7)  		return;  	/* @@ -612,7 +618,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)  	unsigned long flags;  	unsigned short trig_lvl; -	if (i2c->variant->hw == HSI2C_EXYNOS7) +	if (i2c->variant->hw == I2C_TYPE_EXYNOS7)  		int_en |= HSI2C_INT_I2C_TRANS;  	else  		int_en |= HSI2C_INT_I2C; diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c new file mode 100644 index 000000000000..1e2be2219a60 --- /dev/null +++ b/drivers/i2c/busses/i2c-fsi.c @@ -0,0 +1,752 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * FSI-attached I2C master algorithm + * + * Copyright 2018 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fsi.h> +#include <linux/i2c.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/slab.h> + +#define FSI_ENGID_I2C		0x7 + +#define I2C_DEFAULT_CLK_DIV	6 + +/* i2c registers */ +#define I2C_FSI_FIFO		0x00 +#define I2C_FSI_CMD		0x04 +#define I2C_FSI_MODE		0x08 +#define I2C_FSI_WATER_MARK	0x0C +#define I2C_FSI_INT_MASK	0x10 +#define I2C_FSI_INT_COND	0x14 +#define I2C_FSI_OR_INT_MASK	0x14 +#define I2C_FSI_INTS		0x18 +#define I2C_FSI_AND_INT_MASK	0x18 +#define I2C_FSI_STAT		0x1C +#define I2C_FSI_RESET_I2C	0x1C +#define I2C_FSI_ESTAT		0x20 +#define I2C_FSI_RESET_ERR	0x20 +#define I2C_FSI_RESID_LEN	0x24 +#define I2C_FSI_SET_SCL		0x24 +#define I2C_FSI_PORT_BUSY	0x28 +#define I2C_FSI_RESET_SCL	0x2C +#define I2C_FSI_SET_SDA		0x30 +#define I2C_FSI_RESET_SDA	0x34 + +/* cmd register */ +#define I2C_CMD_WITH_START	BIT(31) +#define I2C_CMD_WITH_ADDR	BIT(30) +#define I2C_CMD_RD_CONT		BIT(29) +#define I2C_CMD_WITH_STOP	BIT(28) +#define I2C_CMD_FORCELAUNCH	BIT(27) +#define I2C_CMD_ADDR		GENMASK(23, 17) +#define I2C_CMD_READ		BIT(16) +#define I2C_CMD_LEN		GENMASK(15, 0) + +/* mode register */ +#define I2C_MODE_CLKDIV		GENMASK(31, 16) +#define I2C_MODE_PORT		GENMASK(15, 10) +#define I2C_MODE_ENHANCED	BIT(3) +#define I2C_MODE_DIAG		BIT(2) +#define I2C_MODE_PACE_ALLOW	BIT(1) +#define I2C_MODE_WRAP		BIT(0) + +/* watermark register */ +#define I2C_WATERMARK_HI	GENMASK(15, 12) +#define I2C_WATERMARK_LO	GENMASK(7, 4) + +#define I2C_FIFO_HI_LVL		4 +#define I2C_FIFO_LO_LVL		4 + +/* interrupt register */ +#define I2C_INT_INV_CMD		BIT(15) +#define I2C_INT_PARITY		BIT(14) +#define I2C_INT_BE_OVERRUN	BIT(13) +#define I2C_INT_BE_ACCESS	BIT(12) +#define I2C_INT_LOST_ARB	BIT(11) +#define I2C_INT_NACK		BIT(10) +#define I2C_INT_DAT_REQ		BIT(9) +#define I2C_INT_CMD_COMP	BIT(8) +#define I2C_INT_STOP_ERR	BIT(7) +#define I2C_INT_BUSY		BIT(6) +#define I2C_INT_IDLE		BIT(5) + +/* status register */ +#define I2C_STAT_INV_CMD	BIT(31) +#define I2C_STAT_PARITY		BIT(30) +#define I2C_STAT_BE_OVERRUN	BIT(29) +#define I2C_STAT_BE_ACCESS	BIT(28) +#define I2C_STAT_LOST_ARB	BIT(27) +#define I2C_STAT_NACK		BIT(26) +#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_ANY_INT	BIT(15) +#define I2C_STAT_SCL_IN		BIT(11) +#define I2C_STAT_SDA_IN		BIT(10) +#define I2C_STAT_PORT_BUSY	BIT(9) +#define I2C_STAT_SELF_BUSY	BIT(8) +#define I2C_STAT_FIFO_COUNT	GENMASK(7, 0) + +#define I2C_STAT_ERR		(I2C_STAT_INV_CMD |			\ +				 I2C_STAT_PARITY |			\ +				 I2C_STAT_BE_OVERRUN |			\ +				 I2C_STAT_BE_ACCESS |			\ +				 I2C_STAT_LOST_ARB |			\ +				 I2C_STAT_NACK |			\ +				 I2C_STAT_STOP_ERR) +#define I2C_STAT_ANY_RESP	(I2C_STAT_ERR |				\ +				 I2C_STAT_DAT_REQ |			\ +				 I2C_STAT_CMD_COMP) + +/* extended status register */ +#define I2C_ESTAT_FIFO_SZ	GENMASK(31, 24) +#define I2C_ESTAT_SCL_IN_SY	BIT(15) +#define I2C_ESTAT_SDA_IN_SY	BIT(14) +#define I2C_ESTAT_S_SCL		BIT(13) +#define I2C_ESTAT_S_SDA		BIT(12) +#define I2C_ESTAT_M_SCL		BIT(11) +#define I2C_ESTAT_M_SDA		BIT(10) +#define I2C_ESTAT_HI_WATER	BIT(9) +#define I2C_ESTAT_LO_WATER	BIT(8) +#define I2C_ESTAT_PORT_BUSY	BIT(7) +#define I2C_ESTAT_SELF_BUSY	BIT(6) +#define I2C_ESTAT_VERSION	GENMASK(4, 0) + +/* port busy register */ +#define I2C_PORT_BUSY_RESET	BIT(31) + +/* wait for command complete or data request */ +#define I2C_CMD_SLEEP_MAX_US	500 +#define I2C_CMD_SLEEP_MIN_US	50 + +/* wait after reset; choose time from legacy driver */ +#define I2C_RESET_SLEEP_MAX_US	2000 +#define I2C_RESET_SLEEP_MIN_US	1000 + +/* choose timeout length from legacy driver; it's well tested */ +#define I2C_ABORT_TIMEOUT	msecs_to_jiffies(100) + +struct fsi_i2c_master { +	struct fsi_device	*fsi; +	u8			fifo_size; +	struct list_head	ports; +	struct mutex		lock; +}; + +struct fsi_i2c_port { +	struct list_head	list; +	struct i2c_adapter	adapter; +	struct fsi_i2c_master	*master; +	u16			port; +	u16			xfrd; +}; + +static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg, +			    u32 *data) +{ +	int rc; +	__be32 data_be; + +	rc = fsi_device_read(fsi, reg, &data_be, sizeof(data_be)); +	if (rc) +		return rc; + +	*data = be32_to_cpu(data_be); + +	return 0; +} + +static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg, +			     u32 *data) +{ +	__be32 data_be = cpu_to_be32p(data); + +	return fsi_device_write(fsi, reg, &data_be, sizeof(data_be)); +} + +static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) +{ +	int rc; +	u32 mode = I2C_MODE_ENHANCED, extended_status, watermark; +	u32 interrupt = 0; + +	/* since we use polling, disable interrupts */ +	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt); +	if (rc) +		return rc; + +	mode |= FIELD_PREP(I2C_MODE_CLKDIV, I2C_DEFAULT_CLK_DIV); +	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +	if (rc) +		return rc; + +	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status); +	if (rc) +		return rc; + +	i2c->fifo_size = FIELD_GET(I2C_ESTAT_FIFO_SZ, extended_status); +	watermark = FIELD_PREP(I2C_WATERMARK_HI, +			       i2c->fifo_size - I2C_FIFO_HI_LVL); +	watermark |= FIELD_PREP(I2C_WATERMARK_LO, I2C_FIFO_LO_LVL); + +	return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark); +} + +static int fsi_i2c_set_port(struct fsi_i2c_port *port) +{ +	int rc; +	struct fsi_device *fsi = port->master->fsi; +	u32 mode, dummy = 0; + +	rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode); +	if (rc) +		return rc; + +	if (FIELD_GET(I2C_MODE_PORT, mode) == port->port) +		return 0; + +	mode = (mode & ~I2C_MODE_PORT) | FIELD_PREP(I2C_MODE_PORT, port->port); +	rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode); +	if (rc) +		return rc; + +	/* reset engine when port is changed */ +	return fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy); +} + +static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg, +			 bool stop) +{ +	struct fsi_i2c_master *i2c = port->master; +	u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR; + +	port->xfrd = 0; + +	if (msg->flags & I2C_M_RD) +		cmd |= I2C_CMD_READ; + +	if (stop || msg->flags & I2C_M_STOP) +		cmd |= I2C_CMD_WITH_STOP; + +	cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr); +	cmd |= FIELD_PREP(I2C_CMD_LEN, msg->len); + +	return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd); +} + +static int fsi_i2c_get_op_bytes(int op_bytes) +{ +	/* fsi is limited to max 4 byte aligned ops */ +	if (op_bytes > 4) +		return 4; +	else if (op_bytes == 3) +		return 2; +	return op_bytes; +} + +static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, +			      u8 fifo_count) +{ +	int write; +	int rc; +	struct fsi_i2c_master *i2c = port->master; +	int bytes_to_write = i2c->fifo_size - fifo_count; +	int bytes_remaining = msg->len - port->xfrd; + +	bytes_to_write = min(bytes_to_write, bytes_remaining); + +	while (bytes_to_write) { +		write = fsi_i2c_get_op_bytes(bytes_to_write); + +		rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO, +				      &msg->buf[port->xfrd], write); +		if (rc) +			return rc; + +		port->xfrd += write; +		bytes_to_write -= write; +	} + +	return 0; +} + +static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, +			     u8 fifo_count) +{ +	int read; +	int rc; +	struct fsi_i2c_master *i2c = port->master; +	int bytes_to_read; +	int xfr_remaining = msg->len - port->xfrd; +	u32 dummy; + +	bytes_to_read = min_t(int, fifo_count, xfr_remaining); + +	while (bytes_to_read) { +		read = fsi_i2c_get_op_bytes(bytes_to_read); + +		if (xfr_remaining) { +			rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, +					     &msg->buf[port->xfrd], read); +			if (rc) +				return rc; + +			port->xfrd += read; +			xfr_remaining -= read; +		} else { +			/* no more buffer but data in fifo, need to clear it */ +			rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy, +					     read); +			if (rc) +				return rc; +		} + +		bytes_to_read -= read; +	} + +	return 0; +} + +static int fsi_i2c_get_scl(struct i2c_adapter *adap) +{ +	u32 stat = 0; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *i2c = port->master; + +	fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + +	return !!(stat & I2C_STAT_SCL_IN); +} + +static void fsi_i2c_set_scl(struct i2c_adapter *adap, int val) +{ +	u32 dummy = 0; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *i2c = port->master; + +	if (val) +		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); +	else +		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); +} + +static int fsi_i2c_get_sda(struct i2c_adapter *adap) +{ +	u32 stat = 0; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *i2c = port->master; + +	fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + +	return !!(stat & I2C_STAT_SDA_IN); +} + +static void fsi_i2c_set_sda(struct i2c_adapter *adap, int val) +{ +	u32 dummy = 0; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *i2c = port->master; + +	if (val) +		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); +	else +		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); +} + +static void fsi_i2c_prepare_recovery(struct i2c_adapter *adap) +{ +	int rc; +	u32 mode; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *i2c = port->master; + +	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); +	if (rc) +		return; + +	mode |= I2C_MODE_DIAG; +	fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +} + +static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ +	int rc; +	u32 mode; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *i2c = port->master; + +	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); +	if (rc) +		return; + +	mode &= ~I2C_MODE_DIAG; +	fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +} + +static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c, +			     struct fsi_i2c_port *port) +{ +	int rc; +	u32 stat, dummy = 0; + +	/* force bus reset, ignore errors */ +	i2c_recover_bus(&port->adapter); + +	/* reset errors */ +	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); +	if (rc) +		return rc; + +	/* wait for command complete */ +	usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US); + +	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); +	if (rc) +		return rc; + +	if (stat & I2C_STAT_CMD_COMP) +		return 0; + +	/* failed to get command complete; reset engine again */ +	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); +	if (rc) +		return rc; + +	/* re-init engine again */ +	return fsi_i2c_dev_init(i2c); +} + +static int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port) +{ +	int rc; +	u32 mode, dummy = 0; + +	/* reset engine */ +	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); +	if (rc) +		return rc; + +	/* re-init engine */ +	rc = fsi_i2c_dev_init(i2c); +	if (rc) +		return rc; + +	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); +	if (rc) +		return rc; + +	/* set port; default after reset is 0 */ +	if (port) { +		mode &= ~I2C_MODE_PORT; +		mode |= FIELD_PREP(I2C_MODE_PORT, port); +		rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +		if (rc) +			return rc; +	} + +	/* reset busy register; hw workaround */ +	dummy = I2C_PORT_BUSY_RESET; +	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_PORT_BUSY, &dummy); +	if (rc) +		return rc; + +	return 0; +} + +static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) +{ +	int rc; +	unsigned long start; +	u32 cmd = I2C_CMD_WITH_STOP; +	u32 stat; +	struct fsi_i2c_master *i2c = port->master; +	struct fsi_device *fsi = i2c->fsi; + +	rc = fsi_i2c_reset_engine(i2c, port->port); +	if (rc) +		return rc; + +	rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &stat); +	if (rc) +		return rc; + +	/* if sda is low, peform full bus reset */ +	if (!(stat & I2C_STAT_SDA_IN)) { +		rc = fsi_i2c_reset_bus(i2c, port); +		if (rc) +			return rc; +	} + +	/* skip final stop command for these errors */ +	if (status & (I2C_STAT_PARITY | I2C_STAT_LOST_ARB | I2C_STAT_STOP_ERR)) +		return 0; + +	/* write stop command */ +	rc = fsi_i2c_write_reg(fsi, I2C_FSI_CMD, &cmd); +	if (rc) +		return rc; + +	/* wait until we see command complete in the master */ +	start = jiffies; + +	do { +		rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &status); +		if (rc) +			return rc; + +		if (status & I2C_STAT_CMD_COMP) +			return 0; + +		usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US); +	} while (time_after(start + I2C_ABORT_TIMEOUT, jiffies)); + +	return -ETIMEDOUT; +} + +static int fsi_i2c_handle_status(struct fsi_i2c_port *port, +				 struct i2c_msg *msg, u32 status) +{ +	int rc; +	u8 fifo_count; + +	if (status & I2C_STAT_ERR) { +		rc = fsi_i2c_abort(port, status); +		if (rc) +			return rc; + +		if (status & I2C_STAT_INV_CMD) +			return -EINVAL; + +		if (status & (I2C_STAT_PARITY | I2C_STAT_BE_OVERRUN | +		    I2C_STAT_BE_ACCESS)) +			return -EPROTO; + +		if (status & I2C_STAT_NACK) +			return -ENXIO; + +		if (status & I2C_STAT_LOST_ARB) +			return -EAGAIN; + +		if (status & I2C_STAT_STOP_ERR) +			return -EBADMSG; + +		return -EIO; +	} + +	if (status & I2C_STAT_DAT_REQ) { +		fifo_count = FIELD_GET(I2C_STAT_FIFO_COUNT, status); + +		if (msg->flags & I2C_M_RD) +			return fsi_i2c_read_fifo(port, msg, fifo_count); + +		return fsi_i2c_write_fifo(port, msg, fifo_count); +	} + +	if (status & I2C_STAT_CMD_COMP) { +		if (port->xfrd < msg->len) +			return -ENODATA; + +		return msg->len; +	} + +	return 0; +} + +static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg, +			unsigned long timeout) +{ +	u32 status = 0; +	int rc; +	unsigned long start = jiffies; + +	do { +		rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT, +				      &status); +		if (rc) +			return rc; + +		if (status & I2C_STAT_ANY_RESP) { +			rc = fsi_i2c_handle_status(port, msg, status); +			if (rc < 0) +				return rc; + +			/* cmd complete and all data xfrd */ +			if (rc == msg->len) +				return 0; + +			/* need to xfr more data, but maybe don't need wait */ +			continue; +		} + +		usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US); +	} while (time_after(start + timeout, jiffies)); + +	return -ETIMEDOUT; +} + +static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, +			int num) +{ +	int i, rc; +	unsigned long start_time; +	struct fsi_i2c_port *port = adap->algo_data; +	struct fsi_i2c_master *master = port->master; +	struct i2c_msg *msg; + +	mutex_lock(&master->lock); + +	rc = fsi_i2c_set_port(port); +	if (rc) +		goto unlock; + +	for (i = 0; i < num; i++) { +		msg = msgs + i; +		start_time = jiffies; + +		rc = fsi_i2c_start(port, msg, i == num - 1); +		if (rc) +			goto unlock; + +		rc = fsi_i2c_wait(port, msg, +				  adap->timeout - (jiffies - start_time)); +		if (rc) +			goto unlock; +	} + +unlock: +	mutex_unlock(&master->lock); +	return rc ? : num; +} + +static u32 fsi_i2c_functionality(struct i2c_adapter *adap) +{ +	return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | +		I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = { +	.recover_bus = i2c_generic_scl_recovery, +	.get_scl = fsi_i2c_get_scl, +	.set_scl = fsi_i2c_set_scl, +	.get_sda = fsi_i2c_get_sda, +	.set_sda = fsi_i2c_set_sda, +	.prepare_recovery = fsi_i2c_prepare_recovery, +	.unprepare_recovery = fsi_i2c_unprepare_recovery, +}; + +static const struct i2c_algorithm fsi_i2c_algorithm = { +	.master_xfer = fsi_i2c_xfer, +	.functionality = fsi_i2c_functionality, +}; + +static int fsi_i2c_probe(struct device *dev) +{ +	struct fsi_i2c_master *i2c; +	struct fsi_i2c_port *port; +	struct device_node *np; +	int rc; +	u32 port_no; + +	i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); +	if (!i2c) +		return -ENOMEM; + +	mutex_init(&i2c->lock); +	i2c->fsi = to_fsi_dev(dev); +	INIT_LIST_HEAD(&i2c->ports); + +	rc = fsi_i2c_dev_init(i2c); +	if (rc) +		return rc; + +	/* Add adapter for each i2c port of the master. */ +	for_each_available_child_of_node(dev->of_node, np) { +		rc = of_property_read_u32(np, "reg", &port_no); +		if (rc || port_no > USHRT_MAX) +			continue; + +		port = kzalloc(sizeof(*port), GFP_KERNEL); +		if (!port) +			break; + +		port->master = i2c; +		port->port = port_no; + +		port->adapter.owner = THIS_MODULE; +		port->adapter.dev.of_node = np; +		port->adapter.dev.parent = dev; +		port->adapter.algo = &fsi_i2c_algorithm; +		port->adapter.bus_recovery_info = &fsi_i2c_bus_recovery_info; +		port->adapter.algo_data = port; + +		snprintf(port->adapter.name, sizeof(port->adapter.name), +			 "i2c_bus-%u", port_no); + +		rc = i2c_add_adapter(&port->adapter); +		if (rc < 0) { +			dev_err(dev, "Failed to register adapter: %d\n", rc); +			kfree(port); +			continue; +		} + +		list_add(&port->list, &i2c->ports); +	} + +	dev_set_drvdata(dev, i2c); + +	return 0; +} + +static int fsi_i2c_remove(struct device *dev) +{ +	struct fsi_i2c_master *i2c = dev_get_drvdata(dev); +	struct fsi_i2c_port *port, *tmp; + +	list_for_each_entry_safe(port, tmp, &i2c->ports, list) { +		list_del(&port->list); +		i2c_del_adapter(&port->adapter); +		kfree(port); +	} + +	return 0; +} + +static const struct fsi_device_id fsi_i2c_ids[] = { +	{ FSI_ENGID_I2C, FSI_VERSION_ANY }, +	{ } +}; + +static struct fsi_driver fsi_i2c_driver = { +	.id_table = fsi_i2c_ids, +	.drv = { +		.name = "i2c-fsi", +		.bus = &fsi_bus_type, +		.probe = fsi_i2c_probe, +		.remove = fsi_i2c_remove, +	}, +}; + +module_fsi_driver(fsi_i2c_driver); + +MODULE_AUTHOR("Eddie James <[email protected]>"); +MODULE_DESCRIPTION("FSI attached I2C master"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 66f85bbf3591..c008d209f0b8 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -78,49 +78,43 @@ static struct dentry *i2c_gpio_debug_dir;  #define getscl(bd)	((bd)->getscl((bd)->data))  #define WIRE_ATTRIBUTE(wire) \ -static int fops_##wire##_get(void *data, u64 *val)	\ -{							\ -	struct i2c_gpio_private_data *priv = data;	\ -							\ -	i2c_lock_adapter(&priv->adap);			\ -	*val = get##wire(&priv->bit_data);		\ -	i2c_unlock_adapter(&priv->adap);		\ -	return 0;					\ -}							\ -static int fops_##wire##_set(void *data, u64 val)	\ -{							\ -	struct i2c_gpio_private_data *priv = data;	\ -							\ -	i2c_lock_adapter(&priv->adap);			\ -	set##wire(&priv->bit_data, val);		\ -	i2c_unlock_adapter(&priv->adap);		\ -	return 0;					\ -}							\ +static int fops_##wire##_get(void *data, u64 *val)		\ +{								\ +	struct i2c_gpio_private_data *priv = data;		\ +								\ +	i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);	\ +	*val = get##wire(&priv->bit_data);			\ +	i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);	\ +	return 0;						\ +}								\ +static int fops_##wire##_set(void *data, u64 val)		\ +{								\ +	struct i2c_gpio_private_data *priv = data;		\ +								\ +	i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);	\ +	set##wire(&priv->bit_data, val);			\ +	i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);	\ +	return 0;						\ +}								\  DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n")  WIRE_ATTRIBUTE(scl);  WIRE_ATTRIBUTE(sda); -static int fops_incomplete_transfer_set(void *data, u64 addr) +static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, +					u32 pattern, u8 pattern_size)  { -	struct i2c_gpio_private_data *priv = data;  	struct i2c_algo_bit_data *bit_data = &priv->bit_data; -	int i, pattern; +	int i; -	if (addr > 0x7f) -		return -EINVAL; - -	/* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */ -	pattern = (addr << 2) | 3; - -	i2c_lock_adapter(&priv->adap); +	i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);  	/* START condition */  	setsda(bit_data, 0);  	udelay(bit_data->udelay); -	/* Send ADDR+RD, request ACK, don't send STOP */ -	for (i = 8; i >= 0; i--) { +	/* Send pattern, request ACK, don't send STOP */ +	for (i = pattern_size - 1; i >= 0; i--) {  		setscl(bit_data, 0);  		udelay(bit_data->udelay / 2);  		setsda(bit_data, (pattern >> i) & 1); @@ -129,11 +123,44 @@ static int fops_incomplete_transfer_set(void *data, u64 addr)  		udelay(bit_data->udelay);  	} -	i2c_unlock_adapter(&priv->adap); +	i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); +} + +static int fops_incomplete_addr_phase_set(void *data, u64 addr) +{ +	struct i2c_gpio_private_data *priv = data; +	u32 pattern; + +	if (addr > 0x7f) +		return -EINVAL; + +	/* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ +	pattern = (addr << 2) | 3; + +	i2c_gpio_incomplete_transfer(priv, pattern, 9); + +	return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); + +static int fops_incomplete_write_byte_set(void *data, u64 addr) +{ +	struct i2c_gpio_private_data *priv = data; +	u32 pattern; + +	if (addr > 0x7f) +		return -EINVAL; + +	/* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ +	pattern = (addr << 2) | 1; +	/* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ +	pattern = (pattern << 9) | 1; + +	i2c_gpio_incomplete_transfer(priv, pattern, 18);  	return 0;  } -DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n");  static void i2c_gpio_fault_injector_init(struct platform_device *pdev)  { @@ -156,8 +183,10 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev)  	debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl);  	debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); -	debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, -				   priv, &fops_incomplete_transfer); +	debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, +				   priv, &fops_incomplete_addr_phase); +	debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, +				   priv, &fops_incomplete_write_byte);  }  static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 56dc69e7349f..ff340d7ae2e5 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Renesas Solutions Highlander FPGA I2C/SMBus support.   * @@ -6,10 +7,6 @@   * Copyright (C) 2008  Paul Mundt   * Copyright (C) 2008  Renesas Solutions Corp.   * Copyright (C) 2008  Atom Create Engineering Co., Ltd. - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file "COPYING" in the main directory - * of this archive for more details.   */  #include <linux/module.h>  #include <linux/interrupt.h> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index aa726607645e..941c223f6491 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -70,6 +70,7 @@   * Cannon Lake-H (PCH)		0xa323	32	hard	yes	yes	yes   * Cannon Lake-LP (PCH)		0x9da3	32	hard	yes	yes	yes   * Cedar Fork (PCH)		0x18df	32	hard	yes	yes	yes + * Ice Lake-LP (PCH)		0x34a3	32	hard	yes	yes	yes   *   * Features supported by this driver:   * Software PEC				no @@ -220,6 +221,7 @@  #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS		0x2330  #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS		0x23b0  #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS		0x31d4 +#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS		0x34a3  #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS		0x3b30  #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS		0x5ad4  #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS		0x8c22 @@ -1034,6 +1036,7 @@ static const struct pci_device_id i801_ids[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },  	{ 0, }  }; @@ -1518,6 +1521,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)  	case PCI_DEVICE_ID_INTEL_CDF_SMBUS:  	case PCI_DEVICE_ID_INTEL_DNV_SMBUS:  	case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: +	case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:  		priv->features |= FEATURE_I2C_BLOCK_READ;  		priv->features |= FEATURE_IRQ;  		priv->features |= FEATURE_SMBUS_PEC; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 498c5e891649..c406700789e1 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -421,10 +421,14 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)  			return -EAGAIN;  		} -		if (for_busy && (temp & I2SR_IBB)) +		if (for_busy && (temp & I2SR_IBB)) { +			i2c_imx->stopped = 0;  			break; -		if (!for_busy && !(temp & I2SR_IBB)) +		} +		if (!for_busy && !(temp & I2SR_IBB)) { +			i2c_imx->stopped = 1;  			break; +		}  		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {  			dev_dbg(&i2c_imx->adapter.dev,  				"<%s> I2C bus is busy\n", __func__); @@ -538,7 +542,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)  	result = i2c_imx_bus_busy(i2c_imx, 1);  	if (result)  		return result; -	i2c_imx->stopped = 0;  	temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;  	temp &= ~I2CR_DMAEN; @@ -567,10 +570,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)  		udelay(i2c_imx->disable_delay);  	} -	if (!i2c_imx->stopped) { +	if (!i2c_imx->stopped)  		i2c_imx_bus_busy(i2c_imx, 0); -		i2c_imx->stopped = 1; -	}  	/* Disable I2C controller */  	temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, @@ -668,9 +669,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,  	struct imx_i2c_dma *dma = i2c_imx->dma;  	struct device *dev = &i2c_imx->adapter.dev; -	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); -	temp |= I2CR_DMAEN; -	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);  	dma->chan_using = dma->chan_rx;  	dma->dma_transfer_dir = DMA_DEV_TO_MEM; @@ -727,7 +725,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,  		temp &= ~(I2CR_MSTA | I2CR_MTX);  		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);  		i2c_imx_bus_busy(i2c_imx, 0); -		i2c_imx->stopped = 1;  	} else {  		/*  		 * For i2c master receiver repeat restart operation like: @@ -783,6 +780,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo  	int i, result;  	unsigned int temp;  	int block_data = msgs->flags & I2C_M_RECV_LEN; +	int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data;  	dev_dbg(&i2c_imx->adapter.dev,  		"<%s> write slave address: addr=0x%x\n", @@ -809,12 +807,14 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo  	 */  	if ((msgs->len - 1) || block_data)  		temp &= ~I2CR_TXAK; +	if (use_dma) +		temp |= I2CR_DMAEN;  	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);  	imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */  	dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); -	if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) +	if (use_dma)  		return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg);  	/* read data */ @@ -850,7 +850,6 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo  				temp &= ~(I2CR_MSTA | I2CR_MTX);  				imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);  				i2c_imx_bus_busy(i2c_imx, 0); -				i2c_imx->stopped = 1;  			} else {  				/*  				 * For i2c master receiver repeat restart operation like: diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 642c58946d8d..7d79317a1046 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -567,9 +567,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,  	dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",  		msg->addr, msg->len, msg->flags, stop); -	if (msg->len == 0) -		return -EINVAL; -  	/*  	 * The MX28 I2C IP block can only do PIO READ for transfer of to up  	 * 4 bytes of length. The write transfer is not limited as it can use @@ -683,6 +680,10 @@ static const struct i2c_algorithm mxs_i2c_algo = {  	.functionality = mxs_i2c_func,  }; +static const struct i2c_adapter_quirks mxs_i2c_quirks = { +	.flags = I2C_AQ_NO_ZERO_LEN, +}; +  static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed)  {  	/* The I2C block clock runs at 24MHz */ @@ -854,6 +855,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)  	strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));  	adap->owner = THIS_MODULE;  	adap->algo = &mxs_i2c_algo; +	adap->quirks = &mxs_i2c_quirks;  	adap->dev.parent = dev;  	adap->nr = pdev->id;  	adap->dev.of_node = pdev->dev.of_node; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 88444ef74943..87f9caacba85 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -2,7 +2,7 @@   * i2c-ocores.c: I2C bus driver for OpenCores I2C controller   * (https://opencores.org/project/i2c/overview)   * - * Peter Korsgaard <[email protected]> + * Peter Korsgaard <[email protected]>   *   * Support for the GRLIB port of the controller by   * Andreas Larsson <[email protected]> @@ -576,7 +576,7 @@ static struct platform_driver ocores_i2c_driver = {  module_platform_driver(ocores_i2c_driver); -MODULE_AUTHOR("Peter Korsgaard <[email protected]>"); +MODULE_AUTHOR("Peter Korsgaard <[email protected]>");  MODULE_DESCRIPTION("OpenCores I2C bus driver");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:ocores-i2c"); diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c new file mode 100644 index 000000000000..96b4572e6d9c --- /dev/null +++ b/drivers/i2c/busses/i2c-owl.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Actions Semiconductor Owl SoC's I2C driver + * + * Copyright (c) 2014 Actions Semi Inc. + * Author: David Liu <[email protected]> + * + * Copyright (c) 2018 Linaro Ltd. + * Author: Manivannan Sadhasivam <[email protected]> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_device.h> + +/* I2C registers */ +#define OWL_I2C_REG_CTL		0x0000 +#define OWL_I2C_REG_CLKDIV	0x0004 +#define OWL_I2C_REG_STAT	0x0008 +#define OWL_I2C_REG_ADDR	0x000C +#define OWL_I2C_REG_TXDAT	0x0010 +#define OWL_I2C_REG_RXDAT	0x0014 +#define OWL_I2C_REG_CMD		0x0018 +#define OWL_I2C_REG_FIFOCTL	0x001C +#define OWL_I2C_REG_FIFOSTAT	0x0020 +#define OWL_I2C_REG_DATCNT	0x0024 +#define OWL_I2C_REG_RCNT	0x0028 + +/* I2Cx_CTL Bit Mask */ +#define OWL_I2C_CTL_RB		BIT(1) +#define OWL_I2C_CTL_GBCC(x)	(((x) & 0x3) << 2) +#define	OWL_I2C_CTL_GBCC_NONE	OWL_I2C_CTL_GBCC(0) +#define	OWL_I2C_CTL_GBCC_START	OWL_I2C_CTL_GBCC(1) +#define	OWL_I2C_CTL_GBCC_STOP	OWL_I2C_CTL_GBCC(2) +#define	OWL_I2C_CTL_GBCC_RSTART	OWL_I2C_CTL_GBCC(3) +#define OWL_I2C_CTL_IRQE	BIT(5) +#define OWL_I2C_CTL_EN		BIT(7) +#define OWL_I2C_CTL_AE		BIT(8) +#define OWL_I2C_CTL_SHSM	BIT(10) + +#define OWL_I2C_DIV_FACTOR(x)	((x) & 0xff) + +/* I2Cx_STAT Bit Mask */ +#define OWL_I2C_STAT_RACK	BIT(0) +#define OWL_I2C_STAT_BEB	BIT(1) +#define OWL_I2C_STAT_IRQP	BIT(2) +#define OWL_I2C_STAT_LAB	BIT(3) +#define OWL_I2C_STAT_STPD	BIT(4) +#define OWL_I2C_STAT_STAD	BIT(5) +#define OWL_I2C_STAT_BBB	BIT(6) +#define OWL_I2C_STAT_TCB	BIT(7) +#define OWL_I2C_STAT_LBST	BIT(8) +#define OWL_I2C_STAT_SAMB	BIT(9) +#define OWL_I2C_STAT_SRGC	BIT(10) + +/* I2Cx_CMD Bit Mask */ +#define OWL_I2C_CMD_SBE		BIT(0) +#define OWL_I2C_CMD_RBE		BIT(4) +#define OWL_I2C_CMD_DE		BIT(8) +#define OWL_I2C_CMD_NS		BIT(9) +#define OWL_I2C_CMD_SE		BIT(10) +#define OWL_I2C_CMD_MSS		BIT(11) +#define OWL_I2C_CMD_WRS		BIT(12) +#define OWL_I2C_CMD_SECL	BIT(15) + +#define OWL_I2C_CMD_AS(x)	(((x) & 0x7) << 1) +#define OWL_I2C_CMD_SAS(x)	(((x) & 0x7) << 5) + +/* I2Cx_FIFOCTL Bit Mask */ +#define OWL_I2C_FIFOCTL_NIB	BIT(0) +#define OWL_I2C_FIFOCTL_RFR	BIT(1) +#define OWL_I2C_FIFOCTL_TFR	BIT(2) + +/* I2Cc_FIFOSTAT Bit Mask */ +#define OWL_I2C_FIFOSTAT_RNB	BIT(1) +#define OWL_I2C_FIFOSTAT_RFE	BIT(2) +#define OWL_I2C_FIFOSTAT_TFF	BIT(5) +#define OWL_I2C_FIFOSTAT_TFD	GENMASK(23, 16) +#define OWL_I2C_FIFOSTAT_RFD	GENMASK(15, 8) + +/* I2C bus timeout */ +#define OWL_I2C_TIMEOUT		msecs_to_jiffies(4 * 1000) + +#define OWL_I2C_MAX_RETRIES	50 + +#define OWL_I2C_DEF_SPEED_HZ	100000 +#define OWL_I2C_MAX_SPEED_HZ	400000 + +struct owl_i2c_dev { +	struct i2c_adapter	adap; +	struct i2c_msg		*msg; +	struct completion	msg_complete; +	struct clk		*clk; +	spinlock_t		lock; +	void __iomem		*base; +	unsigned long		clk_rate; +	u32			bus_freq; +	u32			msg_ptr; +	int			err; +}; + +static void owl_i2c_update_reg(void __iomem *reg, unsigned int val, bool state) +{ +	unsigned int regval; + +	regval = readl(reg); + +	if (state) +		regval |= val; +	else +		regval &= ~val; + +	writel(regval, reg); +} + +static void owl_i2c_reset(struct owl_i2c_dev *i2c_dev) +{ +	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, +			   OWL_I2C_CTL_EN, false); +	mdelay(1); +	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, +			   OWL_I2C_CTL_EN, true); + +	/* Clear status registers */ +	writel(0, i2c_dev->base + OWL_I2C_REG_STAT); +} + +static int owl_i2c_reset_fifo(struct owl_i2c_dev *i2c_dev) +{ +	unsigned int val, timeout = 0; + +	/* Reset FIFO */ +	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, +			   OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR, +			   true); + +	/* Wait 50ms for FIFO reset complete */ +	do { +		val = readl(i2c_dev->base + OWL_I2C_REG_FIFOCTL); +		if (!(val & (OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR))) +			break; +		usleep_range(500, 1000); +	} while (timeout++ < OWL_I2C_MAX_RETRIES); + +	if (timeout > OWL_I2C_MAX_RETRIES) { +		dev_err(&i2c_dev->adap.dev, "FIFO reset timeout\n"); +		return -ETIMEDOUT; +	} + +	return 0; +} + +static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev) +{ +	unsigned int val; + +	val = DIV_ROUND_UP(i2c_dev->clk_rate, i2c_dev->bus_freq * 16); + +	/* Set clock divider factor */ +	writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV); +} + +static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) +{ +	struct owl_i2c_dev *i2c_dev = _dev; +	struct i2c_msg *msg = i2c_dev->msg; +	unsigned long flags; +	unsigned int stat, fifostat; + +	spin_lock_irqsave(&i2c_dev->lock, flags); + +	i2c_dev->err = 0; + +	/* Handle NACK from slave */ +	fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT); +	if (fifostat & OWL_I2C_FIFOSTAT_RNB) { +		i2c_dev->err = -ENXIO; +		goto stop; +	} + +	/* Handle bus error */ +	stat = readl(i2c_dev->base + OWL_I2C_REG_STAT); +	if (stat & OWL_I2C_STAT_BEB) { +		i2c_dev->err = -EIO; +		goto stop; +	} + +	/* Handle FIFO read */ +	if (msg->flags & I2C_M_RD) { +		while ((readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & +			OWL_I2C_FIFOSTAT_RFE) && i2c_dev->msg_ptr < msg->len) { +			msg->buf[i2c_dev->msg_ptr++] = readl(i2c_dev->base + +							     OWL_I2C_REG_RXDAT); +		} +	} else { +		/* Handle the remaining bytes which were not sent */ +		while (!(readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & +			 OWL_I2C_FIFOSTAT_TFF) && i2c_dev->msg_ptr < msg->len) { +			writel(msg->buf[i2c_dev->msg_ptr++], +			       i2c_dev->base + OWL_I2C_REG_TXDAT); +		} +	} + +stop: +	/* Clear pending interrupts */ +	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, +			   OWL_I2C_STAT_IRQP, true); + +	complete_all(&i2c_dev->msg_complete); +	spin_unlock_irqrestore(&i2c_dev->lock, flags); + +	return IRQ_HANDLED; +} + +static u32 owl_i2c_func(struct i2c_adapter *adap) +{ +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static int owl_i2c_check_bus_busy(struct i2c_adapter *adap) +{ +	struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); +	unsigned long timeout; + +	/* Check for Bus busy */ +	timeout = jiffies + OWL_I2C_TIMEOUT; +	while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) { +		if (time_after(jiffies, timeout)) { +			dev_err(&adap->dev, "Bus busy timeout\n"); +			return -ETIMEDOUT; +		} +	} + +	return 0; +} + +static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, +			       int num) +{ +	struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); +	struct i2c_msg *msg; +	unsigned long time_left, flags; +	unsigned int i2c_cmd, val; +	unsigned int addr; +	int ret, idx; + +	spin_lock_irqsave(&i2c_dev->lock, flags); + +	/* Reset I2C controller */ +	owl_i2c_reset(i2c_dev); + +	/* Set bus frequency */ +	owl_i2c_set_freq(i2c_dev); + +	/* +	 * Spinlock should be released before calling reset FIFO and +	 * bus busy check since those functions may sleep +	 */ +	spin_unlock_irqrestore(&i2c_dev->lock, flags); + +	/* Reset FIFO */ +	ret = owl_i2c_reset_fifo(i2c_dev); +	if (ret) +		goto unlocked_err_exit; + +	/* Check for bus busy */ +	ret = owl_i2c_check_bus_busy(adap); +	if (ret) +		goto unlocked_err_exit; + +	spin_lock_irqsave(&i2c_dev->lock, flags); + +	/* Check for Arbitration lost */ +	val = readl(i2c_dev->base + OWL_I2C_REG_STAT); +	if (val & OWL_I2C_STAT_LAB) { +		val &= ~OWL_I2C_STAT_LAB; +		writel(val, i2c_dev->base + OWL_I2C_REG_STAT); +		ret = -EAGAIN; +		goto err_exit; +	} + +	reinit_completion(&i2c_dev->msg_complete); + +	/* Enable I2C controller interrupt */ +	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, +			   OWL_I2C_CTL_IRQE, true); + +	/* +	 * Select: FIFO enable, Master mode, Stop enable, Data count enable, +	 * Send start bit +	 */ +	i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE | +		  OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE; + +	/* Handle repeated start condition */ +	if (num > 1) { +		/* Set internal address length and enable repeated start */ +		i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) | +			   OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE; + +		/* Write slave address */ +		addr = i2c_8bit_addr_from_msg(&msgs[0]); +		writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); + +		/* Write internal register address */ +		for (idx = 0; idx < msgs[0].len; idx++) +			writel(msgs[0].buf[idx], +			       i2c_dev->base + OWL_I2C_REG_TXDAT); + +		msg = &msgs[1]; +	} else { +		/* Set address length */ +		i2c_cmd |= OWL_I2C_CMD_AS(1); +		msg = &msgs[0]; +	} + +	i2c_dev->msg = msg; +	i2c_dev->msg_ptr = 0; + +	/* Set data count for the message */ +	writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT); + +	addr = i2c_8bit_addr_from_msg(msg); +	writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); + +	if (!(msg->flags & I2C_M_RD)) { +		/* Write data to FIFO */ +		for (idx = 0; idx < msg->len; idx++) { +			/* Check for FIFO full */ +			if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & +			    OWL_I2C_FIFOSTAT_TFF) +				break; + +			writel(msg->buf[idx], +			       i2c_dev->base + OWL_I2C_REG_TXDAT); +		} + +		i2c_dev->msg_ptr = idx; +	} + +	/* Ignore the NACK if needed */ +	if (msg->flags & I2C_M_IGNORE_NAK) +		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, +				   OWL_I2C_FIFOCTL_NIB, true); +	else +		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, +				   OWL_I2C_FIFOCTL_NIB, false); + +	/* Start the transfer */ +	writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD); + +	spin_unlock_irqrestore(&i2c_dev->lock, flags); + +	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, +						adap->timeout); + +	spin_lock_irqsave(&i2c_dev->lock, flags); +	if (time_left == 0) { +		dev_err(&adap->dev, "Transaction timed out\n"); +		/* Send stop condition and release the bus */ +		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, +				   OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB, +				   true); +		ret = -ETIMEDOUT; +		goto err_exit; +	} + +	ret = i2c_dev->err < 0 ? i2c_dev->err : num; + +err_exit: +	spin_unlock_irqrestore(&i2c_dev->lock, flags); + +unlocked_err_exit: +	/* Disable I2C controller */ +	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, +			   OWL_I2C_CTL_EN, false); + +	return ret; +} + +static const struct i2c_algorithm owl_i2c_algorithm = { +	.master_xfer    = owl_i2c_master_xfer, +	.functionality  = owl_i2c_func, +}; + +static const struct i2c_adapter_quirks owl_i2c_quirks = { +	.flags		= I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST, +	.max_read_len   = 240, +	.max_write_len  = 240, +	.max_comb_1st_msg_len = 6, +	.max_comb_2nd_msg_len = 240, +}; + +static int owl_i2c_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct owl_i2c_dev *i2c_dev; +	struct resource *res; +	int ret, irq; + +	i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL); +	if (!i2c_dev) +		return -ENOMEM; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	i2c_dev->base = devm_ioremap_resource(dev, res); +	if (IS_ERR(i2c_dev->base)) +		return PTR_ERR(i2c_dev->base); + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(dev, "failed to get IRQ number\n"); +		return irq; +	} + +	if (of_property_read_u32(dev->of_node, "clock-frequency", +				 &i2c_dev->bus_freq)) +		i2c_dev->bus_freq = OWL_I2C_DEF_SPEED_HZ; + +	/* We support only frequencies of 100k and 400k for now */ +	if (i2c_dev->bus_freq != OWL_I2C_DEF_SPEED_HZ && +	    i2c_dev->bus_freq != OWL_I2C_MAX_SPEED_HZ) { +		dev_err(dev, "invalid clock-frequency %d\n", i2c_dev->bus_freq); +		return -EINVAL; +	} + +	i2c_dev->clk = devm_clk_get(dev, NULL); +	if (IS_ERR(i2c_dev->clk)) { +		dev_err(dev, "failed to get clock\n"); +		return PTR_ERR(i2c_dev->clk); +	} + +	ret = clk_prepare_enable(i2c_dev->clk); +	if (ret) +		return ret; + +	i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk); +	if (!i2c_dev->clk_rate) { +		dev_err(dev, "input clock rate should not be zero\n"); +		ret = -EINVAL; +		goto disable_clk; +	} + +	init_completion(&i2c_dev->msg_complete); +	spin_lock_init(&i2c_dev->lock); +	i2c_dev->adap.owner = THIS_MODULE; +	i2c_dev->adap.algo = &owl_i2c_algorithm; +	i2c_dev->adap.timeout = OWL_I2C_TIMEOUT; +	i2c_dev->adap.quirks = &owl_i2c_quirks; +	i2c_dev->adap.dev.parent = dev; +	i2c_dev->adap.dev.of_node = dev->of_node; +	snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name), +		 "%s", "OWL I2C adapter"); +	i2c_set_adapdata(&i2c_dev->adap, i2c_dev); + +	platform_set_drvdata(pdev, i2c_dev); + +	ret = devm_request_irq(dev, irq, owl_i2c_interrupt, 0, pdev->name, +			       i2c_dev); +	if (ret) { +		dev_err(dev, "failed to request irq %d\n", irq); +		goto disable_clk; +	} + +	return i2c_add_adapter(&i2c_dev->adap); + +disable_clk: +	clk_disable_unprepare(i2c_dev->clk); + +	return ret; +} + +static const struct of_device_id owl_i2c_of_match[] = { +	{ .compatible = "actions,s900-i2c" }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, owl_i2c_of_match); + +static struct platform_driver owl_i2c_driver = { +	.probe		= owl_i2c_probe, +	.driver		= { +		.name	= "owl-i2c", +		.of_match_table = of_match_ptr(owl_i2c_of_match), +	}, +}; +module_platform_driver(owl_i2c_driver); + +MODULE_AUTHOR("David Liu <[email protected]>"); +MODULE_AUTHOR("Manivannan Sadhasivam <[email protected]>"); +MODULE_DESCRIPTION("Actions Semiconductor Owl SoC's I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 55fd5c6f3cca..50803e5d995b 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -365,7 +365,6 @@ static int pasemi_smb_probe(struct pci_dev *dev,  	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;  	smbus->adapter.algo = &smbus_algorithm;  	smbus->adapter.algo_data = smbus; -	smbus->adapter.nr = PCI_FUNC(dev->devfn);  	/* set up the sysfs linkage to our parent device */  	smbus->adapter.dev.parent = &dev->dev; @@ -373,7 +372,7 @@ static int pasemi_smb_probe(struct pci_dev *dev,  	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |  		  (CLK_100K_DIV & CTL_CLK_M))); -	error = i2c_add_numbered_adapter(&smbus->adapter); +	error = i2c_add_adapter(&smbus->adapter);  	if (error)  		goto out_release_region; diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index dae8ac618a52..0829cb696d9d 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -444,16 +444,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(  {  	enum pmcmsptwi_xfer_result retval; -	if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) || -	    (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) || -	    (cmd->type == MSP_TWI_CMD_WRITE_READ && -	    (cmd->read_len == 0 || cmd->write_len == 0))) { -		dev_err(&pmcmsptwi_adapter.dev, -			"%s: Cannot transfer less than 1 byte\n", -			__func__); -		return -EINVAL; -	} -  	mutex_lock(&data->lock);  	dev_dbg(&pmcmsptwi_adapter.dev,  		"Setting address to 0x%04x\n", cmd->addr); @@ -532,11 +522,6 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,  		cmd.write_data = msg->buf;  	} -	if (msg->len == 0) { -		dev_err(&adap->dev, "Zero-byte messages unsupported\n"); -		return -EINVAL; -	} -  	cmd.addr = msg->addr;  	if (msg->flags & I2C_M_TEN) { @@ -578,7 +563,7 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)  }  static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = { -	.flags = I2C_AQ_COMB_WRITE_THEN_READ, +	.flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN,  	.max_write_len = MSP_MAX_BYTES_PER_RW,  	.max_read_len = MSP_MAX_BYTES_PER_RW,  	.max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c new file mode 100644 index 000000000000..36732eb688a4 --- /dev/null +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -0,0 +1,673 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/qcom-geni-se.h> +#include <linux/spinlock.h> + +#define SE_I2C_TX_TRANS_LEN		0x26c +#define SE_I2C_RX_TRANS_LEN		0x270 +#define SE_I2C_SCL_COUNTERS		0x278 + +#define SE_I2C_ERR  (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\ +			M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN) +#define SE_I2C_ABORT		BIT(1) + +/* M_CMD OP codes for I2C */ +#define I2C_WRITE		0x1 +#define I2C_READ		0x2 +#define I2C_WRITE_READ		0x3 +#define I2C_ADDR_ONLY		0x4 +#define I2C_BUS_CLEAR		0x6 +#define I2C_STOP_ON_BUS		0x7 +/* M_CMD params for I2C */ +#define PRE_CMD_DELAY		BIT(0) +#define TIMESTAMP_BEFORE	BIT(1) +#define STOP_STRETCH		BIT(2) +#define TIMESTAMP_AFTER		BIT(3) +#define POST_COMMAND_DELAY	BIT(4) +#define IGNORE_ADD_NACK		BIT(6) +#define READ_FINISHED_WITH_ACK	BIT(7) +#define BYPASS_ADDR_PHASE	BIT(8) +#define SLV_ADDR_MSK		GENMASK(15, 9) +#define SLV_ADDR_SHFT		9 +/* I2C SCL COUNTER fields */ +#define HIGH_COUNTER_MSK	GENMASK(29, 20) +#define HIGH_COUNTER_SHFT	20 +#define LOW_COUNTER_MSK		GENMASK(19, 10) +#define LOW_COUNTER_SHFT	10 +#define CYCLE_COUNTER_MSK	GENMASK(9, 0) + +enum geni_i2c_err_code { +	GP_IRQ0, +	NACK, +	GP_IRQ2, +	BUS_PROTO, +	ARB_LOST, +	GP_IRQ5, +	GENI_OVERRUN, +	GENI_ILLEGAL_CMD, +	GENI_ABORT_DONE, +	GENI_TIMEOUT, +}; + +#define DM_I2C_CB_ERR		((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \ +									<< 5) + +#define I2C_AUTO_SUSPEND_DELAY	250 +#define KHZ(freq)		(1000 * freq) +#define PACKING_BYTES_PW	4 + +#define ABORT_TIMEOUT		HZ +#define XFER_TIMEOUT		HZ +#define RST_TIMEOUT		HZ + +struct geni_i2c_dev { +	struct geni_se se; +	u32 tx_wm; +	int irq; +	int err; +	struct i2c_adapter adap; +	struct completion done; +	struct i2c_msg *cur; +	int cur_wr; +	int cur_rd; +	spinlock_t lock; +	u32 clk_freq_out; +	const struct geni_i2c_clk_fld *clk_fld; +	int suspended; +}; + +struct geni_i2c_err_log { +	int err; +	const char *msg; +}; + +static const struct geni_i2c_err_log gi2c_log[] = { +	[GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"}, +	[NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"}, +	[GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"}, +	[BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unepxected start/stop"}, +	[ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"}, +	[GP_IRQ5] = {-EIO, "Unknown I2C err GP IRQ5"}, +	[GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"}, +	[GENI_ILLEGAL_CMD] = {-EIO, "Illegal cmd, check GENI cmd-state machine"}, +	[GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"}, +	[GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"}, +}; + +struct geni_i2c_clk_fld { +	u32	clk_freq_out; +	u8	clk_div; +	u8	t_high_cnt; +	u8	t_low_cnt; +	u8	t_cycle_cnt; +}; + +/* + * Hardware uses the underlying formula to calculate time periods of + * SCL clock cycle. Firmware uses some additional cycles excluded from the + * below formula and it is confirmed that the time periods are within + * specification limits. + * + * time of high period of SCL: t_high = (t_high_cnt * clk_div) / source_clock + * time of low period of SCL: t_low = (t_low_cnt * clk_div) / source_clock + * time of full period of SCL: t_cycle = (t_cycle_cnt * clk_div) / source_clock + * clk_freq_out = t / t_cycle + * source_clock = 19.2 MHz + */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { +	{KHZ(100), 7, 10, 11, 26}, +	{KHZ(400), 2,  5, 12, 24}, +	{KHZ(1000), 1, 3,  9, 18}, +}; + +static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) +{ +	int i; +	const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + +	for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { +		if (itr->clk_freq_out == gi2c->clk_freq_out) { +			gi2c->clk_fld = itr; +			return 0; +		} +	} +	return -EINVAL; +} + +static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c) +{ +	const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; +	u32 val; + +	writel_relaxed(0, gi2c->se.base + SE_GENI_CLK_SEL); + +	val = (itr->clk_div << CLK_DIV_SHFT) | SER_CLK_EN; +	writel_relaxed(val, gi2c->se.base + GENI_SER_M_CLK_CFG); + +	val = itr->t_high_cnt << HIGH_COUNTER_SHFT; +	val |= itr->t_low_cnt << LOW_COUNTER_SHFT; +	val |= itr->t_cycle_cnt; +	writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS); +} + +static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c) +{ +	u32 m_cmd = readl_relaxed(gi2c->se.base + SE_GENI_M_CMD0); +	u32 m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); +	u32 geni_s = readl_relaxed(gi2c->se.base + SE_GENI_STATUS); +	u32 geni_ios = readl_relaxed(gi2c->se.base + SE_GENI_IOS); +	u32 dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN); +	u32 rx_st, tx_st; + +	if (dma) { +		rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); +		tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); +	} else { +		rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS); +		tx_st = readl_relaxed(gi2c->se.base + SE_GENI_TX_FIFO_STATUS); +	} +	dev_dbg(gi2c->se.dev, "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n", +		dma, tx_st, rx_st, m_stat); +	dev_dbg(gi2c->se.dev, "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n", +		m_cmd, geni_s, geni_ios); +} + +static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) +{ +	if (!gi2c->err) +		gi2c->err = gi2c_log[err].err; +	if (gi2c->cur) +		dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n", +			gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags); + +	if (err != NACK && err != GENI_ABORT_DONE) { +		dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg); +		geni_i2c_err_misc(gi2c); +	} +} + +static irqreturn_t geni_i2c_irq(int irq, void *dev) +{ +	struct geni_i2c_dev *gi2c = dev; +	int j; +	u32 m_stat; +	u32 rx_st; +	u32 dm_tx_st; +	u32 dm_rx_st; +	u32 dma; +	struct i2c_msg *cur; +	unsigned long flags; + +	spin_lock_irqsave(&gi2c->lock, flags); +	m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); +	rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS); +	dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); +	dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); +	dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN); +	cur = gi2c->cur; + +	if (!cur || +	    m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) || +	    dm_rx_st & (DM_I2C_CB_ERR)) { +		if (m_stat & M_GP_IRQ_1_EN) +			geni_i2c_err(gi2c, NACK); +		if (m_stat & M_GP_IRQ_3_EN) +			geni_i2c_err(gi2c, BUS_PROTO); +		if (m_stat & M_GP_IRQ_4_EN) +			geni_i2c_err(gi2c, ARB_LOST); +		if (m_stat & M_CMD_OVERRUN_EN) +			geni_i2c_err(gi2c, GENI_OVERRUN); +		if (m_stat & M_ILLEGAL_CMD_EN) +			geni_i2c_err(gi2c, GENI_ILLEGAL_CMD); +		if (m_stat & M_CMD_ABORT_EN) +			geni_i2c_err(gi2c, GENI_ABORT_DONE); +		if (m_stat & M_GP_IRQ_0_EN) +			geni_i2c_err(gi2c, GP_IRQ0); + +		/* Disable the TX Watermark interrupt to stop TX */ +		if (!dma) +			writel_relaxed(0, gi2c->se.base + +					   SE_GENI_TX_WATERMARK_REG); +		goto irqret; +	} + +	if (dma) { +		dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n", +			dm_tx_st, dm_rx_st); +		goto irqret; +	} + +	if (cur->flags & I2C_M_RD && +	    m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) { +		u32 rxcnt = rx_st & RX_FIFO_WC_MSK; + +		for (j = 0; j < rxcnt; j++) { +			u32 val; +			int p = 0; + +			val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn); +			while (gi2c->cur_rd < cur->len && p < sizeof(val)) { +				cur->buf[gi2c->cur_rd++] = val & 0xff; +				val >>= 8; +				p++; +			} +			if (gi2c->cur_rd == cur->len) +				break; +		} +	} else if (!(cur->flags & I2C_M_RD) && +		   m_stat & M_TX_FIFO_WATERMARK_EN) { +		for (j = 0; j < gi2c->tx_wm; j++) { +			u32 temp; +			u32 val = 0; +			int p = 0; + +			while (gi2c->cur_wr < cur->len && p < sizeof(val)) { +				temp = cur->buf[gi2c->cur_wr++]; +				val |= temp << (p * 8); +				p++; +			} +			writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn); +			/* TX Complete, Disable the TX Watermark interrupt */ +			if (gi2c->cur_wr == cur->len) { +				writel_relaxed(0, gi2c->se.base + +						SE_GENI_TX_WATERMARK_REG); +				break; +			} +		} +	} +irqret: +	if (m_stat) +		writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR); + +	if (dma) { +		if (dm_tx_st) +			writel_relaxed(dm_tx_st, gi2c->se.base + +						SE_DMA_TX_IRQ_CLR); +		if (dm_rx_st) +			writel_relaxed(dm_rx_st, gi2c->se.base + +						SE_DMA_RX_IRQ_CLR); +	} +	/* if this is err with done-bit not set, handle that through timeout. */ +	if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN) +		complete(&gi2c->done); +	else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE) +		complete(&gi2c->done); +	else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE) +		complete(&gi2c->done); + +	spin_unlock_irqrestore(&gi2c->lock, flags); +	return IRQ_HANDLED; +} + +static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c) +{ +	u32 val; +	unsigned long time_left = ABORT_TIMEOUT; +	unsigned long flags; + +	spin_lock_irqsave(&gi2c->lock, flags); +	geni_i2c_err(gi2c, GENI_TIMEOUT); +	gi2c->cur = NULL; +	geni_se_abort_m_cmd(&gi2c->se); +	spin_unlock_irqrestore(&gi2c->lock, flags); +	do { +		time_left = wait_for_completion_timeout(&gi2c->done, time_left); +		val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); +	} while (!(val & M_CMD_ABORT_EN) && time_left); + +	if (!(val & M_CMD_ABORT_EN)) +		dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n"); +} + +static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c) +{ +	u32 val; +	unsigned long time_left = RST_TIMEOUT; + +	writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST); +	do { +		time_left = wait_for_completion_timeout(&gi2c->done, time_left); +		val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); +	} while (!(val & RX_RESET_DONE) && time_left); + +	if (!(val & RX_RESET_DONE)) +		dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n"); +} + +static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c) +{ +	u32 val; +	unsigned long time_left = RST_TIMEOUT; + +	writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST); +	do { +		time_left = wait_for_completion_timeout(&gi2c->done, time_left); +		val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); +	} while (!(val & TX_RESET_DONE) && time_left); + +	if (!(val & TX_RESET_DONE)) +		dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n"); +} + +static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, +				u32 m_param) +{ +	dma_addr_t rx_dma; +	enum geni_se_xfer_mode mode; +	unsigned long time_left = XFER_TIMEOUT; + +	gi2c->cur = msg; +	mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO; +	geni_se_select_mode(&gi2c->se, mode); +	writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN); +	geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param); +	if (mode == GENI_SE_DMA) { +		int ret; + +		ret = geni_se_rx_dma_prep(&gi2c->se, msg->buf, msg->len, +								&rx_dma); +		if (ret) { +			mode = GENI_SE_FIFO; +			geni_se_select_mode(&gi2c->se, mode); +		} +	} + +	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); +	if (!time_left) +		geni_i2c_abort_xfer(gi2c); + +	gi2c->cur_rd = 0; +	if (mode == GENI_SE_DMA) { +		if (gi2c->err) +			geni_i2c_rx_fsm_rst(gi2c); +		geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len); +	} +	return gi2c->err; +} + +static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, +				u32 m_param) +{ +	dma_addr_t tx_dma; +	enum geni_se_xfer_mode mode; +	unsigned long time_left; + +	gi2c->cur = msg; +	mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO; +	geni_se_select_mode(&gi2c->se, mode); +	writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN); +	geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param); +	if (mode == GENI_SE_DMA) { +		int ret; + +		ret = geni_se_tx_dma_prep(&gi2c->se, msg->buf, msg->len, +								&tx_dma); +		if (ret) { +			mode = GENI_SE_FIFO; +			geni_se_select_mode(&gi2c->se, mode); +		} +	} + +	if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */ +		writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG); + +	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); +	if (!time_left) +		geni_i2c_abort_xfer(gi2c); + +	gi2c->cur_wr = 0; +	if (mode == GENI_SE_DMA) { +		if (gi2c->err) +			geni_i2c_tx_fsm_rst(gi2c); +		geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len); +	} +	return gi2c->err; +} + +static int geni_i2c_xfer(struct i2c_adapter *adap, +			 struct i2c_msg msgs[], +			 int num) +{ +	struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap); +	int i, ret; + +	gi2c->err = 0; +	reinit_completion(&gi2c->done); +	ret = pm_runtime_get_sync(gi2c->se.dev); +	if (ret < 0) { +		dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret); +		pm_runtime_put_noidle(gi2c->se.dev); +		/* Set device in suspended since resume failed */ +		pm_runtime_set_suspended(gi2c->se.dev); +		return ret; +	} + +	qcom_geni_i2c_conf(gi2c); +	for (i = 0; i < num; i++) { +		u32 m_param = i < (num - 1) ? STOP_STRETCH : 0; + +		m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); + +		if (msgs[i].flags & I2C_M_RD) +			ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); +		else +			ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param); + +		if (ret) +			break; +	} +	if (ret == 0) +		ret = num; + +	pm_runtime_mark_last_busy(gi2c->se.dev); +	pm_runtime_put_autosuspend(gi2c->se.dev); +	gi2c->cur = NULL; +	gi2c->err = 0; +	return ret; +} + +static u32 geni_i2c_func(struct i2c_adapter *adap) +{ +	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +static const struct i2c_algorithm geni_i2c_algo = { +	.master_xfer	= geni_i2c_xfer, +	.functionality	= geni_i2c_func, +}; + +static int geni_i2c_probe(struct platform_device *pdev) +{ +	struct geni_i2c_dev *gi2c; +	struct resource *res; +	u32 proto, tx_depth; +	int ret; + +	gi2c = devm_kzalloc(&pdev->dev, sizeof(*gi2c), GFP_KERNEL); +	if (!gi2c) +		return -ENOMEM; + +	gi2c->se.dev = &pdev->dev; +	gi2c->se.wrapper = dev_get_drvdata(pdev->dev.parent); +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	gi2c->se.base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(gi2c->se.base)) +		return PTR_ERR(gi2c->se.base); + +	gi2c->se.clk = devm_clk_get(&pdev->dev, "se"); +	if (IS_ERR(gi2c->se.clk)) { +		ret = PTR_ERR(gi2c->se.clk); +		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); +		return ret; +	} + +	ret = device_property_read_u32(&pdev->dev, "clock-frequency", +							&gi2c->clk_freq_out); +	if (ret) { +		dev_info(&pdev->dev, +			"Bus frequency not specified, default to 100kHz.\n"); +		gi2c->clk_freq_out = KHZ(100); +	} + +	gi2c->irq = platform_get_irq(pdev, 0); +	if (gi2c->irq < 0) { +		dev_err(&pdev->dev, "IRQ error for i2c-geni\n"); +		return gi2c->irq; +	} + +	ret = geni_i2c_clk_map_idx(gi2c); +	if (ret) { +		dev_err(&pdev->dev, "Invalid clk frequency %d Hz: %d\n", +			gi2c->clk_freq_out, ret); +		return ret; +	} + +	gi2c->adap.algo = &geni_i2c_algo; +	init_completion(&gi2c->done); +	spin_lock_init(&gi2c->lock); +	platform_set_drvdata(pdev, gi2c); +	ret = devm_request_irq(&pdev->dev, gi2c->irq, geni_i2c_irq, +			       IRQF_TRIGGER_HIGH, "i2c_geni", gi2c); +	if (ret) { +		dev_err(&pdev->dev, "Request_irq failed:%d: err:%d\n", +			gi2c->irq, ret); +		return ret; +	} +	/* Disable the interrupt so that the system can enter low-power mode */ +	disable_irq(gi2c->irq); +	i2c_set_adapdata(&gi2c->adap, gi2c); +	gi2c->adap.dev.parent = &pdev->dev; +	gi2c->adap.dev.of_node = pdev->dev.of_node; +	strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); + +	ret = geni_se_resources_on(&gi2c->se); +	if (ret) { +		dev_err(&pdev->dev, "Error turning on resources %d\n", ret); +		return ret; +	} +	proto = geni_se_read_proto(&gi2c->se); +	tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); +	if (proto != GENI_SE_I2C) { +		dev_err(&pdev->dev, "Invalid proto %d\n", proto); +		geni_se_resources_off(&gi2c->se); +		return -ENXIO; +	} +	gi2c->tx_wm = tx_depth - 1; +	geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); +	geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW, +							true, true, true); +	ret = geni_se_resources_off(&gi2c->se); +	if (ret) { +		dev_err(&pdev->dev, "Error turning off resources %d\n", ret); +		return ret; +	} + +	dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); + +	ret = i2c_add_adapter(&gi2c->adap); +	if (ret) { +		dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret); +		return ret; +	} + +	gi2c->suspended = 1; +	pm_runtime_set_suspended(gi2c->se.dev); +	pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY); +	pm_runtime_use_autosuspend(gi2c->se.dev); +	pm_runtime_enable(gi2c->se.dev); + +	return 0; +} + +static int geni_i2c_remove(struct platform_device *pdev) +{ +	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); + +	pm_runtime_disable(gi2c->se.dev); +	i2c_del_adapter(&gi2c->adap); +	return 0; +} + +static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) +{ +	int ret; +	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + +	disable_irq(gi2c->irq); +	ret = geni_se_resources_off(&gi2c->se); +	if (ret) { +		enable_irq(gi2c->irq); +		return ret; + +	} else { +		gi2c->suspended = 1; +	} + +	return 0; +} + +static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) +{ +	int ret; +	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + +	ret = geni_se_resources_on(&gi2c->se); +	if (ret) +		return ret; + +	enable_irq(gi2c->irq); +	gi2c->suspended = 0; +	return 0; +} + +static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev) +{ +	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + +	if (!gi2c->suspended) { +		geni_i2c_runtime_suspend(dev); +		pm_runtime_disable(dev); +		pm_runtime_set_suspended(dev); +		pm_runtime_enable(dev); +	} +	return 0; +} + +static const struct dev_pm_ops geni_i2c_pm_ops = { +	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, NULL) +	SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume, +									NULL) +}; + +static const struct of_device_id geni_i2c_dt_match[] = { +	{ .compatible = "qcom,geni-i2c" }, +	{} +}; +MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); + +static struct platform_driver geni_i2c_driver = { +	.probe  = geni_i2c_probe, +	.remove = geni_i2c_remove, +	.driver = { +		.name = "geni_i2c", +		.pm = &geni_i2c_pm_ops, +		.of_match_table = geni_i2c_dt_match, +	}, +}; + +module_platform_driver(geni_i2c_driver); + +MODULE_DESCRIPTION("I2C Controller Driver for GENI based QUP cores"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 3c1c817f6968..52cf42b32f0a 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Driver for the Renesas R-Car I2C unit   * @@ -9,16 +10,8 @@   *   * This file is based on the drivers/i2c/busses/i2c-sh7760.c   * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */ +#include <linux/bitops.h>  #include <linux/clk.h>  #include <linux/delay.h>  #include <linux/dmaengine.h> @@ -112,9 +105,10 @@  #define ID_ARBLOST	(1 << 3)  #define ID_NACK		(1 << 4)  /* persistent flags */ -#define ID_P_NO_RXDMA	(1 << 30) /* HW forbids RXDMA sometimes */ -#define ID_P_PM_BLOCKED	(1 << 31) -#define ID_P_MASK	(ID_P_PM_BLOCKED | ID_P_NO_RXDMA) +#define ID_P_REP_AFTER_RD	BIT(29) +#define ID_P_NO_RXDMA		BIT(30) /* HW forbids RXDMA sometimes */ +#define ID_P_PM_BLOCKED		BIT(31) +#define ID_P_MASK		GENMASK(31, 29)  enum rcar_i2c_type {  	I2C_RCAR_GEN1, @@ -183,8 +177,6 @@ static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)  	rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);  }; -/* No get_sda, because the HW only reports its bus free logic, not SDA itself */ -  static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)  {  	struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); @@ -197,10 +189,19 @@ static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)  	rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);  }; +static int rcar_i2c_get_bus_free(struct i2c_adapter *adap) +{ +	struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + +	return !(rcar_i2c_read(priv, ICMCR) & FSDA); + +}; +  static struct i2c_bus_recovery_info rcar_i2c_bri = {  	.get_scl = rcar_i2c_get_scl,  	.set_scl = rcar_i2c_set_scl,  	.set_sda = rcar_i2c_set_sda, +	.get_bus_free = rcar_i2c_get_bus_free,  	.recover_bus = i2c_generic_scl_recovery,  };  static void rcar_i2c_init(struct rcar_i2c_priv *priv) @@ -215,7 +216,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)  static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)  { -	int i, ret; +	int i;  	for (i = 0; i < LOOP_TIMEOUT; i++) {  		/* make sure that bus is not busy */ @@ -226,13 +227,7 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)  	/* Waiting did not help, try to recover */  	priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; -	ret = i2c_recover_bus(&priv->adap); - -	/* No failure when recovering, so check bus busy bit again */ -	if (ret == 0) -		ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0; - -	return ret; +	return i2c_recover_bus(&priv->adap);  }  static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) @@ -343,7 +338,10 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)  		rcar_i2c_write(priv, ICMSR, 0);  		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);  	} else { -		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); +		if (priv->flags & ID_P_REP_AFTER_RD) +			priv->flags &= ~ID_P_REP_AFTER_RD; +		else +			rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);  		rcar_i2c_write(priv, ICMSR, 0);  	}  	rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); @@ -548,15 +546,15 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)  		priv->pos++;  	} -	/* -	 * If next received data is the _LAST_, go to STOP phase. Might be -	 * overwritten by REP START when setting up a new msg. Not elegant -	 * but the only stable sequence for REP START I have found so far. -	 * If you want to change this code, make sure sending one transfer with -	 * four messages (WR-RD-WR-RD) works! -	 */ -	if (priv->pos + 1 >= msg->len) -		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); +	/* If next received data is the _LAST_, go to new phase. */ +	if (priv->pos + 1 == msg->len) { +		if (priv->flags & ID_LAST_MSG) { +			rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); +		} else { +			rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); +			priv->flags |= ID_P_REP_AFTER_RD; +		} +	}  	if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))  		rcar_i2c_next_msg(priv); @@ -624,9 +622,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)  	struct rcar_i2c_priv *priv = ptr;  	u32 msr, val; -	/* Clear START or STOP as soon as we can */ -	val = rcar_i2c_read(priv, ICMCR); -	rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); +	/* Clear START or STOP immediately, except for REPSTART after read */ +	if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) { +		val = rcar_i2c_read(priv, ICMCR); +		rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); +	}  	msr = rcar_i2c_read(priv, ICMSR); @@ -795,14 +795,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,  	if (ret < 0)  		goto out; -	for (i = 0; i < num; i++) { -		/* This HW can't send STOP after address phase */ -		if (msgs[i].len == 0) { -			ret = -EOPNOTSUPP; -			goto out; -		} +	for (i = 0; i < num; i++)  		rcar_i2c_request_dma(priv, msgs + i); -	}  	/* init first message */  	priv->msg = msgs; @@ -889,6 +883,10 @@ static const struct i2c_algorithm rcar_i2c_algo = {  	.unreg_slave	= rcar_unreg_slave,  }; +static const struct i2c_adapter_quirks rcar_i2c_quirks = { +	.flags = I2C_AQ_NO_ZERO_LEN, +}; +  static const struct of_device_id rcar_i2c_dt_ids[] = {  	{ .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 },  	{ .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, @@ -942,6 +940,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)  	adap->dev.parent = dev;  	adap->dev.of_node = dev->of_node;  	adap->bus_recovery_info = &rcar_i2c_bri; +	adap->quirks = &rcar_i2c_quirks;  	i2c_set_adapdata(adap, priv);  	strlcpy(adap->name, pdev->name, sizeof(adap->name)); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 5f1fca7880b1..b75ff144b570 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Renesas RIIC driver   *   * Copyright (C) 2013 Wolfram Sang <[email protected]>   * Copyright (C) 2013 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation.   */  /* diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 9fe2b6951895..2f2e28d60ef5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -919,9 +919,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,  	if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||  	    (val == CPUFREQ_PRECHANGE && delta_f > 0)) { -		i2c_lock_adapter(&i2c->adap); +		i2c_lock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER);  		ret = s3c24xx_i2c_clockrate(i2c, &got); -		i2c_unlock_adapter(&i2c->adap); +		i2c_unlock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER);  		if (ret < 0)  			dev_err(i2c->dev, "cannot find frequency (%d)\n", ret); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 5fda4188a9e5..439e8778f849 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * SuperH Mobile I2C Controller   * @@ -7,15 +8,6 @@   *   * Portions of the code based on out-of-tree driver i2c-sh7343.c   * Copyright (c) 2006 Carlos Munoz <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */  #include <linux/clk.h> @@ -613,11 +605,6 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)  static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,  		    bool do_init)  { -	if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) { -		dev_err(pd->dev, "Unsupported zero length i2c read\n"); -		return -EOPNOTSUPP; -	} -  	if (do_init) {  		/* Initialize channel registers */  		iic_wr(pd, ICCR, ICCR_SCP); @@ -758,6 +745,10 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = {  	.master_xfer	= sh_mobile_i2c_xfer,  }; +static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = { +	.flags = I2C_AQ_NO_ZERO_LEN_READ, +}; +  /*   * r8a7740 chip has lasting errata on I2C I/O pad reset.   * this is work-around for it. @@ -925,6 +916,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)  	adap->owner = THIS_MODULE;  	adap->algo = &sh_mobile_i2c_algorithm; +	adap->quirks = &sh_mobile_i2c_quirks;  	adap->dev.parent = &dev->dev;  	adap->retries = 5;  	adap->nr = dev->id; diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 4053259bccb8..a94e724f51dc 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -590,9 +590,9 @@ static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev)  {  	struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); -	i2c_lock_adapter(&i2c_dev->adap); +	i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);  	i2c_dev->is_suspended = true; -	i2c_unlock_adapter(&i2c_dev->adap); +	i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);  	return pm_runtime_force_suspend(pdev);  } @@ -601,9 +601,9 @@ static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev)  {  	struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); -	i2c_lock_adapter(&i2c_dev->adap); +	i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);  	i2c_dev->is_suspended = false; -	i2c_unlock_adapter(&i2c_dev->adap); +	i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);  	return pm_runtime_force_resume(pdev);  } diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index fce52bdab2b7..5503fa171df0 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -673,12 +673,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap,  			msg->addr, msg->len, msg->flags, stop);  	} -	/* Zero-length messages are not supported by this hardware */ -	if (msg->len == 0) { -		ret = -EINVAL; -		goto exit_disable; -	} -  	/*  	 * For some reason, sending the address sometimes fails when running  	 * on  the 13 MHz clock. No interrupt arrives. This is a work around, @@ -863,6 +857,10 @@ static const struct i2c_algorithm stu300_algo = {  	.functionality	= stu300_func,  }; +static const struct i2c_adapter_quirks stu300_quirks = { +	.flags = I2C_AQ_NO_ZERO_LEN, +}; +  static int stu300_probe(struct platform_device *pdev)  {  	struct stu300_dev *dev; @@ -920,6 +918,8 @@ static int stu300_probe(struct platform_device *pdev)  	adap->algo = &stu300_algo;  	adap->dev.parent = &pdev->dev;  	adap->dev.of_node = pdev->dev.of_node; +	adap->quirks = &stu300_quirks; +  	i2c_set_adapdata(adap, dev);  	/* i2c device drivers may be active on return from add_adapter() */ diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 797def5319f1..60c8561fbe65 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -115,6 +115,18 @@  #define I2C_CONFIG_LOAD_TIMEOUT			1000000 +#define I2C_MST_FIFO_CONTROL			0x0b4 +#define I2C_MST_FIFO_CONTROL_RX_FLUSH		BIT(0) +#define I2C_MST_FIFO_CONTROL_TX_FLUSH		BIT(1) +#define I2C_MST_FIFO_CONTROL_RX_TRIG(x)		(((x) - 1) <<  4) +#define I2C_MST_FIFO_CONTROL_TX_TRIG(x)		(((x) - 1) << 16) + +#define I2C_MST_FIFO_STATUS			0x0b8 +#define I2C_MST_FIFO_STATUS_RX_MASK		0xff +#define I2C_MST_FIFO_STATUS_RX_SHIFT		0 +#define I2C_MST_FIFO_STATUS_TX_MASK		0xff0000 +#define I2C_MST_FIFO_STATUS_TX_SHIFT		16 +  /*   * msg_end_type: The bus control which need to be send at end of transfer.   * @MSG_END_STOP: Send stop pulse at end of transfer. @@ -154,6 +166,7 @@ struct tegra_i2c_hw_feature {  	u16 clk_divisor_fast_plus_mode;  	bool has_multi_master_mode;  	bool has_slcg_override_reg; +	bool has_mst_fifo;  };  /** @@ -266,13 +279,24 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)  static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)  {  	unsigned long timeout = jiffies + HZ; -	u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); +	unsigned int offset; +	u32 mask, val; + +	if (i2c_dev->hw->has_mst_fifo) { +		mask = I2C_MST_FIFO_CONTROL_TX_FLUSH | +		       I2C_MST_FIFO_CONTROL_RX_FLUSH; +		offset = I2C_MST_FIFO_CONTROL; +	} else { +		mask = I2C_FIFO_CONTROL_TX_FLUSH | +		       I2C_FIFO_CONTROL_RX_FLUSH; +		offset = I2C_FIFO_CONTROL; +	} -	val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; -	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); +	val = i2c_readl(i2c_dev, offset); +	val |= mask; +	i2c_writel(i2c_dev, val, offset); -	while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) & -		(I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) { +	while (i2c_readl(i2c_dev, offset) & mask) {  		if (time_after(jiffies, timeout)) {  			dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");  			return -ETIMEDOUT; @@ -290,9 +314,15 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)  	size_t buf_remaining = i2c_dev->msg_buf_remaining;  	int words_to_transfer; -	val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); -	rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> -		I2C_FIFO_STATUS_RX_SHIFT; +	if (i2c_dev->hw->has_mst_fifo) { +		val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); +		rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >> +			I2C_MST_FIFO_STATUS_RX_SHIFT; +	} else { +		val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); +		rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> +			I2C_FIFO_STATUS_RX_SHIFT; +	}  	/* Rounds down to not include partial word at the end of buf */  	words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; @@ -321,6 +351,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)  	BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);  	i2c_dev->msg_buf_remaining = buf_remaining;  	i2c_dev->msg_buf = buf; +  	return 0;  } @@ -332,9 +363,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)  	size_t buf_remaining = i2c_dev->msg_buf_remaining;  	int words_to_transfer; -	val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); -	tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> -		I2C_FIFO_STATUS_TX_SHIFT; +	if (i2c_dev->hw->has_mst_fifo) { +		val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); +		tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >> +			I2C_MST_FIFO_STATUS_TX_SHIFT; +	} else { +		val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); +		tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> +			I2C_FIFO_STATUS_TX_SHIFT; +	}  	/* Rounds down to not include partial word at the end of buf */  	words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; @@ -516,9 +553,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)  		i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);  	} -	val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | -		0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; -	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); +	if (i2c_dev->hw->has_mst_fifo) { +		val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) | +		      I2C_MST_FIFO_CONTROL_RX_TRIG(1); +		i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL); +	} else { +		val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | +			0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; +		i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); +	}  	err = tegra_i2c_flush_fifos(i2c_dev);  	if (err) @@ -802,6 +845,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {  	.has_config_load_reg = false,  	.has_multi_master_mode = false,  	.has_slcg_override_reg = false, +	.has_mst_fifo = false,  };  static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { @@ -814,6 +858,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {  	.has_config_load_reg = false,  	.has_multi_master_mode = false,  	.has_slcg_override_reg = false, +	.has_mst_fifo = false,  };  static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { @@ -826,6 +871,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {  	.has_config_load_reg = false,  	.has_multi_master_mode = false,  	.has_slcg_override_reg = false, +	.has_mst_fifo = false,  };  static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { @@ -838,6 +884,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {  	.has_config_load_reg = true,  	.has_multi_master_mode = false,  	.has_slcg_override_reg = true, +	.has_mst_fifo = false,  };  static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { @@ -850,10 +897,25 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {  	.has_config_load_reg = true,  	.has_multi_master_mode = true,  	.has_slcg_override_reg = true, +	.has_mst_fifo = false, +}; + +static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { +	.has_continue_xfer_support = true, +	.has_per_pkt_xfer_complete_irq = true, +	.has_single_clk_source = true, +	.clk_divisor_hs_mode = 1, +	.clk_divisor_std_fast_mode = 0x19, +	.clk_divisor_fast_plus_mode = 0x10, +	.has_config_load_reg = true, +	.has_multi_master_mode = true, +	.has_slcg_override_reg = true, +	.has_mst_fifo = true,  };  /* Match table for of_platform binding */  static const struct of_device_id tegra_i2c_of_match[] = { +	{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },  	{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },  	{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },  	{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 1f41a4f89c08..8a873975cf12 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -191,28 +191,43 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)  	if (priv->len_recv) {  		/* read length byte */  		rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + +		/* +		 * We expect at least 2 interrupts for I2C_M_RECV_LEN +		 * transactions. The length is updated during the first +		 * interrupt, and the buffer contents are only copied +		 * during subsequent interrupts. If in case the interrupts +		 * get merged we would complete the transaction without +		 * copying out the bytes from RX fifo. To avoid this now we +		 * drain the fifo as and when data is available. +		 * We drained the rlen byte already, decrement total length +		 * by one. +		 */ + +		len--;  		if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) {  			rlen = 0;	/*abort transfer */  			priv->msg_buf_remaining = 0;  			priv->msg_len = 0; -		} else { -			*buf++ = rlen; -			if (priv->client_pec) -				++rlen; /* account for error check byte */ -			/* update remaining bytes and message length */ -			priv->msg_buf_remaining = rlen; -			priv->msg_len = rlen + 1; +			xlp9xx_i2c_update_rlen(priv); +			return;  		} + +		*buf++ = rlen; +		if (priv->client_pec) +			++rlen; /* account for error check byte */ +		/* update remaining bytes and message length */ +		priv->msg_buf_remaining = rlen; +		priv->msg_len = rlen + 1;  		xlp9xx_i2c_update_rlen(priv);  		priv->len_recv = false; -	} else { -		len = min(priv->msg_buf_remaining, len); -		for (i = 0; i < len; i++, buf++) -			*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); - -		priv->msg_buf_remaining -= len;  	} +	len = min(priv->msg_buf_remaining, len); +	for (i = 0; i < len; i++, buf++) +		*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + +	priv->msg_buf_remaining -= len;  	priv->msg_buf = buf;  	if (priv->msg_buf_remaining) diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index 484bfa15d58e..34cd4b308540 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -173,9 +173,6 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv,  u16 len,  	u8 offset;  	u32 xfer; -	if (!len) -		return -EOPNOTSUPP; -  	offset = buf[0];  	xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);  	xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); @@ -241,9 +238,6 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)  	unsigned long timeout, stoptime, checktime;  	int nbytes, timedout; -	if (!len) -		return -EOPNOTSUPP; -  	xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,  			XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra);  	xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); @@ -340,6 +334,10 @@ static const struct i2c_algorithm xlr_i2c_algo = {  	.functionality	= xlr_func,  }; +static const struct i2c_adapter_quirks xlr_i2c_quirks = { +	.flags = I2C_AQ_NO_ZERO_LEN, +}; +  static const struct xlr_i2c_config xlr_i2c_config_default = {  	.status_busy	= XLR_I2C_BUS_BUSY,  	.cfg_extra	= 0, @@ -427,6 +425,7 @@ static int xlr_i2c_probe(struct platform_device *pdev)  	priv->adap.owner	= THIS_MODULE;  	priv->adap.algo_data	= priv;  	priv->adap.algo		= &xlr_i2c_algo; +	priv->adap.quirks	= &xlr_i2c_quirks;  	priv->adap.nr		= pdev->id;  	priv->adap.class	= I2C_CLASS_HWMON;  	snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 7c3b4740b94b..32affd3fa8bd 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -453,8 +453,12 @@ static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,  		else  			dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n",  				data_len, client->addr, cmd, ret); -	} else { +	/* 2 transfers must have completed successfully */ +	} else if (ret == 2) {  		memcpy(data, buffer, data_len); +		ret = 0; +	} else { +		ret = -EIO;  	}  	kfree(buffer); @@ -482,11 +486,16 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,  	msgs[0].buf = buffer;  	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -	if (ret < 0) -		dev_err(&client->adapter->dev, "i2c write failed\n");  	kfree(buffer); -	return ret; + +	if (ret < 0) { +		dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); +		return ret; +	} + +	/* 1 transfer must have completed successfully */ +	return (ret == 1) ? 0 : -EIO;  }  static acpi_status @@ -590,8 +599,6 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,  		if (action == ACPI_READ) {  			status = acpi_gsb_i2c_read_bytes(client, command,  					gsb->data, info->access_length); -			if (status > 0) -				status = 0;  		} else {  			status = acpi_gsb_i2c_write_bytes(client, command,  					gsb->data, info->access_length); diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 15c95aaa484c..f15737763608 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -62,7 +62,7 @@  /*   * core_lock protects i2c_adapter_idr, and guarantees that device detection, - * deletion of detected devices, and attach_adapter calls are serialized + * deletion of detected devices are serialized   */  static DEFINE_MUTEX(core_lock);  static DEFINE_IDR(i2c_adapter_idr); @@ -158,6 +158,22 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val)  	gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);  } +static int i2c_generic_bus_free(struct i2c_adapter *adap) +{ +	struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; +	int ret = -EOPNOTSUPP; + +	if (bri->get_bus_free) +		ret = bri->get_bus_free(adap); +	else if (bri->get_sda) +		ret = bri->get_sda(adap); + +	if (ret < 0) +		return ret; + +	return ret ? 0 : -EBUSY; +} +  /*   * We are generating clock pulses. ndelay() determines durating of clk pulses.   * We will generate clock with rate 100 KHz and so duration of both clock levels @@ -169,21 +185,28 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val)  int i2c_generic_scl_recovery(struct i2c_adapter *adap)  {  	struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; -	int i = 0, val = 1, ret = 0; +	int i = 0, scl = 1, ret;  	if (bri->prepare_recovery)  		bri->prepare_recovery(adap); -	bri->set_scl(adap, val); +	/* +	 * If we can set SDA, we will always create a STOP to ensure additional +	 * pulses will do no harm. This is achieved by letting SDA follow SCL +	 * half a cycle later. Check the 'incomplete_write_byte' fault injector +	 * for details. +	 */ +	bri->set_scl(adap, scl); +	ndelay(RECOVERY_NDELAY / 2);  	if (bri->set_sda) -		bri->set_sda(adap, 1); -	ndelay(RECOVERY_NDELAY); +		bri->set_sda(adap, scl); +	ndelay(RECOVERY_NDELAY / 2);  	/*  	 * By this time SCL is high, as we need to give 9 falling-rising edges  	 */  	while (i++ < RECOVERY_CLK_CNT * 2) { -		if (val) { +		if (scl) {  			/* SCL shouldn't be low here */  			if (!bri->get_scl(adap)) {  				dev_err(&adap->dev, @@ -191,41 +214,27 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)  				ret = -EBUSY;  				break;  			} -			/* Break if SDA is high */ -			if (bri->get_sda && bri->get_sda(adap)) -				break;  		} -		val = !val; -		bri->set_scl(adap, val); - -		/* -		 * If we can set SDA, we will always create STOP here to ensure -		 * the additional pulses will do no harm. This is achieved by -		 * letting SDA follow SCL half a cycle later. -		 */ +		scl = !scl; +		bri->set_scl(adap, scl); +		/* Creating STOP again, see above */  		ndelay(RECOVERY_NDELAY / 2);  		if (bri->set_sda) -			bri->set_sda(adap, val); +			bri->set_sda(adap, scl);  		ndelay(RECOVERY_NDELAY / 2); -	} - -	/* check if recovery actually succeeded */ -	if (bri->get_sda && !bri->get_sda(adap)) -		ret = -EBUSY; -	/* If all went well, send STOP for a sane bus state. */ -	if (ret == 0 && bri->set_sda) { -		bri->set_scl(adap, 0); -		ndelay(RECOVERY_NDELAY / 2); -		bri->set_sda(adap, 0); -		ndelay(RECOVERY_NDELAY / 2); -		bri->set_scl(adap, 1); -		ndelay(RECOVERY_NDELAY / 2); -		bri->set_sda(adap, 1); -		ndelay(RECOVERY_NDELAY / 2); +		if (scl) { +			ret = i2c_generic_bus_free(adap); +			if (ret == 0) +				break; +		}  	} +	/* If we can't check bus status, assume recovery worked */ +	if (ret == -EOPNOTSUPP) +		ret = 0; +  	if (bri->unprepare_recovery)  		bri->unprepare_recovery(adap); @@ -274,6 +283,10 @@ static void i2c_init_recovery(struct i2c_adapter *adap)  			err_str = "no {get|set}_scl() found";  			goto err;  		} +		if (!bri->set_sda && !bri->get_sda) { +			err_str = "either get_sda() or set_sda() needed"; +			goto err; +		}  	}  	return; @@ -1111,15 +1124,6 @@ static int i2c_do_add_adapter(struct i2c_driver *driver,  	/* Detect supported devices on that bus, and instantiate them */  	i2c_detect(adap, driver); -	/* Let legacy drivers scan this bus for matching devices */ -	if (driver->attach_adapter) { -		dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", -			 driver->driver.name); -		dev_warn(&adap->dev, -			 "Please use another way to instantiate your i2c_client\n"); -		/* We ignore the return code; if it fails, too bad */ -		driver->attach_adapter(adap); -	}  	return 0;  } @@ -1563,6 +1567,8 @@ void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_de  	ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns);  	if (ret && use_defaults)  		t->sda_fall_ns = t->scl_fall_ns; + +	device_property_read_u32(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns);  }  EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); @@ -1826,9 +1832,15 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs,  		if (msgs[i].flags & I2C_M_RD) {  			if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len))  				return i2c_quirk_error(adap, &msgs[i], "msg too long"); + +			if (q->flags & I2C_AQ_NO_ZERO_LEN_READ && len == 0) +				return i2c_quirk_error(adap, &msgs[i], "no zero length");  		} else {  			if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len))  				return i2c_quirk_error(adap, &msgs[i], "msg too long"); + +			if (q->flags & I2C_AQ_NO_ZERO_LEN_WRITE && len == 0) +				return i2c_quirk_error(adap, &msgs[i], "no zero length");  		}  	} diff --git a/drivers/i2c/i2c-core-slave.c b/drivers/i2c/i2c-core-slave.c index 4a78c65e9971..47a9f70a24a9 100644 --- a/drivers/i2c/i2c-core-slave.c +++ b/drivers/i2c/i2c-core-slave.c @@ -47,9 +47,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)  	client->slave_cb = slave_cb; -	i2c_lock_adapter(client->adapter); +	i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);  	ret = client->adapter->algo->reg_slave(client); -	i2c_unlock_adapter(client->adapter); +	i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);  	if (ret) {  		client->slave_cb = NULL; @@ -69,9 +69,9 @@ int i2c_slave_unregister(struct i2c_client *client)  		return -EOPNOTSUPP;  	} -	i2c_lock_adapter(client->adapter); +	i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);  	ret = client->adapter->algo->unreg_slave(client); -	i2c_unlock_adapter(client->adapter); +	i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);  	if (ret == 0)  		client->slave_cb = NULL; diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 51970bae3c4a..9cd66cabb84f 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -463,7 +463,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,  			msg[num-1].len++;  	} -	status = i2c_transfer(adapter, msg, num); +	status = __i2c_transfer(adapter, msg, num);  	if (status < 0)  		goto cleanup;  	if (status != num) { @@ -524,9 +524,24 @@ cleanup:   * This executes an SMBus protocol operation, and returns a negative   * errno code else zero on success.   */ -s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, -		   char read_write, u8 command, int protocol, -		   union i2c_smbus_data *data) +s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, +		   unsigned short flags, char read_write, +		   u8 command, int protocol, union i2c_smbus_data *data) +{ +	s32 res; + +	i2c_lock_bus(adapter, I2C_LOCK_SEGMENT); +	res = __i2c_smbus_xfer(adapter, addr, flags, read_write, +			       command, protocol, data); +	i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); + +	return res; +} +EXPORT_SYMBOL(i2c_smbus_xfer); + +s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, +		     unsigned short flags, char read_write, +		     u8 command, int protocol, union i2c_smbus_data *data)  {  	unsigned long orig_jiffies;  	int try; @@ -543,8 +558,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,  	flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;  	if (adapter->algo->smbus_xfer) { -		i2c_lock_bus(adapter, I2C_LOCK_SEGMENT); -  		/* Retry automatically on arbitration loss */  		orig_jiffies = jiffies;  		for (res = 0, try = 0; try <= adapter->retries; try++) { @@ -557,7 +570,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,  				       orig_jiffies + adapter->timeout))  				break;  		} -		i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);  		if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)  			goto trace; @@ -579,7 +591,7 @@ trace:  	return res;  } -EXPORT_SYMBOL(i2c_smbus_xfer); +EXPORT_SYMBOL(__i2c_smbus_xfer);  /**   * i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 29646aa6132e..f330690b4125 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -87,8 +87,8 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,  	ret = muxc->select(muxc, priv->chan_id);  	if (ret >= 0) -		ret = parent->algo->smbus_xfer(parent, addr, flags, -					read_write, command, size, data); +		ret = __i2c_smbus_xfer(parent, addr, flags, +				       read_write, command, size, data);  	if (muxc->deselect)  		muxc->deselect(muxc, priv->chan_id); diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 12ad8d65faf6..f2bf3e57ed67 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -94,31 +94,11 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,  				 struct i2c_client *client, u8 val)  {  	struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); -	int ret = -ENODEV; - -	if (adap->algo->master_xfer) { -		struct i2c_msg msg; -		u8 msgbuf[] = {pdata->sel_reg_addr, val}; - -		msg.addr = client->addr; -		msg.flags = 0; -		msg.len = 2; -		msg.buf = msgbuf; -		ret = __i2c_transfer(adap, &msg, 1); - -		if (ret >= 0 && ret != 1) -			ret = -EREMOTEIO; -	} else if (adap->algo->smbus_xfer) { -		union i2c_smbus_data data; - -		data.byte = val; -		ret = adap->algo->smbus_xfer(adap, client->addr, -					     client->flags, I2C_SMBUS_WRITE, -					     pdata->sel_reg_addr, -					     I2C_SMBUS_BYTE_DATA, &data); -	} +	union i2c_smbus_data data = { .byte = val }; -	return ret; +	return __i2c_smbus_xfer(adap, client->addr, client->flags, +				I2C_SMBUS_WRITE, pdata->sel_reg_addr, +				I2C_SMBUS_BYTE_DATA, &data);  }  static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 6a39adaf433f..9e75d6b9140b 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -99,31 +99,11 @@ MODULE_DEVICE_TABLE(of, pca9541_of_match);  static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)  {  	struct i2c_adapter *adap = client->adapter; -	int ret; - -	if (adap->algo->master_xfer) { -		struct i2c_msg msg; -		char buf[2]; - -		msg.addr = client->addr; -		msg.flags = 0; -		msg.len = 2; -		buf[0] = command; -		buf[1] = val; -		msg.buf = buf; -		ret = __i2c_transfer(adap, &msg, 1); -	} else { -		union i2c_smbus_data data; - -		data.byte = val; -		ret = adap->algo->smbus_xfer(adap, client->addr, -					     client->flags, -					     I2C_SMBUS_WRITE, -					     command, -					     I2C_SMBUS_BYTE_DATA, &data); -	} +	union i2c_smbus_data data = { .byte = val }; -	return ret; +	return __i2c_smbus_xfer(adap, client->addr, client->flags, +				I2C_SMBUS_WRITE, command, +				I2C_SMBUS_BYTE_DATA, &data);  }  /* @@ -133,41 +113,14 @@ static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)  static int pca9541_reg_read(struct i2c_client *client, u8 command)  {  	struct i2c_adapter *adap = client->adapter; +	union i2c_smbus_data data;  	int ret; -	u8 val; - -	if (adap->algo->master_xfer) { -		struct i2c_msg msg[2] = { -			{ -				.addr = client->addr, -				.flags = 0, -				.len = 1, -				.buf = &command -			}, -			{ -				.addr = client->addr, -				.flags = I2C_M_RD, -				.len = 1, -				.buf = &val -			} -		}; -		ret = __i2c_transfer(adap, msg, 2); -		if (ret == 2) -			ret = val; -		else if (ret >= 0) -			ret = -EIO; -	} else { -		union i2c_smbus_data data; - -		ret = adap->algo->smbus_xfer(adap, client->addr, -					     client->flags, -					     I2C_SMBUS_READ, -					     command, -					     I2C_SMBUS_BYTE_DATA, &data); -		if (!ret) -			ret = data.byte; -	} -	return ret; + +	ret = __i2c_smbus_xfer(adap, client->addr, client->flags, +			       I2C_SMBUS_READ, command, +			       I2C_SMBUS_BYTE_DATA, &data); + +	return ret ?: data.byte;  }  /* @@ -345,11 +298,11 @@ static int pca9541_probe(struct i2c_client *client,  	/*  	 * I2C accesses are unprotected here. -	 * We have to lock the adapter before releasing the bus. +	 * We have to lock the I2C segment before releasing the bus.  	 */ -	i2c_lock_adapter(adap); +	i2c_lock_bus(adap, I2C_LOCK_SEGMENT);  	pca9541_release_bus(client); -	i2c_unlock_adapter(adap); +	i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);  	/* Create mux adapter */ diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index fbc748027087..24bd9275fde5 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -220,30 +220,11 @@ MODULE_DEVICE_TABLE(of, pca954x_of_match);  static int pca954x_reg_write(struct i2c_adapter *adap,  			     struct i2c_client *client, u8 val)  { -	int ret = -ENODEV; - -	if (adap->algo->master_xfer) { -		struct i2c_msg msg; -		char buf[1]; - -		msg.addr = client->addr; -		msg.flags = 0; -		msg.len = 1; -		buf[0] = val; -		msg.buf = buf; -		ret = __i2c_transfer(adap, &msg, 1); - -		if (ret >= 0 && ret != 1) -			ret = -EREMOTEIO; -	} else { -		union i2c_smbus_data data; -		ret = adap->algo->smbus_xfer(adap, client->addr, -					     client->flags, -					     I2C_SMBUS_WRITE, -					     val, I2C_SMBUS_BYTE, &data); -	} +	union i2c_smbus_data dummy; -	return ret; +	return __i2c_smbus_xfer(adap, client->addr, client->flags, +				I2C_SMBUS_WRITE, val, +				I2C_SMBUS_BYTE, &dummy);  }  static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) @@ -368,7 +349,8 @@ static int pca954x_probe(struct i2c_client *client,  {  	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);  	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); -	struct device_node *of_node = client->dev.of_node; +	struct device *dev = &client->dev; +	struct device_node *np = dev->of_node;  	bool idle_disconnect_dt;  	struct gpio_desc *gpio;  	int num, force, class; @@ -379,8 +361,7 @@ static int pca954x_probe(struct i2c_client *client,  	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))  		return -ENODEV; -	muxc = i2c_mux_alloc(adap, &client->dev, -			     PCA954X_MAX_NCHANS, sizeof(*data), 0, +	muxc = i2c_mux_alloc(adap, dev, PCA954X_MAX_NCHANS, sizeof(*data), 0,  			     pca954x_select_chan, pca954x_deselect_mux);  	if (!muxc)  		return -ENOMEM; @@ -390,7 +371,7 @@ static int pca954x_probe(struct i2c_client *client,  	data->client = client;  	/* Reset the mux if a reset GPIO is specified. */ -	gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); +	gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);  	if (IS_ERR(gpio))  		return PTR_ERR(gpio);  	if (gpio) { @@ -400,7 +381,7 @@ static int pca954x_probe(struct i2c_client *client,  		udelay(1);  	} -	data->chip = of_device_get_match_data(&client->dev); +	data->chip = of_device_get_match_data(dev);  	if (!data->chip)  		data->chip = &chips[id->driver_data]; @@ -414,8 +395,7 @@ static int pca954x_probe(struct i2c_client *client,  		if (!ret &&  		    (id.manufacturer_id != data->chip->id.manufacturer_id ||  		     id.part_id != data->chip->id.part_id)) { -			dev_warn(&client->dev, -				 "unexpected device id %03x-%03x-%x\n", +			dev_warn(dev, "unexpected device id %03x-%03x-%x\n",  				 id.manufacturer_id, id.part_id,  				 id.die_revision);  			return -ENODEV; @@ -427,14 +407,14 @@ static int pca954x_probe(struct i2c_client *client,  	 * initializes the mux to disconnected state.  	 */  	if (i2c_smbus_write_byte(client, 0) < 0) { -		dev_warn(&client->dev, "probe failed\n"); +		dev_warn(dev, "probe failed\n");  		return -ENODEV;  	}  	data->last_chan = 0;		   /* force the first selection */ -	idle_disconnect_dt = of_node && -		of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); +	idle_disconnect_dt = np && +		of_property_read_bool(np, "i2c-mux-idle-disconnect");  	ret = pca954x_irq_setup(muxc);  	if (ret) @@ -465,7 +445,7 @@ static int pca954x_probe(struct i2c_client *client,  	}  	if (data->irq) { -		ret = devm_request_threaded_irq(&client->dev, data->client->irq, +		ret = devm_request_threaded_irq(dev, data->client->irq,  						NULL, pca954x_irq_handler,  						IRQF_ONESHOT | IRQF_SHARED,  						"pca954x", data); @@ -473,8 +453,7 @@ static int pca954x_probe(struct i2c_client *client,  			goto fail_cleanup;  	} -	dev_info(&client->dev, -		 "registered %d multiplexed busses for I2C %s %s\n", +	dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n",  		 num, data->chip->muxtype == pca954x_ismux  				? "mux" : "switch", client->name);  |