aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-at91-master.c1
-rw-r--r--drivers/i2c/busses/i2c-at91.h2
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h98
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c5
-rw-r--r--drivers/i2c/busses/i2c-imx.c259
-rw-r--r--drivers/i2c/busses/i2c-ismt.c19
-rw-r--r--drivers/i2c/busses/i2c-mlxbf.c12
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c29
-rw-r--r--drivers/i2c/busses/i2c-mxs.c22
-rw-r--r--drivers/i2c/busses/i2c-nvidia-gpu.c10
-rw-r--r--drivers/i2c/busses/i2c-ocores.c25
-rw-r--r--drivers/i2c/busses/i2c-owl.c75
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c4
-rw-r--r--drivers/i2c/busses/i2c-pxa.c76
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c4
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c18
-rw-r--r--drivers/i2c/busses/i2c-qup.c3
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c28
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c4
-rw-r--r--drivers/i2c/i2c-core-base.c14
21 files changed, 451 insertions, 259 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index a97a9d058198..d4d60ad0eda0 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -675,6 +675,7 @@ config I2C_IMG
config I2C_IMX
tristate "IMX I2C interface"
depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
+ select I2C_SLAVE
help
Say Y here if you want to use the IIC bus controller on
the Freescale i.MX/MXC, Layerscape or ColdFire processors.
@@ -734,6 +735,7 @@ config I2C_LPC2K
config I2C_MLXBF
tristate "Mellanox BlueField I2C controller"
depends on MELLANOX_PLATFORM && ARM64
+ select I2C_SLAVE
help
Enabling this option will add I2C SMBus support for Mellanox BlueField
system.
diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c
index 66864f9cf7ac..1cceb6866689 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -26,7 +26,6 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/dma-atmel.h>
#include <linux/pm_runtime.h>
#include "i2c-at91.h"
diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
index eae673ae786c..942e9c3973bb 100644
--- a/drivers/i2c/busses/i2c-at91.h
+++ b/drivers/i2c/busses/i2c-at91.h
@@ -18,7 +18,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/i2c.h>
-#include <linux/platform_data/dma-atmel.h>
#include <linux/platform_device.h>
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
@@ -123,7 +122,6 @@ struct at91_twi_pdata {
bool has_adv_dig_filtr;
bool has_ana_filtr;
bool has_clear_cmd;
- struct at_dma_slave dma_slave;
};
struct at91_twi_dma {
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index eb5ef4d0f463..85307cfa7109 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -25,25 +25,25 @@
I2C_FUNC_SMBUS_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
-#define DW_IC_CON_MASTER 0x1
-#define DW_IC_CON_SPEED_STD 0x2
-#define DW_IC_CON_SPEED_FAST 0x4
-#define DW_IC_CON_SPEED_HIGH 0x6
-#define DW_IC_CON_SPEED_MASK 0x6
-#define DW_IC_CON_10BITADDR_SLAVE 0x8
-#define DW_IC_CON_10BITADDR_MASTER 0x10
-#define DW_IC_CON_RESTART_EN 0x20
-#define DW_IC_CON_SLAVE_DISABLE 0x40
-#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80
-#define DW_IC_CON_TX_EMPTY_CTRL 0x100
-#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
+#define DW_IC_CON_MASTER BIT(0)
+#define DW_IC_CON_SPEED_STD (1 << 1)
+#define DW_IC_CON_SPEED_FAST (2 << 1)
+#define DW_IC_CON_SPEED_HIGH (3 << 1)
+#define DW_IC_CON_SPEED_MASK GENMASK(2, 1)
+#define DW_IC_CON_10BITADDR_SLAVE BIT(3)
+#define DW_IC_CON_10BITADDR_MASTER BIT(4)
+#define DW_IC_CON_RESTART_EN BIT(5)
+#define DW_IC_CON_SLAVE_DISABLE BIT(6)
+#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7)
+#define DW_IC_CON_TX_EMPTY_CTRL BIT(8)
+#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9)
/*
* Registers offset
*/
-#define DW_IC_CON 0x0
-#define DW_IC_TAR 0x4
-#define DW_IC_SAR 0x8
+#define DW_IC_CON 0x00
+#define DW_IC_TAR 0x04
+#define DW_IC_SAR 0x08
#define DW_IC_DATA_CMD 0x10
#define DW_IC_SS_SCL_HCNT 0x14
#define DW_IC_SS_SCL_LCNT 0x18
@@ -81,19 +81,19 @@
#define DW_IC_COMP_TYPE 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140
-#define DW_IC_INTR_RX_UNDER 0x001
-#define DW_IC_INTR_RX_OVER 0x002
-#define DW_IC_INTR_RX_FULL 0x004
-#define DW_IC_INTR_TX_OVER 0x008
-#define DW_IC_INTR_TX_EMPTY 0x010
-#define DW_IC_INTR_RD_REQ 0x020
-#define DW_IC_INTR_TX_ABRT 0x040
-#define DW_IC_INTR_RX_DONE 0x080
-#define DW_IC_INTR_ACTIVITY 0x100
-#define DW_IC_INTR_STOP_DET 0x200
-#define DW_IC_INTR_START_DET 0x400
-#define DW_IC_INTR_GEN_CALL 0x800
-#define DW_IC_INTR_RESTART_DET 0x1000
+#define DW_IC_INTR_RX_UNDER BIT(0)
+#define DW_IC_INTR_RX_OVER BIT(1)
+#define DW_IC_INTR_RX_FULL BIT(2)
+#define DW_IC_INTR_TX_OVER BIT(3)
+#define DW_IC_INTR_TX_EMPTY BIT(4)
+#define DW_IC_INTR_RD_REQ BIT(5)
+#define DW_IC_INTR_TX_ABRT BIT(6)
+#define DW_IC_INTR_RX_DONE BIT(7)
+#define DW_IC_INTR_ACTIVITY BIT(8)
+#define DW_IC_INTR_STOP_DET BIT(9)
+#define DW_IC_INTR_START_DET BIT(10)
+#define DW_IC_INTR_GEN_CALL BIT(11)
+#define DW_IC_INTR_RESTART_DET BIT(12)
#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
DW_IC_INTR_TX_ABRT | \
@@ -105,13 +105,13 @@
DW_IC_INTR_RX_UNDER | \
DW_IC_INTR_RD_REQ)
-#define DW_IC_STATUS_ACTIVITY 0x1
+#define DW_IC_STATUS_ACTIVITY BIT(0)
#define DW_IC_STATUS_TFE BIT(2)
#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
#define DW_IC_SDA_HOLD_RX_SHIFT 16
-#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
+#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16)
#define DW_IC_ERR_TX_ABRT 0x1
@@ -154,20 +154,20 @@
#define ABRT_SLAVE_ARBLOST 14
#define ABRT_SLAVE_RD_INTX 15
-#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
-#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
-#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
-#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
-#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
-#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
-#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
-#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
-#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
-#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
-#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
-#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX)
-#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST)
-#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO)
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK BIT(ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK BIT(ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK BIT(ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ BIT(ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET BIT(ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT BIT(ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT BIT(ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS BIT(ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST BIT(ARB_LOST)
+#define DW_IC_RX_ABRT_SLAVE_RD_INTX BIT(ABRT_SLAVE_RD_INTX)
+#define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST)
+#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO)
#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
DW_IC_TX_ABRT_10ADDR1_NOACK | \
@@ -288,12 +288,12 @@ struct dw_i2c_dev {
bool suspended;
};
-#define ACCESS_INTR_MASK 0x00000001
-#define ACCESS_NO_IRQ_SUSPEND 0x00000002
+#define ACCESS_INTR_MASK BIT(0)
+#define ACCESS_NO_IRQ_SUSPEND BIT(1)
-#define MODEL_MSCC_OCELOT 0x00000100
-#define MODEL_BAIKAL_BT1 0x00000200
-#define MODEL_MASK 0x00000f00
+#define MODEL_MSCC_OCELOT BIT(8)
+#define MODEL_BAIKAL_BT1 BIT(9)
+#define MODEL_MASK GENMASK(11, 8)
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 6ce3ec03b595..20a9881a0d6c 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -778,11 +778,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
init_completion(&i2c->msg_complete);
i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
- ret = -EINVAL;
+ if (ret < 0)
goto err_clk;
- }
ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq,
IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index c98529c76348..b444fbf1a262 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -17,6 +17,7 @@
* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
*
* Copyright 2013 Freescale Semiconductor, Inc.
+ * Copyright 2020 NXP
*
*/
@@ -73,6 +74,11 @@
#define IMX_I2C_I2SR 0x03 /* i2c status */
#define IMX_I2C_I2DR 0x04 /* i2c transfer data */
+/*
+ * All of the layerscape series SoCs support IBIC register.
+ */
+#define IMX_I2C_IBIC 0x05 /* i2c bus interrupt config */
+
#define IMX_I2C_REGSHIFT 2
#define VF610_I2C_REGSHIFT 0
@@ -91,6 +97,7 @@
#define I2CR_MSTA 0x20
#define I2CR_IIEN 0x40
#define I2CR_IEN 0x80
+#define IBIC_BIIE 0x80 /* Bus idle interrupt enable */
/* register bits different operating codes definition:
* 1) I2SR: Interrupt flags clear operation differ between SoCs:
@@ -201,6 +208,7 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
struct imx_i2c_dma *dma;
+ struct i2c_client *slave;
};
static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
@@ -233,19 +241,6 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
};
-static const struct platform_device_id imx_i2c_devtype[] = {
- {
- .name = "imx1-i2c",
- .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
- }, {
- .name = "imx21-i2c",
- .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
-
static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
@@ -265,6 +260,11 @@ static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
return i2c_imx->hwdata->devtype == IMX1_I2C;
}
+static inline int is_vf610_i2c(struct imx_i2c_struct *i2c_imx)
+{
+ return i2c_imx->hwdata->devtype == VF610_I2C;
+}
+
static inline void imx_i2c_write_reg(unsigned int val,
struct imx_i2c_struct *i2c_imx, unsigned int reg)
{
@@ -277,6 +277,27 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
}
+static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
+{
+ unsigned int temp;
+
+ /*
+ * i2sr_clr_opcode is the value to clear all interrupts. Here we want to
+ * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
+ * toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
+ */
+ temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+}
+
+/* Set up i2c controller register and i2c status register to default value. */
+static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
+{
+ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ i2c_imx, IMX_I2C_I2CR);
+ i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL);
+}
+
/* Functions for DMA support */
static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma_addr_t phy_addr)
@@ -424,8 +445,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a
/* check for arbitration lost */
if (temp & I2SR_IAL) {
- temp &= ~I2SR_IAL;
- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+ i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
return -EAGAIN;
}
@@ -469,7 +489,7 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic)
*/
readb_poll_timeout_atomic(addr, regval, regval & I2SR_IIF, 5, 1000 + 100);
i2c_imx->i2csr = regval;
- imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
+ i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL);
} else {
wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
}
@@ -478,6 +498,16 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic)
dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
return -ETIMEDOUT;
}
+
+ /* check for arbitration lost */
+ if (i2c_imx->i2csr & I2SR_IAL) {
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__);
+ i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
+
+ i2c_imx->i2csr = 0;
+ return -EAGAIN;
+ }
+
dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
i2c_imx->i2csr = 0;
return 0;
@@ -593,6 +623,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
/* Stop I2C transaction */
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (!(temp & I2CR_MSTA))
+ i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
if (i2c_imx->dma)
temp &= ~I2CR_DMAEN;
@@ -614,20 +646,165 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
+/*
+ * Enable bus idle interrupts
+ * Note: IBIC register will be cleared after disabled i2c module.
+ * All of layerscape series SoCs support IBIC register.
+ */
+static void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx)
+{
+ if (is_vf610_i2c(i2c_imx)) {
+ unsigned int temp;
+
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_IBIC);
+ temp |= IBIC_BIIE;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_IBIC);
+ }
+}
+
+static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
+ unsigned int status, unsigned int ctl)
+{
+ u8 value;
+
+ if (status & I2SR_IAL) { /* Arbitration lost */
+ i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
+ if (!(status & I2SR_IAAS))
+ return IRQ_HANDLED;
+ }
+
+ if (status & I2SR_IAAS) { /* Addressed as a slave */
+ if (status & I2SR_SRW) { /* Master wants to read from us*/
+ dev_dbg(&i2c_imx->adapter.dev, "read requested");
+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);
+
+ /* Slave transmit */
+ ctl |= I2CR_MTX;
+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+
+ /* Send data */
+ imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
+ } else { /* Master wants to write to us */
+ dev_dbg(&i2c_imx->adapter.dev, "write requested");
+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+
+ /* Slave receive */
+ ctl &= ~I2CR_MTX;
+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+ /* Dummy read */
+ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ }
+ } else if (!(ctl & I2CR_MTX)) { /* Receive mode */
+ if (status & I2SR_IBB) { /* No STOP signal detected */
+ value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
+ } else { /* STOP signal is detected */
+ dev_dbg(&i2c_imx->adapter.dev,
+ "STOP signal detected");
+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
+ }
+ } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */
+ ctl |= I2CR_MTX;
+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+
+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value);
+
+ imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
+ } else { /* Transmit mode received NAK */
+ ctl &= ~I2CR_MTX;
+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
+{
+ int temp;
+
+ /* Set slave addr. */
+ imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);
+
+ i2c_imx_reset_regs(i2c_imx);
+
+ /* Enable module */
+ temp = i2c_imx->hwdata->i2cr_ien_opcode;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ /* Enable interrupt from i2c module */
+ temp |= I2CR_IIEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ i2c_imx_enable_bus_idle(i2c_imx);
+}
+
+static int i2c_imx_reg_slave(struct i2c_client *client)
+{
+ struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
+ int ret;
+
+ if (i2c_imx->slave)
+ return -EBUSY;
+
+ i2c_imx->slave = client;
+
+ /* Resume */
+ ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+ if (ret < 0) {
+ dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
+ return ret;
+ }
+
+ i2c_imx_slave_init(i2c_imx);
+
+ return 0;
+}
+
+static int i2c_imx_unreg_slave(struct i2c_client *client)
+{
+ struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
+ int ret;
+
+ if (!i2c_imx->slave)
+ return -EINVAL;
+
+ /* Reset slave address. */
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
+
+ i2c_imx_reset_regs(i2c_imx);
+
+ i2c_imx->slave = NULL;
+
+ /* Suspend */
+ ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent);
+ if (ret < 0)
+ dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller");
+
+ return ret;
+}
+
+static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status)
+{
+ /* save status register */
+ i2c_imx->i2csr = status;
+ wake_up(&i2c_imx->queue);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
{
struct imx_i2c_struct *i2c_imx = dev_id;
- unsigned int temp;
-
- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
- if (temp & I2SR_IIF) {
- /* save status register */
- i2c_imx->i2csr = temp;
- temp &= ~I2SR_IIF;
- temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
- wake_up(&i2c_imx->queue);
- return IRQ_HANDLED;
+ unsigned int ctl, status;
+
+ status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+ ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (status & I2SR_IIF) {
+ i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
+ if (i2c_imx->slave && !(ctl & I2CR_MSTA))
+ return i2c_imx_slave_isr(i2c_imx, status, ctl);
+ return i2c_imx_master_isr(i2c_imx, status);
}
return IRQ_NONE;
@@ -758,9 +935,12 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
*/
dev_dbg(dev, "<%s> clear MSTA\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (!(temp & I2CR_MSTA))
+ i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- i2c_imx_bus_busy(i2c_imx, 0, false);
+ if (!i2c_imx->stopped)
+ i2c_imx_bus_busy(i2c_imx, 0, false);
} else {
/*
* For i2c master receiver repeat restart operation like:
@@ -885,9 +1065,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
dev_dbg(&i2c_imx->adapter.dev,
"<%s> clear MSTA\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (!(temp & I2CR_MSTA))
+ i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- i2c_imx_bus_busy(i2c_imx, 0, atomic);
+ if (!i2c_imx->stopped)
+ i2c_imx_bus_busy(i2c_imx, 0, atomic);
} else {
/*
* For i2c master receiver repeat restart operation like:
@@ -999,6 +1182,10 @@ fail0:
dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
(result < 0) ? "error" : "success msg",
(result < 0) ? result : num);
+ /* After data is transferred, switch to slave mode(as a receiver) */
+ if (i2c_imx->slave)
+ i2c_imx_slave_init(i2c_imx);
+
return (result < 0) ? result : num;
}
@@ -1112,6 +1299,8 @@ static const struct i2c_algorithm i2c_imx_algo = {
.master_xfer = i2c_imx_xfer,
.master_xfer_atomic = i2c_imx_xfer_atomic,
.functionality = i2c_imx_func,
+ .reg_slave = i2c_imx_reg_slave,
+ .unreg_slave = i2c_imx_unreg_slave,
};
static int i2c_imx_probe(struct platform_device *pdev)
@@ -1141,11 +1330,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
return -ENOMEM;
match = device_get_match_data(&pdev->dev);
- if (match)
- i2c_imx->hwdata = match;
- else
- i2c_imx->hwdata = (struct imx_i2c_hwdata *)
- platform_get_device_id(pdev)->driver_data;
+ i2c_imx->hwdata = match;
/* Setup i2c_imx driver structure */
strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
@@ -1205,10 +1390,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
- /* Set up chip registers to defaults */
- imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
- i2c_imx, IMX_I2C_I2CR);
- imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+ i2c_imx_reset_regs(i2c_imx);
/* Init optional bus recovery function */
ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
@@ -1316,7 +1498,6 @@ static struct platform_driver i2c_imx_driver = {
.of_match_table = i2c_imx_dt_ids,
.acpi_match_table = i2c_imx_acpi_ids,
},
- .id_table = imx_i2c_devtype,
};
static int __init i2c_adap_imx_init(void)
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index a35a27c320e7..a6187cbec2c9 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -53,7 +53,7 @@
* Features supported by this driver:
* Hardware PEC yes
* Block buffer yes
- * Block process call transaction no
+ * Block process call transaction yes
* Slave mode no
*/
@@ -332,7 +332,8 @@ static int ismt_process_desc(const struct ismt_desc *desc,
if (desc->status & ISMT_DESC_SCS) {
if (read_write == I2C_SMBUS_WRITE &&
- size != I2C_SMBUS_PROC_CALL)
+ size != I2C_SMBUS_PROC_CALL &&
+ size != I2C_SMBUS_BLOCK_PROC_CALL)
return 0;
switch (size) {
@@ -345,6 +346,7 @@ static int ismt_process_desc(const struct ismt_desc *desc,
data->word = dma_buffer[0] | (dma_buffer[1] << 8);
break;
case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
if (desc->rxbytes != dma_buffer[0] + 1)
return -EMSGSIZE;
@@ -518,6 +520,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
}
break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n");
+ dma_size = I2C_SMBUS_BLOCK_MAX;
+ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1);
+ desc->wr_len_cmd = data->block[0] + 1;
+ desc->rd_len = dma_size;
+ desc->control |= ISMT_DESC_BLK;
+ dma_direction = DMA_BIDIRECTIONAL;
+ dma_buffer[0] = command;
+ memcpy(&dma_buffer[1], &data->block[1], data->block[0]);
+ break;
+
case I2C_SMBUS_I2C_BLOCK_DATA:
/* Make sure the length is valid */
if (data->block[0] < 1)
@@ -624,6 +638,7 @@ static u32 ismt_func(struct i2c_adapter *adap)
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_SMBUS_BLOCK_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK |
I2C_FUNC_SMBUS_PEC;
diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c
index 33574d40ea9c..2fb0532d8a16 100644
--- a/drivers/i2c/busses/i2c-mlxbf.c
+++ b/drivers/i2c/busses/i2c-mlxbf.c
@@ -1258,9 +1258,9 @@ static int mlxbf_i2c_get_gpio(struct platform_device *pdev,
return -EFAULT;
gpio_res->io = devm_ioremap(dev, params->start, size);
- if (IS_ERR(gpio_res->io)) {
+ if (!gpio_res->io) {
devm_release_mem_region(dev, params->start, size);
- return PTR_ERR(gpio_res->io);
+ return -ENOMEM;
}
return 0;
@@ -1323,9 +1323,9 @@ static int mlxbf_i2c_get_corepll(struct platform_device *pdev,
return -EFAULT;
corepll_res->io = devm_ioremap(dev, params->start, size);
- if (IS_ERR(corepll_res->io)) {
+ if (!corepll_res->io) {
devm_release_mem_region(dev, params->start, size);
- return PTR_ERR(corepll_res->io);
+ return -ENOMEM;
}
return 0;
@@ -1717,9 +1717,9 @@ static int mlxbf_i2c_init_coalesce(struct platform_device *pdev,
return -EFAULT;
coalesce_res->io = ioremap(params->start, size);
- if (IS_ERR(coalesce_res->io)) {
+ if (!coalesce_res->io) {
release_mem_region(params->start, size);
- return PTR_ERR(coalesce_res->io);
+ return -ENOMEM;
}
priv->coalesce = coalesce_res;
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index e0e45fc19b8f..5cfe70aedced 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/mv643xx_i2c.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -147,6 +148,7 @@ struct mv64xxx_i2c_data {
bool irq_clear_inverted;
/* Clk div is 2 to the power n, not 2 to the power n + 1 */
bool clk_n_base_0;
+ struct i2c_bus_recovery_info rinfo;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -325,7 +327,8 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
drv_data->msg->flags);
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
mv64xxx_i2c_hw_init(drv_data);
- drv_data->rc = -EIO;
+ i2c_recover_bus(&drv_data->adapter);
+ drv_data->rc = -EAGAIN;
}
}
@@ -561,6 +564,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
"time_left: %d\n", drv_data->block,
(int)time_left);
mv64xxx_i2c_hw_init(drv_data);
+ i2c_recover_bus(&drv_data->adapter);
}
} else
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -870,6 +874,25 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
}
#endif /* CONFIG_OF */
+static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data,
+ struct device *dev)
+{
+ struct i2c_bus_recovery_info *rinfo = &drv_data->rinfo;
+
+ rinfo->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(rinfo->pinctrl)) {
+ if (PTR_ERR(rinfo->pinctrl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(dev, "can't get pinctrl, bus recovery not supported\n");
+ return PTR_ERR(rinfo->pinctrl);
+ } else if (!rinfo->pinctrl) {
+ return -ENODEV;
+ }
+
+ drv_data->adapter.bus_recovery_info = rinfo;
+ return 0;
+}
+
static int
mv64xxx_i2c_probe(struct platform_device *pd)
{
@@ -926,6 +949,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
goto exit_reset;
}
+ rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev);
+ if (rc == -EPROBE_DEFER)
+ goto exit_reset;
+
drv_data->adapter.dev.parent = &pd->dev;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index c4b08a924461..f97243f02231 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -781,28 +781,15 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
return 0;
}
-static const struct platform_device_id mxs_i2c_devtype[] = {
- {
- .name = "imx23-i2c",
- .driver_data = MXS_I2C_V1,
- }, {
- .name = "imx28-i2c",
- .driver_data = MXS_I2C_V2,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype);
-
static const struct of_device_id mxs_i2c_dt_ids[] = {
- { .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], },
- { .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], },
+ { .compatible = "fsl,imx23-i2c", .data = (void *)MXS_I2C_V1, },
+ { .compatible = "fsl,imx28-i2c", .data = (void *)MXS_I2C_V2, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
static int mxs_i2c_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(mxs_i2c_dt_ids, &pdev->dev);
struct device *dev = &pdev->dev;
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
@@ -812,10 +799,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
- i2c->dev_type = device_id->driver_data;
- }
+ i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(i2c->regs))
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
index f9a69b109e5c..6b20601ffb13 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -353,15 +353,7 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
pci_free_irq_vectors(pdev);
}
-/*
- * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
- * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
- * Documentation/power/pci.rst also insists for driver to provide this.
- */
-static __maybe_unused int gpu_i2c_suspend(struct device *dev)
-{
- return 0;
-}
+#define gpu_i2c_suspend NULL
static __maybe_unused int gpu_i2c_resume(struct device *dev)
{
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index f5fc75b65a19..273222e38056 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -83,7 +83,6 @@ struct ocores_i2c {
#define TYPE_OCORES 0
#define TYPE_GRLIB 1
-#define TYPE_SIFIVE_REV0 2
#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
@@ -476,11 +475,9 @@ static const struct of_device_id ocores_i2c_match[] = {
},
{
.compatible = "sifive,fu540-c000-i2c",
- .data = (void *)TYPE_SIFIVE_REV0,
},
{
.compatible = "sifive,i2c0",
- .data = (void *)TYPE_SIFIVE_REV0,
},
{},
};
@@ -606,7 +603,6 @@ static int ocores_i2c_probe(struct platform_device *pdev)
{
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
- const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -686,17 +682,20 @@ static int ocores_i2c_probe(struct platform_device *pdev)
init_waitqueue_head(&i2c->wait);
- irq = platform_get_irq(pdev, 0);
+ irq = platform_get_irq_optional(pdev, 0);
+ /*
+ * Since the SoC does have an interrupt, its DT has an interrupt
+ * property - But this should be bypassed as the IRQ logic in this
+ * SoC is broken.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "sifive,fu540-c000-i2c")) {
+ i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+ irq = -ENXIO;
+ }
+
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
-
- /*
- * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
- * FU540-C000 SoC in polling mode.
- */
- match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
- if (match && (long)match->data == TYPE_SIFIVE_REV0)
- i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c
index 9918b2a0b909..98882fe4e965 100644
--- a/drivers/i2c/busses/i2c-owl.c
+++ b/drivers/i2c/busses/i2c-owl.c
@@ -14,6 +14,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -76,6 +77,7 @@
#define OWL_I2C_FIFOCTL_TFR BIT(2)
/* I2Cc_FIFOSTAT Bit Mask */
+#define OWL_I2C_FIFOSTAT_CECB BIT(0)
#define OWL_I2C_FIFOSTAT_RNB BIT(1)
#define OWL_I2C_FIFOSTAT_RFE BIT(2)
#define OWL_I2C_FIFOSTAT_TFF BIT(5)
@@ -83,7 +85,8 @@
#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8)
/* I2C bus timeout */
-#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000)
+#define OWL_I2C_TIMEOUT_MS (4 * 1000)
+#define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS)
#define OWL_I2C_MAX_RETRIES 50
@@ -161,14 +164,11 @@ static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev)
writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
}
-static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev)
{
- struct owl_i2c_dev *i2c_dev = _dev;
struct i2c_msg *msg = i2c_dev->msg;
unsigned int stat, fifostat;
- spin_lock(&i2c_dev->lock);
-
i2c_dev->err = 0;
/* Handle NACK from slave */
@@ -178,7 +178,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
/* Clear NACK error bit by writing "1" */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
OWL_I2C_FIFOSTAT_RNB, true);
- goto stop;
+ return;
}
/* Handle bus error */
@@ -188,7 +188,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
/* Clear BUS error bit by writing "1" */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
OWL_I2C_STAT_BEB, true);
- goto stop;
+ return;
}
/* Handle FIFO read */
@@ -206,8 +206,16 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
i2c_dev->base + OWL_I2C_REG_TXDAT);
}
}
+}
+
+static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+{
+ struct owl_i2c_dev *i2c_dev = _dev;
+
+ spin_lock(&i2c_dev->lock);
+
+ owl_i2c_xfer_data(i2c_dev);
-stop:
/* Clear pending interrupts */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
OWL_I2C_STAT_IRQP, true);
@@ -240,8 +248,8 @@ static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
return 0;
}
-static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- int num)
+static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num, bool atomic)
{
struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
struct i2c_msg *msg;
@@ -285,11 +293,12 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
goto err_exit;
}
- reinit_completion(&i2c_dev->msg_complete);
+ if (!atomic)
+ reinit_completion(&i2c_dev->msg_complete);
- /* Enable I2C controller interrupt */
+ /* Enable/disable I2C controller interrupt */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
- OWL_I2C_CTL_IRQE, true);
+ OWL_I2C_CTL_IRQE, !atomic);
/*
* Select: FIFO enable, Master mode, Stop enable, Data count enable,
@@ -357,20 +366,33 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
spin_unlock_irqrestore(&i2c_dev->lock, flags);
- time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
- adap->timeout);
+ if (atomic) {
+ /* Wait for Command Execute Completed or NACK Error bits */
+ ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
+ val, val & (OWL_I2C_FIFOSTAT_CECB |
+ OWL_I2C_FIFOSTAT_RNB),
+ 10, OWL_I2C_TIMEOUT_MS * 1000);
+ } else {
+ time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+ adap->timeout);
+ if (!time_left)
+ ret = -ETIMEDOUT;
+ }
spin_lock_irqsave(&i2c_dev->lock, flags);
- if (time_left == 0) {
+
+ if (ret) {
dev_err(&adap->dev, "Transaction timed out\n");
/* Send stop condition and release the bus */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
true);
- ret = -ETIMEDOUT;
goto err_exit;
}
+ if (atomic)
+ owl_i2c_xfer_data(i2c_dev);
+
ret = i2c_dev->err < 0 ? i2c_dev->err : num;
err_exit:
@@ -384,9 +406,22 @@ unlocked_err_exit:
return ret;
}
+static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ return owl_i2c_xfer_common(adap, msgs, num, false);
+}
+
+static int owl_i2c_xfer_atomic(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ return owl_i2c_xfer_common(adap, msgs, num, true);
+}
+
static const struct i2c_algorithm owl_i2c_algorithm = {
- .master_xfer = owl_i2c_master_xfer,
- .functionality = owl_i2c_func,
+ .master_xfer = owl_i2c_xfer,
+ .master_xfer_atomic = owl_i2c_xfer_atomic,
+ .functionality = owl_i2c_func,
};
static const struct i2c_adapter_quirks owl_i2c_quirks = {
@@ -473,6 +508,7 @@ disable_clk:
}
static const struct of_device_id owl_i2c_of_match[] = {
+ { .compatible = "actions,s500-i2c" },
{ .compatible = "actions,s700-i2c" },
{ .compatible = "actions,s900-i2c" },
{ /* sentinel */ }
@@ -484,6 +520,7 @@ static struct platform_driver owl_i2c_driver = {
.driver = {
.name = "owl-i2c",
.of_match_table = of_match_ptr(owl_i2c_of_match),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_platform_driver(owl_i2c_driver);
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index 546426a470cc..86d4f75ef8d3 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -33,8 +33,6 @@ struct i2c_pca_pf_data {
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_algo_pca_data algo_data;
- unsigned long io_base;
- unsigned long io_size;
};
/* Read/Write functions for different register alignments */
@@ -156,8 +154,6 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
init_waitqueue_head(&i2c->wait);
- i2c->io_base = res->start;
- i2c->io_size = resource_size(res);
i2c->irq = irq;
i2c->adap.nr = pdev->id;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 35ca2c02c9b9..a636ea0eb50a 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -264,9 +264,6 @@ struct pxa_i2c {
u32 hs_mask;
struct i2c_bus_recovery_info recovery;
- struct pinctrl *pinctrl;
- struct pinctrl_state *pinctrl_default;
- struct pinctrl_state *pinctrl_recovery;
};
#define _IBMR(i2c) ((i2c)->reg_ibmr)
@@ -1305,13 +1302,12 @@ static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap)
*/
gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS);
gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS);
-
- WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery));
}
static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
{
struct pxa_i2c *i2c = adap->algo_data;
+ struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
u32 isr;
/*
@@ -1325,7 +1321,7 @@ static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
i2c_pxa_do_reset(i2c);
}
- WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default));
+ WARN_ON(pinctrl_select_state(bri->pinctrl, bri->pins_default));
dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n",
readl(_IBMR(i2c)), readl(_ISR(i2c)));
@@ -1347,76 +1343,20 @@ static int i2c_pxa_init_recovery(struct pxa_i2c *i2c)
if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE))
return 0;
- i2c->pinctrl = devm_pinctrl_get(dev);
- if (PTR_ERR(i2c->pinctrl) == -ENODEV)
- i2c->pinctrl = NULL;
- if (IS_ERR(i2c->pinctrl))
- return PTR_ERR(i2c->pinctrl);
-
- if (!i2c->pinctrl)
- return 0;
-
- i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl,
- PINCTRL_STATE_DEFAULT);
- i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery");
-
- if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) {
- dev_info(dev, "missing pinmux recovery information: %ld %ld\n",
- PTR_ERR(i2c->pinctrl_default),
- PTR_ERR(i2c->pinctrl_recovery));
- return 0;
- }
-
- /*
- * Claiming GPIOs can influence the pinmux state, and may glitch the
- * I2C bus. Do this carefully.
- */
- bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
- if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER))
- return -EPROBE_DEFER;
- if (IS_ERR(bri->scl_gpiod)) {
- dev_info(dev, "missing scl gpio recovery information: %pe\n",
- bri->scl_gpiod);
- return 0;
- }
-
- /*
- * We have SCL. Pull SCL low and wait a bit so that SDA glitches
- * have no effect.
- */
- gpiod_direction_output(bri->scl_gpiod, 0);
- udelay(10);
- bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN);
-
- /* Wait a bit in case of a SDA glitch, and then release SCL. */
- udelay(10);
- gpiod_direction_output(bri->scl_gpiod, 1);
-
- if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER))
- return -EPROBE_DEFER;
-
- if (IS_ERR(bri->sda_gpiod)) {
- dev_info(dev, "missing sda gpio recovery information: %pe\n",
- bri->sda_gpiod);
+ bri->pinctrl = devm_pinctrl_get(dev);
+ if (PTR_ERR(bri->pinctrl) == -ENODEV) {
+ bri->pinctrl = NULL;
return 0;
}
+ if (IS_ERR(bri->pinctrl))
+ return PTR_ERR(bri->pinctrl);
bri->prepare_recovery = i2c_pxa_prepare_recovery;
bri->unprepare_recovery = i2c_pxa_unprepare_recovery;
- bri->recover_bus = i2c_generic_scl_recovery;
i2c->adap.bus_recovery_info = bri;
- /*
- * Claiming GPIOs can change the pinmux state, which confuses the
- * pinctrl since pinctrl's idea of the current setting is unaffected
- * by the pinmux change caused by claiming the GPIO. Work around that
- * by switching pinctrl to the GPIO state here. We do it this way to
- * avoid glitching the I2C bus.
- */
- pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery);
-
- return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default);
+ return 0;
}
static int i2c_pxa_probe(struct platform_device *dev)
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index f13735beca58..1c259b5188de 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -194,9 +194,9 @@ static irqreturn_t cci_isr(int irq, void *dev)
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_ERROR)) {
if (val & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR ||
val & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR)
- cci->master[0].status = -ENXIO;
+ cci->master[1].status = -ENXIO;
else
- cci->master[0].status = -EIO;
+ cci->master[1].status = -EIO;
writel(CCI_HALT_REQ_I2C_M1_Q0Q1, cci->base + CCI_HALT_REQ);
ret = IRQ_HANDLED;
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 8b4c35f47a70..046d241183c5 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -353,19 +353,18 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
{
dma_addr_t rx_dma;
unsigned long time_left;
- void *dma_buf = NULL;
+ void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
- if (!of_machine_is_compatible("lenovo,yoga-c630"))
- dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
-
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf)
geni_se_select_mode(se, GENI_SE_DMA);
else
geni_se_select_mode(se, GENI_SE_FIFO);
writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_READ, m_param);
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
geni_se_select_mode(se, GENI_SE_FIFO);
@@ -373,8 +372,6 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
dma_buf = NULL;
}
- geni_se_setup_m_cmd(se, I2C_READ, m_param);
-
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
@@ -395,19 +392,18 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
{
dma_addr_t tx_dma;
unsigned long time_left;
- void *dma_buf = NULL;
+ void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
- if (!of_machine_is_compatible("lenovo,yoga-c630"))
- dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
-
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf)
geni_se_select_mode(se, GENI_SE_DMA);
else
geni_se_select_mode(se, GENI_SE_FIFO);
writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
geni_se_select_mode(se, GENI_SE_FIFO);
@@ -415,8 +411,6 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
dma_buf = NULL;
}
- geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
-
if (!dma_buf) /* Get FIFO IRQ */
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index fbc04b60cfd1..5a47915869ae 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -801,7 +801,8 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
if (ret || qup->bus_err || qup->qup_err) {
reinit_completion(&qup->xfer);
- if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret) {
dev_err(qup->dev, "change to run state timed out");
goto desc_err;
}
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index bdd60770779a..3ae6ca21a02c 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -956,10 +956,38 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int sh_mobile_i2c_suspend(struct device *dev)
+{
+ struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_suspended(&pd->adap);
+ return 0;
+}
+
+static int sh_mobile_i2c_resume(struct device *dev)
+{
+ struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_resumed(&pd->adap);
+ return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_i2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend,
+ sh_mobile_i2c_resume)
+};
+
+#define DEV_PM_OPS (&sh_mobile_i2c_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver sh_mobile_i2c_driver = {
.driver = {
.name = "i2c-sh_mobile",
.of_match_table = sh_mobile_i2c_dt_ids,
+ .pm = DEV_PM_OPS,
},
.probe = sh_mobile_i2c_probe,
.remove = sh_mobile_i2c_remove,
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index f41f51a176a1..9aa8e65b511e 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -2322,7 +2322,7 @@ static int stm32f7_i2c_suspend(struct device *dev)
i2c_mark_adapter_suspended(&i2c_dev->adap);
- if (!device_may_wakeup(dev) && !dev->power.wakeup_path) {
+ if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
ret = stm32f7_i2c_regs_backup(i2c_dev);
if (ret < 0) {
i2c_mark_adapter_resumed(&i2c_dev->adap);
@@ -2341,7 +2341,7 @@ static int stm32f7_i2c_resume(struct device *dev)
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int ret;
- if (!device_may_wakeup(dev) && !dev->power.wakeup_path) {
+ if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
ret = pm_runtime_force_resume(dev);
if (ret < 0)
return ret;
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 573b5da145d1..63ebf722a424 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -549,17 +549,18 @@ put_sync_adapter:
static int i2c_device_remove(struct device *dev)
{
- struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver;
- int status = 0;
-
- if (!client || !dev->driver)
- return 0;
driver = to_i2c_driver(dev->driver);
if (driver->remove) {
+ int status;
+
dev_dbg(dev, "remove\n");
+
status = driver->remove(client);
+ if (status)
+ dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status));
}
dev_pm_domain_detach(&client->dev, true);
@@ -571,7 +572,8 @@ static int i2c_device_remove(struct device *dev)
if (client->flags & I2C_CLIENT_HOST_NOTIFY)
pm_runtime_put(&client->adapter->dev);
- return status;
+ /* return always 0 because there is WIP to make remove-functions void */
+ return 0;
}
static void i2c_device_shutdown(struct device *dev)