diff options
Diffstat (limited to 'drivers/i2c')
28 files changed, 1356 insertions, 145 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8d21b9825d71..99edffae27f6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -944,6 +944,7 @@ config I2C_STM32F4 config I2C_STM32F7 tristate "STMicroelectronics STM32F7 I2C support" depends on ARCH_STM32 || COMPILE_TEST + select I2C_SLAVE help Enable this option to add support for STM32 I2C controller embedded in STM32F7 SoCs. diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 189e34ba050f..5a869144a0c5 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -94,7 +94,8 @@ obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o -obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7.o +i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o +obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index bfd1fdff64a9..3f3e8b3bf5ff 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -518,8 +518,16 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) * the RXRDY interrupt first in order to not keep garbage data in the * Receive Holding Register for the next transfer. */ - if (irqstatus & AT91_TWI_RXRDY) - at91_twi_read_next_byte(dev); + if (irqstatus & AT91_TWI_RXRDY) { + /* + * Read all available bytes at once by polling RXRDY usable w/ + * and w/o FIFO. With FIFO enabled we could also read RXFL and + * avoid polling RXRDY. + */ + do { + at91_twi_read_next_byte(dev); + } while (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY); + } /* * When a NACK condition is detected, the I2C controller sets the NACK, diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index 13f07482ec68..12f92369888b 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -532,23 +532,23 @@ static int axxia_i2c_probe(struct platform_device *pdev) if (idev->bus_clk_rate == 0) idev->bus_clk_rate = 100000; /* default clock rate */ + ret = clk_prepare_enable(idev->i2c_clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return ret; + } + ret = axxia_i2c_init(idev); if (ret) { dev_err(&pdev->dev, "failed to initialize\n"); - return ret; + goto error_disable_clk; } ret = devm_request_irq(&pdev->dev, irq, axxia_i2c_isr, 0, pdev->name, idev); if (ret) { dev_err(&pdev->dev, "failed to claim IRQ%d\n", irq); - return ret; - } - - ret = clk_prepare_enable(idev->i2c_clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - return ret; + goto error_disable_clk; } i2c_set_adapdata(&idev->adapter, idev); @@ -563,12 +563,14 @@ static int axxia_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, idev); ret = i2c_add_adapter(&idev->adapter); - if (ret) { - clk_disable_unprepare(idev->i2c_clk); - return ret; - } + if (ret) + goto error_disable_clk; return 0; + +error_disable_clk: + clk_disable_unprepare(idev->i2c_clk); + return ret; } static int axxia_i2c_remove(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 27ebd90de43b..48914dfc8ce8 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -149,18 +149,17 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset; } -void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) -{ - dw_writel(dev, enable, DW_IC_ENABLE); -} - -void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable) +void __i2c_dw_disable(struct dw_i2c_dev *dev) { int timeout = 100; do { - __i2c_dw_enable(dev, enable); - if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) + __i2c_dw_disable_nowait(dev); + /* + * The enable status register may be unimplemented, but + * in that case this test reads zero and exits the loop. + */ + if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == 0) return; /* @@ -171,8 +170,7 @@ void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable) usleep_range(25, 250); } while (timeout--); - dev_warn(dev->dev, "timeout in %sabling adapter\n", - enable ? "en" : "dis"); + dev_warn(dev->dev, "timeout in disabling adapter\n"); } unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) @@ -277,7 +275,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap) void i2c_dw_disable(struct dw_i2c_dev *dev) { /* Disable controller */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* Disable all interupts */ dw_writel(dev, 0, DW_IC_INTR_MASK); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 8707c76b2fee..d690e648bc01 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -297,8 +297,6 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset); void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); 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); -void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); -void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); 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); @@ -309,6 +307,18 @@ u32 i2c_dw_func(struct i2c_adapter *adap); void i2c_dw_disable(struct dw_i2c_dev *dev); void i2c_dw_disable_int(struct dw_i2c_dev *dev); +static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) +{ + dw_writel(dev, 1, DW_IC_ENABLE); +} + +static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) +{ + dw_writel(dev, 0, DW_IC_ENABLE); +} + +void __i2c_dw_disable(struct dw_i2c_dev *dev); + extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); extern int i2c_dw_probe(struct dw_i2c_dev *dev); #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index fd36c39ddf4e..27436a937492 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -81,7 +81,7 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); /* Disable the adapter */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* Set standard and fast speed deviders for high/low periods */ @@ -180,7 +180,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) u32 ic_con, ic_tar = 0; /* Disable the adapter */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* If the slave address is ten bit address, enable 10BITADDR */ ic_con = dw_readl(dev, DW_IC_CON); @@ -209,7 +209,10 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) i2c_dw_disable_int(dev); /* Enable the adapter */ - __i2c_dw_enable_and_wait(dev, true); + __i2c_dw_enable(dev); + + /* Dummy read to avoid the register getting stuck on Bay Trail */ + dw_readl(dev, DW_IC_ENABLE_STATUS); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); @@ -459,7 +462,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) * additional interrupts are a hardware bug or this driver doesn't * handle them correctly yet. */ - __i2c_dw_enable(dev, false); + __i2c_dw_disable_nowait(dev); if (dev->msg_err) { ret = dev->msg_err; diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index d42558d1b002..8ce2cd368477 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -75,7 +75,7 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); /* Disable the adapter. */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* Configure SDA Hold Time if required. */ reg = dw_readl(dev, DW_IC_COMP_VERSION); @@ -119,11 +119,11 @@ static int i2c_dw_reg_slave(struct i2c_client *slave) * Set slave address in the IC_SAR register, * the address to which the DW_apb_i2c responds. */ - __i2c_dw_enable(dev, false); + __i2c_dw_disable_nowait(dev); dw_writel(dev, slave->addr, DW_IC_SAR); dev->slave = slave; - __i2c_dw_enable(dev, true); + __i2c_dw_enable(dev); dev->cmd_err = 0; dev->msg_write_idx = 0; diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 12ec8484e653..de82ad8ff534 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -707,7 +707,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct exynos5_i2c *i2c = adap->algo_data; - int i = 0, ret = 0, stop = 0; + int i, ret; if (i2c->suspended) { dev_err(i2c->dev, "HS-I2C is not initialized.\n"); @@ -718,30 +718,15 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, if (ret) return ret; - for (i = 0; i < num; i++, msgs++) { - stop = (i == num - 1); - - ret = exynos5_i2c_xfer_msg(i2c, msgs, stop); - - if (ret < 0) - goto out; - } - - if (i == num) { - ret = num; - } else { - /* Only one message, cannot access the device */ - if (i == 1) - ret = -EREMOTEIO; - else - ret = i; - - dev_warn(i2c->dev, "xfer message failed\n"); + for (i = 0; i < num; ++i) { + ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num); + if (ret) + break; } - out: clk_disable(i2c->clk); - return ret; + + return ret ?: num; } static u32 exynos5_i2c_func(struct i2c_adapter *adap) diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index bb68957d3da5..f69dd6e46f2d 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -377,17 +377,7 @@ static int hix5hd2_i2c_xfer(struct i2c_adapter *adap, goto out; } - if (i == num) { - ret = num; - } else { - /* Only one message, cannot access the device */ - if (i == 1) - ret = -EREMOTEIO; - else - ret = i; - - dev_warn(priv->dev, "xfer message failed\n"); - } + ret = num; out: pm_runtime_mark_last_busy(priv->dev); @@ -471,7 +461,6 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) goto err_clk; } - pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(priv->dev); pm_runtime_set_active(priv->dev); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index bff160d1ce3f..aa726607645e 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1710,7 +1710,7 @@ static void i801_shutdown(struct pci_dev *dev) pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int i801_suspend(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -1731,8 +1731,7 @@ static int i801_resume(struct device *dev) } #endif -static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend, - i801_resume, NULL); +static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); static struct pci_driver i801_driver = { .name = "i801_smbus", diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 4c28fa28ce76..745ed43a22d6 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -45,13 +45,16 @@ #define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) #define MLXCPLD_I2C_BUS_NUM 1 #define MLXCPLD_I2C_DATA_REG_SZ 36 +#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5) +#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) +#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) #define MLXCPLD_I2C_MAX_ADDR_LEN 4 #define MLXCPLD_I2C_RETR_NUM 2 #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ #define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ /* LPC I2C registers */ -#define MLXCPLD_LPCI2C_LPF_REG 0x0 +#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 #define MLXCPLD_LPCI2C_CTRL_REG 0x1 #define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 #define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 @@ -83,6 +86,7 @@ struct mlxcpld_i2c_priv { struct mutex lock; struct mlxcpld_i2c_curr_xfer xfer; struct device *dev; + bool smbus_block; }; static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) @@ -230,7 +234,7 @@ static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, * All upper layers currently are never use transfer with more than * 2 messages. Actually, it's also not so relevant in Mellanox systems * because of HW limitation. Max size of transfer is not more than 32 - * bytes in the current x86 LPCI2C bridge. + * or 68 bytes in the current x86 LPCI2C bridge. */ priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; @@ -295,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) { int status, i, timeout = 0; - u8 datalen; + u8 datalen, val; do { usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); @@ -324,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) * Actual read data len will be always the same as * requested len. 0xff (line pull-up) will be returned * if slave has no data to return. Thus don't read - * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. + * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of + * SMBus block read transaction data len can be different, + * check this case. */ - datalen = priv->xfer.data_len; + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, + 1); + if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) { + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, + &datalen, 1); + if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) { + dev_err(priv->dev, "Incorrect smbus block read message len\n"); + return -E2BIG; + } + } else { + datalen = priv->xfer.data_len; + } mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, priv->xfer.msg[i].buf, datalen); @@ -344,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) { int i, len = 0; - u8 cmd; + u8 cmd, val; mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, &priv->xfer.data_len, 1); - mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, - &priv->xfer.addr_width, 1); + + val = priv->xfer.addr_width; + /* Notify HW about SMBus block read transaction */ + if (priv->smbus_block && priv->xfer.msg_num >= 2 && + priv->xfer.msg[1].len == 1 && + (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) && + (priv->xfer.msg[1].flags & I2C_M_RD)) + val |= MLXCPLD_I2C_SMBUS_BLK_BIT; + + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1); for (i = 0; i < priv->xfer.msg_num; i++) { if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { @@ -425,7 +450,14 @@ static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; + struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); + + if (priv->smbus_block) + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA; + else + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_I2C_BLOCK; } static const struct i2c_algorithm mlxcpld_i2c_algo = { @@ -440,6 +472,13 @@ static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = { .max_comb_1st_msg_len = 4, }; +static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN, + .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2, + .max_comb_1st_msg_len = 4, +}; + static struct i2c_adapter mlxcpld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-mlxcpld", @@ -454,6 +493,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) { struct mlxcpld_i2c_priv *priv; int err; + u8 val; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -466,6 +506,16 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) /* Register with i2c layer */ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); + /* Read capability register */ + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1); + /* Check support for extended transaction length */ + if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT) + mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext; + /* Check support for smbus block transaction */ + if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) + priv->smbus_block = true; + if (pdev->id >= -1) + mlxcpld_i2c_adapter.nr = pdev->id; priv->adap = mlxcpld_i2c_adapter; priv->adap.dev.parent = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index cf23a746cc17..1e57f58fcb00 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -27,6 +27,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/scatterlist.h> @@ -734,7 +735,6 @@ static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c) static int mtk_i2c_probe(struct platform_device *pdev) { - const struct of_device_id *of_id; int ret = 0; struct mtk_i2c *i2c; struct clk *clk; @@ -761,11 +761,7 @@ static int mtk_i2c_probe(struct platform_device *pdev) init_completion(&i2c->msg_complete); - of_id = of_match_node(mtk_i2c_of_match, pdev->dev.of_node); - if (!of_id) - return -EINVAL; - - i2c->dev_comp = of_id->data; + i2c->dev_comp = of_device_get_match_data(&pdev->dev); i2c->adap.dev.of_node = pdev->dev.of_node; i2c->dev = &pdev->dev; i2c->adap.dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 49c7c0c91486..0ed5a41804dc 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1012,8 +1012,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_mem; } - pm_suspend_ignore_children(&adev->dev, true); - dev->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(dev->clk)) { dev_err(&adev->dev, "could not get i2c clock\n"); diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 2aa0e83174c5..dae8ac618a52 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -564,10 +564,10 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, * TODO: We could potentially loop and retry in the case * of MSP_TWI_XFER_TIMEOUT. */ - return -1; + return -EIO; } - return 0; + return num; } static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index c6915b835396..9d8d5b91220f 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -542,6 +542,8 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) * 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); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 5d97510ee48b..9fe2b6951895 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -154,8 +154,6 @@ static const struct of_device_id s3c24xx_i2c_match[] = { { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 }, { .compatible = "samsung,s3c2440-hdmiphy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, - { .compatible = "samsung,exynos5440-i2c", - .data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) }, { .compatible = "samsung,exynos5-sata-phy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) }, {}, diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index d856bc211715..5fda4188a9e5 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -899,17 +899,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; - /* Enable Runtime PM for this device. - * - * Also tell the Runtime PM core to ignore children - * for this device since it is valid for us to suspend - * this I2C master driver even though the slave devices - * on the I2C bus may not be suspended. - * - * The state of the I2C hardware bus is unaffected by - * the Runtime PM state. - */ - pm_suspend_ignore_children(&dev->dev, true); pm_runtime_enable(&dev->dev); pm_runtime_get_sync(&dev->dev); diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c new file mode 100644 index 000000000000..d75fbcbf02ef --- /dev/null +++ b/drivers/i2c/busses/i2c-stm32.c @@ -0,0 +1,153 @@ +/* + * i2c-stm32.c + * + * Copyright (C) M'boumba Cedric Madianga 2017 + * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com> + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include "i2c-stm32.h" + +/* Functions for DMA support */ +struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_addr_t phy_addr, + u32 txdr_offset, + u32 rxdr_offset) +{ + struct stm32_i2c_dma *dma; + struct dma_slave_config dma_sconfig; + int ret; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return NULL; + + /* Request and configure I2C TX dma channel */ + dma->chan_tx = dma_request_slave_channel(dev, "tx"); + if (!dma->chan_tx) { + dev_dbg(dev, "can't request DMA tx channel\n"); + ret = -EINVAL; + goto fail_al; + } + + memset(&dma_sconfig, 0, sizeof(dma_sconfig)); + dma_sconfig.dst_addr = phy_addr + txdr_offset; + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.dst_maxburst = 1; + dma_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig); + if (ret < 0) { + dev_err(dev, "can't configure tx channel\n"); + goto fail_tx; + } + + /* Request and configure I2C RX dma channel */ + dma->chan_rx = dma_request_slave_channel(dev, "rx"); + if (!dma->chan_rx) { + dev_err(dev, "can't request DMA rx channel\n"); + ret = -EINVAL; + goto fail_tx; + } + + memset(&dma_sconfig, 0, sizeof(dma_sconfig)); + dma_sconfig.src_addr = phy_addr + rxdr_offset; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 1; + dma_sconfig.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig); + if (ret < 0) { + dev_err(dev, "can't configure rx channel\n"); + goto fail_rx; + } + + init_completion(&dma->dma_complete); + + dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n", + dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); + + return dma; + +fail_rx: + dma_release_channel(dma->chan_rx); +fail_tx: + dma_release_channel(dma->chan_tx); +fail_al: + devm_kfree(dev, dma); + dev_info(dev, "can't use DMA\n"); + + return NULL; +} + +void stm32_i2c_dma_free(struct stm32_i2c_dma *dma) +{ + dma->dma_buf = 0; + dma->dma_len = 0; + + dma_release_channel(dma->chan_tx); + dma->chan_tx = NULL; + + dma_release_channel(dma->chan_rx); + dma->chan_rx = NULL; + + dma->chan_using = NULL; +} + +int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, + bool rd_wr, u32 len, u8 *buf, + dma_async_tx_callback callback, + void *dma_async_param) +{ + struct dma_async_tx_descriptor *txdesc; + struct device *chan_dev; + int ret; + + if (rd_wr) { + dma->chan_using = dma->chan_rx; + dma->dma_transfer_dir = DMA_DEV_TO_MEM; + dma->dma_data_dir = DMA_FROM_DEVICE; + } else { + dma->chan_using = dma->chan_tx; + dma->dma_transfer_dir = DMA_MEM_TO_DEV; + dma->dma_data_dir = DMA_TO_DEVICE; + } + + dma->dma_len = len; + chan_dev = dma->chan_using->device->dev; + + dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len, + dma->dma_data_dir); + if (dma_mapping_error(chan_dev, dma->dma_buf)) { + dev_err(dev, "DMA mapping failed\n"); + return -EINVAL; + } + + txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf, + dma->dma_len, + dma->dma_transfer_dir, + DMA_PREP_INTERRUPT); + if (!txdesc) { + dev_err(dev, "Not able to get desc for DMA xfer\n"); + ret = -EINVAL; + goto err; + } + + reinit_completion(&dma->dma_complete); + + txdesc->callback = callback; + txdesc->callback_param = dma_async_param; + ret = dma_submit_error(dmaengine_submit(txdesc)); + if (ret < 0) { + dev_err(dev, "DMA submit failed\n"); + goto err; + } + + dma_async_issue_pending(dma->chan_using); + + return 0; + +err: + dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len, + dma->dma_data_dir); + return ret; +} diff --git a/drivers/i2c/busses/i2c-stm32.h b/drivers/i2c/busses/i2c-stm32.h index d4f9cef251ac..868755f82f88 100644 --- a/drivers/i2c/busses/i2c-stm32.h +++ b/drivers/i2c/busses/i2c-stm32.h @@ -11,6 +11,10 @@ #ifndef _I2C_STM32_H #define _I2C_STM32_H +#include <linux/dma-direction.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> + enum stm32_i2c_speed { STM32_I2C_SPEED_STANDARD, /* 100 kHz */ STM32_I2C_SPEED_FAST, /* 400 kHz */ @@ -18,4 +22,37 @@ enum stm32_i2c_speed { STM32_I2C_SPEED_END, }; +/** + * struct stm32_i2c_dma - DMA specific data + * @chan_tx: dma channel for TX transfer + * @chan_rx: dma channel for RX transfer + * @chan_using: dma channel used for the current transfer (TX or RX) + * @dma_buf: dma buffer + * @dma_len: dma buffer len + * @dma_transfer_dir: dma transfer direction indicator + * @dma_data_dir: dma transfer mode indicator + * @dma_complete: dma transfer completion + */ +struct stm32_i2c_dma { + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + struct dma_chan *chan_using; + dma_addr_t dma_buf; + unsigned int dma_len; + enum dma_transfer_direction dma_transfer_dir; + enum dma_data_direction dma_data_dir; + struct completion dma_complete; +}; + +struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_addr_t phy_addr, + u32 txdr_offset, u32 rxdr_offset); + +void stm32_i2c_dma_free(struct stm32_i2c_dma *dma); + +int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, + bool rd_wr, u32 len, u8 *buf, + dma_async_tx_callback callback, + void *dma_async_param); + #endif /* _I2C_STM32_H */ diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index f273e28c39db..62d023e737d9 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -35,6 +35,9 @@ /* STM32F7 I2C registers */ #define STM32F7_I2C_CR1 0x00 #define STM32F7_I2C_CR2 0x04 +#define STM32F7_I2C_OAR1 0x08 +#define STM32F7_I2C_OAR2 0x0C +#define STM32F7_I2C_PECR 0x20 #define STM32F7_I2C_TIMINGR 0x10 #define STM32F7_I2C_ISR 0x18 #define STM32F7_I2C_ICR 0x1C @@ -42,6 +45,10 @@ #define STM32F7_I2C_TXDR 0x28 /* STM32F7 I2C control 1 */ +#define STM32F7_I2C_CR1_PECEN BIT(23) +#define STM32F7_I2C_CR1_SBC BIT(16) +#define STM32F7_I2C_CR1_RXDMAEN BIT(15) +#define STM32F7_I2C_CR1_TXDMAEN BIT(14) #define STM32F7_I2C_CR1_ANFOFF BIT(12) #define STM32F7_I2C_CR1_ERRIE BIT(7) #define STM32F7_I2C_CR1_TCIE BIT(6) @@ -57,34 +64,77 @@ | STM32F7_I2C_CR1_NACKIE \ | STM32F7_I2C_CR1_RXIE \ | STM32F7_I2C_CR1_TXIE) +#define STM32F7_I2C_XFER_IRQ_MASK (STM32F7_I2C_CR1_TCIE \ + | STM32F7_I2C_CR1_STOPIE \ + | STM32F7_I2C_CR1_NACKIE \ + | STM32F7_I2C_CR1_RXIE \ + | STM32F7_I2C_CR1_TXIE) /* STM32F7 I2C control 2 */ +#define STM32F7_I2C_CR2_PECBYTE BIT(26) #define STM32F7_I2C_CR2_RELOAD BIT(24) #define STM32F7_I2C_CR2_NBYTES_MASK GENMASK(23, 16) #define STM32F7_I2C_CR2_NBYTES(n) (((n) & 0xff) << 16) #define STM32F7_I2C_CR2_NACK BIT(15) #define STM32F7_I2C_CR2_STOP BIT(14) #define STM32F7_I2C_CR2_START BIT(13) +#define STM32F7_I2C_CR2_HEAD10R BIT(12) +#define STM32F7_I2C_CR2_ADD10 BIT(11) #define STM32F7_I2C_CR2_RD_WRN BIT(10) +#define STM32F7_I2C_CR2_SADD10_MASK GENMASK(9, 0) +#define STM32F7_I2C_CR2_SADD10(n) (((n) & \ + STM32F7_I2C_CR2_SADD10_MASK)) #define STM32F7_I2C_CR2_SADD7_MASK GENMASK(7, 1) #define STM32F7_I2C_CR2_SADD7(n) (((n) & 0x7f) << 1) +/* STM32F7 I2C Own Address 1 */ +#define STM32F7_I2C_OAR1_OA1EN BIT(15) +#define STM32F7_I2C_OAR1_OA1MODE BIT(10) +#define STM32F7_I2C_OAR1_OA1_10_MASK GENMASK(9, 0) +#define STM32F7_I2C_OAR1_OA1_10(n) (((n) & \ + STM32F7_I2C_OAR1_OA1_10_MASK)) +#define STM32F7_I2C_OAR1_OA1_7_MASK GENMASK(7, 1) +#define STM32F7_I2C_OAR1_OA1_7(n) (((n) & 0x7f) << 1) +#define STM32F7_I2C_OAR1_MASK (STM32F7_I2C_OAR1_OA1_7_MASK \ + | STM32F7_I2C_OAR1_OA1_10_MASK \ + | STM32F7_I2C_OAR1_OA1EN \ + | STM32F7_I2C_OAR1_OA1MODE) + +/* STM32F7 I2C Own Address 2 */ +#define STM32F7_I2C_OAR2_OA2EN BIT(15) +#define STM32F7_I2C_OAR2_OA2MSK_MASK GENMASK(10, 8) +#define STM32F7_I2C_OAR2_OA2MSK(n) (((n) & 0x7) << 8) +#define STM32F7_I2C_OAR2_OA2_7_MASK GENMASK(7, 1) +#define STM32F7_I2C_OAR2_OA2_7(n) (((n) & 0x7f) << 1) +#define STM32F7_I2C_OAR2_MASK (STM32F7_I2C_OAR2_OA2MSK_MASK \ + | STM32F7_I2C_OAR2_OA2_7_MASK \ + | STM32F7_I2C_OAR2_OA2EN) + /* STM32F7 I2C Interrupt Status */ +#define STM32F7_I2C_ISR_ADDCODE_MASK GENMASK(23, 17) +#define STM32F7_I2C_ISR_ADDCODE_GET(n) \ + (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) +#define STM32F7_I2C_ISR_DIR BIT(16) #define STM32F7_I2C_ISR_BUSY BIT(15) +#define STM32F7_I2C_ISR_PECERR BIT(11) #define STM32F7_I2C_ISR_ARLO BIT(9) #define STM32F7_I2C_ISR_BERR BIT(8) #define STM32F7_I2C_ISR_TCR BIT(7) #define STM32F7_I2C_ISR_TC BIT(6) #define STM32F7_I2C_ISR_STOPF BIT(5) #define STM32F7_I2C_ISR_NACKF BIT(4) +#define STM32F7_I2C_ISR_ADDR BIT(3) #define STM32F7_I2C_ISR_RXNE BIT(2) #define STM32F7_I2C_ISR_TXIS BIT(1) +#define STM32F7_I2C_ISR_TXE BIT(0) /* STM32F7 I2C Interrupt Clear */ +#define STM32F7_I2C_ICR_PECCF BIT(11) #define STM32F7_I2C_ICR_ARLOCF BIT(9) #define STM32F7_I2C_ICR_BERRCF BIT(8) #define STM32F7_I2C_ICR_STOPCF BIT(5) #define STM32F7_I2C_ICR_NACKCF BIT(4) +#define STM32F7_I2C_ICR_ADDRCF BIT(3) /* STM32F7 I2C Timing */ #define STM32F7_I2C_TIMINGR_PRESC(n) (((n) & 0xf) << 28) @@ -94,6 +144,8 @@ #define STM32F7_I2C_TIMINGR_SCLL(n) ((n) & 0xff) #define STM32F7_I2C_MAX_LEN 0xff +#define STM32F7_I2C_DMA_LEN_MIN 0x16 +#define STM32F7_I2C_MAX_SLAVE 0x2 #define STM32F7_I2C_DNF_DEFAULT 0 #define STM32F7_I2C_DNF_MAX 16 @@ -159,11 +211,12 @@ struct stm32f7_i2c_setup { /** * struct stm32f7_i2c_timings - private I2C output parameters - * @prec: Prescaler value + * @node: List entry + * @presc: Prescaler value * @scldel: Data setup time * @sdadel: Data hold time * @sclh: SCL high period (master mode) - * @sclh: SCL low period (master mode) + * @scll: SCL low period (master mode) */ struct stm32f7_i2c_timings { struct list_head node; @@ -176,18 +229,30 @@ struct stm32f7_i2c_timings { /** * struct stm32f7_i2c_msg - client specific data - * @addr: 8-bit slave addr, including r/w bit + * @addr: 8-bit or 10-bit slave addr, including r/w bit * @count: number of bytes to be transferred * @buf: data buffer * @result: result of the transfer * @stop: last I2C msg to be sent, i.e. STOP to be generated + * @smbus: boolean to know if the I2C IP is used in SMBus mode + * @size: type of SMBus protocol + * @read_write: direction of SMBus protocol + * SMBus block read and SMBus block write - block read process call protocols + * @smbus_buf: buffer to be used for SMBus protocol transfer. It will + * contain a maximum of 32 bytes of data + byte command + byte count + PEC + * This buffer has to be 32-bit aligned to be compliant with memory address + * register in DMA mode. */ struct stm32f7_i2c_msg { - u8 addr; + u16 addr; u32 count; u8 *buf; int result; bool stop; + bool smbus; + int size; + char read_write; + u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); }; /** @@ -204,6 +269,13 @@ struct stm32f7_i2c_msg { * @f7_msg: customized i2c msg for driver usage * @setup: I2C timing input setup * @timing: I2C computed timings + * @slave: list of slave devices registered on the I2C bus + * @slave_running: slave device currently used + * @slave_dir: transfer direction for the current slave device + * @master_mode: boolean to know in which mode the I2C is running (master or + * slave) + * @dma: dma data + * @use_dma: boolean to know if dma is used in the current transfer */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -218,6 +290,12 @@ struct stm32f7_i2c_dev { struct stm32f7_i2c_msg f7_msg; struct stm32f7_i2c_setup setup; struct stm32f7_i2c_timings timing; + struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; + struct i2c_client *slave_running; + u32 slave_dir; + bool master_mode; + struct stm32_i2c_dma *dma; + bool use_dma; }; /** @@ -283,6 +361,11 @@ static inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask) writel_relaxed(readl_relaxed(reg) & ~mask, reg); } +static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) +{ + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); +} + static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, struct stm32f7_i2c_setup *setup, struct stm32f7_i2c_timings *output) @@ -524,6 +607,25 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, return 0; } +static void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev) +{ + void __iomem *base = i2c_dev->base; + u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN; + + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); +} + +static void stm32f7_i2c_dma_callback(void *arg) +{ + struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + struct device *dev = dma->chan_using->device->dev; + + stm32f7_i2c_disable_dma_req(i2c_dev); + dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir); + complete(&dma->dma_complete); +} + static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) { struct stm32f7_i2c_timings *t = &i2c_dev->timing; @@ -567,6 +669,9 @@ static void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev) if (f7_msg->count) { *f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR); f7_msg->count--; + } else { + /* Flush RX buffer has no data is expected */ + readb_relaxed(base + STM32F7_I2C_RXDR); } } @@ -575,6 +680,9 @@ static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev) struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; u32 cr2; + if (i2c_dev->use_dma) + f7_msg->count -= STM32F7_I2C_MAX_LEN; + cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK; @@ -588,6 +696,43 @@ static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev) writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); } +static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + u32 cr2; + u8 *val; + + /* + * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first + * data received inform us how many data will follow. + */ + stm32f7_i2c_read_rx_data(i2c_dev); + + /* + * Update NBYTES with the value read to continue the transfer + */ + val = f7_msg->buf - sizeof(u8); + f7_msg->count = *val; + cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); + cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); + cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); + writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); +} + +static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); + + dev_info(i2c_dev->dev, "Trying to recover bus\n"); + + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, + STM32F7_I2C_CR1_PE); + + stm32f7_i2c_hw_config(i2c_dev); + + return 0; +} + static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) { u32 status; @@ -597,12 +742,18 @@ static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) status, !(status & STM32F7_I2C_ISR_BUSY), 10, 1000); + if (!ret) + return 0; + + dev_info(i2c_dev->dev, "bus busy\n"); + + ret = stm32f7_i2c_release_bus(&i2c_dev->adap); if (ret) { - dev_dbg(i2c_dev->dev, "bus busy\n"); - ret = -EBUSY; + dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret); + return ret; } - return ret; + return -EBUSY; } static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, @@ -611,6 +762,7 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; u32 cr1, cr2; + int ret; f7_msg->addr = msg->addr; f7_msg->buf = msg->buf; @@ -629,8 +781,15 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr2 |= STM32F7_I2C_CR2_RD_WRN; /* Set slave address */ - cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK; - cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); + cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10); + if (msg->flags & I2C_M_TEN) { + cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK; + cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr); + cr2 |= STM32F7_I2C_CR2_ADD10; + } else { + cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK; + cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); + } /* Set nb bytes to transfer and reload if needed */ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); @@ -645,16 +804,286 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE | STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE; - /* Clear TX/RX interrupt */ + /* Clear DMA req and TX/RX interrupt */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | + STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); + + /* Configure DMA or enable RX/TX interrupt */ + i2c_dev->use_dma = false; + if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + msg->flags & I2C_M_RD, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + if (!ret) + i2c_dev->use_dma = true; + else + dev_warn(i2c_dev->dev, "can't use DMA\n"); + } + + if (!i2c_dev->use_dma) { + if (msg->flags & I2C_M_RD) + cr1 |= STM32F7_I2C_CR1_RXIE; + else + cr1 |= STM32F7_I2C_CR1_TXIE; + } else { + if (msg->flags & I2C_M_RD) + cr1 |= STM32F7_I2C_CR1_RXDMAEN; + else + cr1 |= STM32F7_I2C_CR1_TXDMAEN; + } + + /* Configure Start/Repeated Start */ + cr2 |= STM32F7_I2C_CR2_START; + + i2c_dev->master_mode = true; + + /* Write configurations registers */ + writel_relaxed(cr1, base + STM32F7_I2C_CR1); + writel_relaxed(cr2, base + STM32F7_I2C_CR2); +} + +static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, + unsigned short flags, u8 command, + union i2c_smbus_data *data) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct device *dev = i2c_dev->dev; + void __iomem *base = i2c_dev->base; + u32 cr1, cr2; + int i, ret; + + f7_msg->result = 0; + reinit_completion(&i2c_dev->complete); + + cr2 = readl_relaxed(base + STM32F7_I2C_CR2); + cr1 = readl_relaxed(base + STM32F7_I2C_CR1); + + /* Set transfer direction */ + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + if (f7_msg->read_write) + cr2 |= STM32F7_I2C_CR2_RD_WRN; + + /* Set slave address */ + cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK); + cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); + + f7_msg->smbus_buf[0] = command; + switch (f7_msg->size) { + case I2C_SMBUS_QUICK: + f7_msg->stop = true; + f7_msg->count = 0; + break; + case I2C_SMBUS_BYTE: + f7_msg->stop = true; + f7_msg->count = 1; + break; + case I2C_SMBUS_BYTE_DATA: + if (f7_msg->read_write) { + f7_msg->stop = false; + f7_msg->count = 1; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + } else { + f7_msg->stop = true; + f7_msg->count = 2; + f7_msg->smbus_buf[1] = data->byte; + } + break; + case I2C_SMBUS_WORD_DATA: + if (f7_msg->read_write) { + f7_msg->stop = false; + f7_msg->count = 1; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + } else { + f7_msg->stop = true; + f7_msg->count = 3; + f7_msg->smbus_buf[1] = data->word & 0xff; + f7_msg->smbus_buf[2] = data->word >> 8; + } + break; + case I2C_SMBUS_BLOCK_DATA: + if (f7_msg->read_write) { + f7_msg->stop = false; + f7_msg->count = 1; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + } else { + f7_msg->stop = true; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX || + !data->block[0]) { + dev_err(dev, "Invalid block write size %d\n", + data->block[0]); + return -EINVAL; + } + f7_msg->count = data->block[0] + 2; + for (i = 1; i < f7_msg->count; i++) + f7_msg->smbus_buf[i] = data->block[i - 1]; + } + break; + case I2C_SMBUS_PROC_CALL: + f7_msg->stop = false; + f7_msg->count = 3; + f7_msg->smbus_buf[1] = data->word & 0xff; + f7_msg->smbus_buf[2] = data->word >> 8; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + f7_msg->read_write = I2C_SMBUS_READ; + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + f7_msg->stop = false; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) { + dev_err(dev, "Invalid block write size %d\n", + data->block[0]); + return -EINVAL; + } + f7_msg->count = data->block[0] + 2; + for (i = 1; i < f7_msg->count; i++) + f7_msg->smbus_buf[i] = data->block[i - 1]; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + f7_msg->read_write = I2C_SMBUS_READ; + break; + default: + dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size); + return -EOPNOTSUPP; + } + + f7_msg->buf = f7_msg->smbus_buf; + + /* Configure PEC */ + if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) { + cr1 |= STM32F7_I2C_CR1_PECEN; + cr2 |= STM32F7_I2C_CR2_PECBYTE; + if (!f7_msg->read_write) + f7_msg->count++; + } else { + cr1 &= ~STM32F7_I2C_CR1_PECEN; + cr2 &= ~STM32F7_I2C_CR2_PECBYTE; + } + + /* Set number of bytes to be transferred */ + cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); + cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); + + /* Enable NACK, STOP, error and transfer complete interrupts */ + cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE | + STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE; + + /* Clear DMA req and TX/RX interrupt */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | + STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); + + /* Configure DMA or enable RX/TX interrupt */ + i2c_dev->use_dma = false; + if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + cr2 & STM32F7_I2C_CR2_RD_WRN, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + if (!ret) + i2c_dev->use_dma = true; + else + dev_warn(i2c_dev->dev, "can't use DMA\n"); + } + + if (!i2c_dev->use_dma) { + if (cr2 & STM32F7_I2C_CR2_RD_WRN) + cr1 |= STM32F7_I2C_CR1_RXIE; + else + cr1 |= STM32F7_I2C_CR1_TXIE; + } else { + if (cr2 & STM32F7_I2C_CR2_RD_WRN) + cr1 |= STM32F7_I2C_CR1_RXDMAEN; + else + cr1 |= STM32F7_I2C_CR1_TXDMAEN; + } + + /* Set Start bit */ + cr2 |= STM32F7_I2C_CR2_START; + + i2c_dev->master_mode = true; + + /* Write configurations registers */ + writel_relaxed(cr1, base + STM32F7_I2C_CR1); + writel_relaxed(cr2, base + STM32F7_I2C_CR2); + + return 0; +} + +static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + void __iomem *base = i2c_dev->base; + u32 cr1, cr2; + int ret; + + cr2 = readl_relaxed(base + STM32F7_I2C_CR2); + cr1 = readl_relaxed(base + STM32F7_I2C_CR1); + + /* Set transfer direction */ + cr2 |= STM32F7_I2C_CR2_RD_WRN; + + switch (f7_msg->size) { + case I2C_SMBUS_BYTE_DATA: + f7_msg->count = 1; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + f7_msg->count = 2; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + f7_msg->count = 1; + cr2 |= STM32F7_I2C_CR2_RELOAD; + break; + } + + f7_msg->buf = f7_msg->smbus_buf; + f7_msg->stop = true; + + /* Add one byte for PEC if needed */ + if (cr1 & STM32F7_I2C_CR1_PECEN) + f7_msg->count++; + + /* Set number of bytes to be transferred */ + cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK); + cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); + + /* + * Configure RX/TX interrupt: + */ cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); + cr1 |= STM32F7_I2C_CR1_RXIE; - /* Enable RX/TX interrupt according to msg direction */ - if (msg->flags & I2C_M_RD) + /* + * Configure DMA or enable RX/TX interrupt: + * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use + * dma as we don't know in advance how many data will be received + */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | + STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); + + i2c_dev->use_dma = false; + if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN && + f7_msg->size != I2C_SMBUS_BLOCK_DATA && + f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) { + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + cr2 & STM32F7_I2C_CR2_RD_WRN, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + + if (!ret) + i2c_dev->use_dma = true; + else + dev_warn(i2c_dev->dev, "can't use DMA\n"); + } + + if (!i2c_dev->use_dma) cr1 |= STM32F7_I2C_CR1_RXIE; else - cr1 |= STM32F7_I2C_CR1_TXIE; + cr1 |= STM32F7_I2C_CR1_RXDMAEN; - /* Configure Start/Repeated Start */ + /* Configure Repeated Start */ cr2 |= STM32F7_I2C_CR2_START; /* Write configurations registers */ @@ -662,9 +1091,278 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, writel_relaxed(cr2, base + STM32F7_I2C_CR2); } -static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) +static int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev) { - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + u8 count, internal_pec, received_pec; + + internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR); + + switch (f7_msg->size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + received_pec = f7_msg->smbus_buf[1]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + received_pec = f7_msg->smbus_buf[2]; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + count = f7_msg->smbus_buf[0]; + received_pec = f7_msg->smbus_buf[count]; + break; + default: + dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n"); + return -EINVAL; + } + + if (internal_pec != received_pec) { + dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n", + internal_pec, received_pec); + return -EBADMSG; + } + + return 0; +} + +static bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode) +{ + u32 addr; + + if (!slave) + return false; + + if (slave->flags & I2C_CLIENT_TEN) { + /* + * For 10-bit addr, addcode = 11110XY with + * X = Bit 9 of slave address + * Y = Bit 8 of slave address + */ + addr = slave->addr >> 8; + addr |= 0x78; + if (addr == addcode) + return true; + } else { + addr = slave->addr & 0x7f; + if (addr == addcode) + return true; + } + + return false; +} + +static void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev) +{ + struct i2c_client *slave = i2c_dev->slave_running; + void __iomem *base = i2c_dev->base; + u32 mask; + u8 value = 0; + + if (i2c_dev->slave_dir) { + /* Notify i2c slave that new read transfer is starting */ + i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); + + /* + * Disable slave TX config in case of I2C combined message + * (I2C Write followed by I2C Read) + */ + mask = STM32F7_I2C_CR2_RELOAD; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask); + mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE | + STM32F7_I2C_CR1_TCIE; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); + + /* Enable TX empty, STOP, NACK interrupts */ + mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE | + STM32F7_I2C_CR1_TXIE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + + } else { + /* Notify i2c slave that new write transfer is starting */ + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); + + /* Set reload mode to be able to ACK/NACK each received byte */ + mask = STM32F7_I2C_CR2_RELOAD; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); + + /* + * Set STOP, NACK, RX empty and transfer complete interrupts.* + * Set Slave Byte Control to be able to ACK/NACK each data + * byte received + */ + mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE | + STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE | + STM32F7_I2C_CR1_TCIE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + } +} + +static void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev) +{ + void __iomem *base = i2c_dev->base; + u32 isr, addcode, dir, mask; + int i; + + isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr); + dir = isr & STM32F7_I2C_ISR_DIR; + + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) { + i2c_dev->slave_running = i2c_dev->slave[i]; + i2c_dev->slave_dir = dir; + + /* Start I2C slave processing */ + stm32f7_i2c_slave_start(i2c_dev); + + /* Clear ADDR flag */ + mask = STM32F7_I2C_ICR_ADDRCF; + writel_relaxed(mask, base + STM32F7_I2C_ICR); + break; + } + } +} + +static int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev, + struct i2c_client *slave, int *id) +{ + int i; + + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i2c_dev->slave[i] == slave) { + *id = i; + return 0; + } + } + + dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr); + + return -ENODEV; +} + +static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, + struct i2c_client *slave, int *id) +{ + struct device *dev = i2c_dev->dev; + int i; + + /* + * slave[0] supports 7-bit and 10-bit slave address + * slave[1] supports 7-bit slave address only + */ + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i == 1 && (slave->flags & I2C_CLIENT_PEC)) + continue; + if (!i2c_dev->slave[i]) { + *id = i; + return 0; + } + } + + dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr); + + return -EINVAL; +} + +static bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev) +{ + int i; + + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i2c_dev->slave[i]) + return true; + } + + return false; +} + +static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev) +{ + int i, busy; + + busy = 0; + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i2c_dev->slave[i]) + busy++; + } + + return i == busy; +} + +static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) +{ + void __iomem *base = i2c_dev->base; + u32 cr2, status, mask; + u8 val; + int ret; + + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + + /* Slave transmitter mode */ + if (status & STM32F7_I2C_ISR_TXIS) { + i2c_slave_event(i2c_dev->slave_running, + I2C_SLAVE_READ_PROCESSED, + &val); + + /* Write data byte */ + writel_relaxed(val, base + STM32F7_I2C_TXDR); + } + + /* Transfer Complete Reload for Slave receiver mode */ + if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) { + /* + * Read data byte then set NBYTES to receive next byte or NACK + * the current received byte + */ + val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR); + ret = i2c_slave_event(i2c_dev->slave_running, + I2C_SLAVE_WRITE_RECEIVED, + &val); + if (!ret) { + cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); + cr2 |= STM32F7_I2C_CR2_NBYTES(1); + writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); + } else { + mask = STM32F7_I2C_CR2_NACK; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); + } + } + + /* NACK received */ + if (status & STM32F7_I2C_ISR_NACKF) { + dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__); + writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); + } + + /* STOP received */ + if (status & STM32F7_I2C_ISR_STOPF) { + /* Disable interrupts */ + stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK); + + if (i2c_dev->slave_dir) { + /* + * Flush TX buffer in order to not used the byte in + * TXDR for the next transfer + */ + mask = STM32F7_I2C_ISR_TXE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask); + } + + /* Clear STOP flag */ + writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); + + /* Notify i2c slave that a STOP flag has been detected */ + i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val); + + i2c_dev->slave_running = NULL; + } + + /* Address match received */ + if (status & STM32F7_I2C_ISR_ADDR) + stm32f7_i2c_slave_addr(i2c_dev); + + return IRQ_HANDLED; } static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) @@ -673,6 +1371,13 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; u32 status, mask; + int ret = IRQ_HANDLED; + + /* Check if the interrupt if for a slave device */ + if (!i2c_dev->master_mode) { + ret = stm32f7_i2c_slave_isr_event(i2c_dev); + return ret; + } status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -694,12 +1399,21 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) /* STOP detection flag */ if (status & STM32F7_I2C_ISR_STOPF) { /* Disable interrupts */ - stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); /* Clear STOP flag */ writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - complete(&i2c_dev->complete); + if (i2c_dev->use_dma) { + ret = IRQ_WAKE_THREAD; + } else { + i2c_dev->master_mode = false; + complete(&i2c_dev->complete); + } } /* Transfer complete */ @@ -707,6 +1421,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) if (f7_msg->stop) { mask = STM32F7_I2C_CR2_STOP; stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); + } else if (i2c_dev->use_dma) { + ret = IRQ_WAKE_THREAD; + } else if (f7_msg->smbus) { + stm32f7_i2c_smbus_rep_start(i2c_dev); } else { i2c_dev->msg_id++; i2c_dev->msg++; @@ -714,13 +1432,50 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) } } + if (status & STM32F7_I2C_ISR_TCR) { + if (f7_msg->smbus) + stm32f7_i2c_smbus_reload(i2c_dev); + else + stm32f7_i2c_reload(i2c_dev); + } + + return ret; +} + +static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) +{ + struct stm32f7_i2c_dev *i2c_dev = data; + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + u32 status; + int ret; + /* - * Transfer Complete Reload: 255 data bytes have been transferred - * We have to prepare the I2C controller to transfer the remaining - * data. + * Wait for dma transfer completion before sending next message or + * notity the end of xfer to the client */ - if (status & STM32F7_I2C_ISR_TCR) - stm32f7_i2c_reload(i2c_dev); + ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); + if (!ret) { + dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); + stm32f7_i2c_disable_dma_req(i2c_dev); + dmaengine_terminate_all(dma->chan_using); + f7_msg->result = -ETIMEDOUT; + } + + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + + if (status & STM32F7_I2C_ISR_TC) { + if (f7_msg->smbus) { + stm32f7_i2c_smbus_rep_start(i2c_dev); + } else { + i2c_dev->msg_id++; + i2c_dev->msg++; + stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg); + } + } else { + i2c_dev->master_mode = false; + complete(&i2c_dev->complete); + } return IRQ_HANDLED; } @@ -731,7 +1486,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; struct device *dev = i2c_dev->dev; - u32 status; + struct stm32_i2c_dma *dma = i2c_dev->dma; + u32 mask, status; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -739,6 +1495,7 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) if (status & STM32F7_I2C_ISR_BERR) { dev_err(dev, "<%s>: Bus error\n", __func__); writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); + stm32f7_i2c_release_bus(&i2c_dev->adap); f7_msg->result = -EIO; } @@ -749,8 +1506,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) f7_msg->result = -EAGAIN; } - stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); + if (status & STM32F7_I2C_ISR_PECERR) { + dev_err(dev, "<%s>: PEC error in reception\n", __func__); + writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); + f7_msg->result = -EINVAL; + } + + /* Disable interrupts */ + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); + + /* Disable dma */ + if (i2c_dev->use_dma) { + stm32f7_i2c_disable_dma_req(i2c_dev); + dmaengine_terminate_all(dma->chan_using); + } + i2c_dev->master_mode = false; complete(&i2c_dev->complete); return IRQ_HANDLED; @@ -761,12 +1536,14 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; unsigned long time_left; int ret; i2c_dev->msg = msgs; i2c_dev->msg_num = num; i2c_dev->msg_id = 0; + f7_msg->smbus = false; ret = clk_enable(i2c_dev->clk); if (ret) { @@ -787,6 +1564,8 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, if (!time_left) { dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", i2c_dev->msg->addr); + if (i2c_dev->use_dma) + dmaengine_terminate_all(dma->chan_using); ret = -ETIMEDOUT; } @@ -796,14 +1575,209 @@ clk_free: return (ret < 0) ? ret : num; } +static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, + union i2c_smbus_data *data) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter); + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + struct device *dev = i2c_dev->dev; + unsigned long timeout; + int i, ret; + + f7_msg->addr = addr; + f7_msg->size = size; + f7_msg->read_write = read_write; + f7_msg->smbus = true; + + ret = clk_enable(i2c_dev->clk); + if (ret) { + dev_err(i2c_dev->dev, "Failed to enable clock\n"); + return ret; + } + + ret = stm32f7_i2c_wait_free_bus(i2c_dev); + if (ret) + goto clk_free; + + ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data); + if (ret) + goto clk_free; + + timeout = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); + ret = f7_msg->result; + if (ret) + goto clk_free; + + if (!timeout) { + dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); + if (i2c_dev->use_dma) + dmaengine_terminate_all(dma->chan_using); + ret = -ETIMEDOUT; + goto clk_free; + } + + /* Check PEC */ + if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) { + ret = stm32f7_i2c_smbus_check_pec(i2c_dev); + if (ret) + goto clk_free; + } + + if (read_write && size != I2C_SMBUS_QUICK) { + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = f7_msg->smbus_buf[0]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = f7_msg->smbus_buf[0] | + (f7_msg->smbus_buf[1] << 8); + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + for (i = 0; i <= f7_msg->smbus_buf[0]; i++) + data->block[i] = f7_msg->smbus_buf[i]; + break; + default: + dev_err(dev, "Unsupported smbus transaction\n"); + ret = -EINVAL; + } + } + +clk_free: + clk_disable(i2c_dev->clk); + return ret; +} + +static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); + void __iomem *base = i2c_dev->base; + struct device *dev = i2c_dev->dev; + u32 oar1, oar2, mask; + int id, ret; + + if (slave->flags & I2C_CLIENT_PEC) { + dev_err(dev, "SMBus PEC not supported in slave mode\n"); + return -EINVAL; + } + + if (stm32f7_i2c_is_slave_busy(i2c_dev)) { + dev_err(dev, "Too much slave registered\n"); + return -EBUSY; + } + + ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id); + if (ret) + return ret; + + if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) { + ret = clk_enable(i2c_dev->clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + } + + if (id == 0) { + /* Configure Own Address 1 */ + oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); + oar1 &= ~STM32F7_I2C_OAR1_MASK; + if (slave->flags & I2C_CLIENT_TEN) { + oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr); + oar1 |= STM32F7_I2C_OAR1_OA1MODE; + } else { + oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr); + } + oar1 |= STM32F7_I2C_OAR1_OA1EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1); + } else if (id == 1) { + /* Configure Own Address 2 */ + oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); + oar2 &= ~STM32F7_I2C_OAR2_MASK; + if (slave->flags & I2C_CLIENT_TEN) { + ret = -EOPNOTSUPP; + goto exit; + } + + oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr); + oar2 |= STM32F7_I2C_OAR2_OA2EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); + } else { + ret = -ENODEV; + goto exit; + } + + /* Enable ACK */ + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK); + + /* Enable Address match interrupt, error interrupt and enable I2C */ + mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE | + STM32F7_I2C_CR1_PE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + + return 0; + +exit: + if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) + clk_disable(i2c_dev->clk); + + return ret; +} + +static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); + void __iomem *base = i2c_dev->base; + u32 mask; + int id, ret; + + ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id); + if (ret) + return ret; + + WARN_ON(!i2c_dev->slave[id]); + + if (id == 0) { + mask = STM32F7_I2C_OAR1_OA1EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); + } else { + mask = STM32F7_I2C_OAR2_OA2EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask); + } + + i2c_dev->slave[id] = NULL; + + if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) { + stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); + clk_disable(i2c_dev->clk); + } + + return 0; +} + static u32 stm32f7_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE | + I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC; } static struct i2c_algorithm stm32f7_i2c_algo = { .master_xfer = stm32f7_i2c_xfer, + .smbus_xfer = stm32f7_i2c_smbus_xfer, .functionality = stm32f7_i2c_func, + .reg_slave = stm32f7_i2c_reg_slave, + .unreg_slave = stm32f7_i2c_unreg_slave, }; static int stm32f7_i2c_probe(struct platform_device *pdev) @@ -815,6 +1789,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) u32 irq_error, irq_event, clk_rate, rise_time, fall_time; struct i2c_adapter *adap; struct reset_control *rst; + dma_addr_t phy_addr; int ret; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); @@ -825,6 +1800,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); + phy_addr = (dma_addr_t)res->start; irq_event = irq_of_parse_and_map(np, 0); if (!irq_event) { @@ -871,8 +1847,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->dev = &pdev->dev; - ret = devm_request_irq(&pdev->dev, irq_event, stm32f7_i2c_isr_event, 0, - pdev->name, i2c_dev); + ret = devm_request_threaded_irq(&pdev->dev, irq_event, + stm32f7_i2c_isr_event, + stm32f7_i2c_isr_event_thread, + IRQF_ONESHOT, + pdev->name, i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to request irq event %i\n", irq_event); @@ -924,6 +1903,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->complete); + /* Init DMA config if supported */ + i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr, + STM32F7_I2C_TXDR, + STM32F7_I2C_RXDR); + ret = i2c_add_adapter(adap); if (ret) goto clk_free; @@ -946,6 +1930,11 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) { struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + if (i2c_dev->dma) { + stm32_i2c_dma_free(i2c_dev->dma); + i2c_dev->dma = NULL; + } + i2c_del_adapter(&i2c_dev->adap); clk_unprepare(i2c_dev->clk); diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index a021f866d8c2..915f5edbab33 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -509,7 +509,7 @@ static int synquacer_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, dev_dbg(i2c->dev, "calculated timeout %d ms\n", i2c->timeout_ms); - for (retry = 0; retry < adap->retries; retry++) { + for (retry = 0; retry <= adap->retries; retry++) { ret = synquacer_i2c_doxfer(i2c, msgs, num); if (ret != -EAGAIN) return ret; diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index e4be86b3de9a..7235c7302bb7 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -337,7 +337,7 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, } mutex_unlock(&vb->lock); } - return 0; + return num; error: mutex_unlock(&vb->lock); return error; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 0ff36f6d7a57..e3161fe048eb 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -415,7 +415,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) clr |= XIIC_INTR_RX_FULL_MASK; if (!i2c->rx_msg) { dev_dbg(i2c->adap.dev.parent, - "%s unexpexted RX IRQ\n", __func__); + "%s unexpected RX IRQ\n", __func__); xiic_clear_rx_fifo(i2c); goto out; } @@ -470,7 +470,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) if (!i2c->tx_msg) { dev_dbg(i2c->adap.dev.parent, - "%s unexpexted TX IRQ\n", __func__); + "%s unexpected TX IRQ\n", __func__); goto out; } diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index a9126b3cda61..7c3b4740b94b 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -445,10 +445,17 @@ static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, msgs[1].buf = buffer; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c read failed\n"); - else + if (ret < 0) { + /* Getting a NACK is unfortunately normal with some DSTDs */ + if (ret == -EREMOTEIO) + dev_dbg(&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 + 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 { memcpy(data, buffer, data_len); + } kfree(buffer); return ret; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 1ba40bb2b966..a407022fdc76 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -717,10 +717,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->adapter = adap; client->dev.platform_data = info->platform_data; - - if (info->archdata) - client->dev.archdata = *info->archdata; - client->flags = info->flags; client->addr = info->addr; diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index c405270a98b4..15bd51eca37b 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -27,7 +27,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, { struct i2c_client *client; struct i2c_board_info info = {}; - struct dev_archdata dev_ad = {}; u32 addr; int ret; @@ -56,7 +55,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, } info.addr = addr; - info.archdata = &dev_ad; info.of_node = of_node_get(node); if (of_property_read_bool(node, "host-notify")) diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index b5aec33002c3..f3f683041e7f 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -466,6 +466,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, status = i2c_transfer(adapter, msg, num); if (status < 0) return status; + if (status != num) + return -EIO; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { |