diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-at91-master.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-at91.h | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 98 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-exynos5.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 239 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ismt.c | 19 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 29 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mxs.c | 22 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nvidia-gpu.c | 10 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 25 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-owl.c | 75 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pca-platform.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 76 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-qcom-geni.c | 18 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 28 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-stm32f7.c | 4 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-base.c | 14 |
18 files changed, 416 insertions, 254 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a49e0ed4a599..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. 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 e6f8d6e45a15..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) @@ -412,19 +433,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) dma->chan_using = NULL; } -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); -} - static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic) { unsigned long orig_jiffies = jiffies; @@ -638,18 +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; + unsigned int ctl, status; - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); - if (temp & I2SR_IIF) { - /* save status register */ - i2c_imx->i2csr = temp; + 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); - wake_up(&i2c_imx->queue); - return IRQ_HANDLED; + 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; @@ -1027,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; } @@ -1140,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) @@ -1169,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)); @@ -1233,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); @@ -1344,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-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-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-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) |