summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-at91.c12
-rw-r--r--drivers/i2c/busses/i2c-axxia.c26
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c20
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h14
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c11
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c6
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c29
-rw-r--r--drivers/i2c/busses/i2c-hix5hd2.c13
-rw-r--r--drivers/i2c/busses/i2c-i801.c5
-rw-r--r--drivers/i2c/busses/i2c-mlxcpld.c68
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c8
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c2
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c4
-rw-r--r--drivers/i2c/busses/i2c-rcar.c2
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c2
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c11
-rw-r--r--drivers/i2c/busses/i2c-stm32.c153
-rw-r--r--drivers/i2c/busses/i2c-stm32.h37
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c1045
-rw-r--r--drivers/i2c/busses/i2c-synquacer.c2
-rw-r--r--drivers/i2c/busses/i2c-viperboard.c2
-rw-r--r--drivers/i2c/busses/i2c-xiic.c4
-rw-r--r--drivers/i2c/i2c-core-acpi.c13
-rw-r--r--drivers/i2c/i2c-core-base.c4
-rw-r--r--drivers/i2c/i2c-core-of.c2
-rw-r--r--drivers/i2c/i2c-core-smbus.c2
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)) {