From 8c7ecc9953391cb0f7bf7e6eb34f9f9ac885259a Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 11 Apr 2018 15:24:53 +0200 Subject: i2c: i2c-stm32f7: Add 10-bit address support This patch adds support for 10-bit device address for STM32F7 I2C Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index f273e28c39db..ae0d15c3180a 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -65,7 +65,12 @@ #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) @@ -176,14 +181,14 @@ 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 */ struct stm32f7_i2c_msg { - u8 addr; + u16 addr; u32 count; u8 *buf; int result; @@ -629,8 +634,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); @@ -798,7 +810,7 @@ clk_free: static u32 stm32f7_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } static struct i2c_algorithm stm32f7_i2c_algo = { -- cgit From 60d609f30de27b14a17eb46365f8ef83fd7af024 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 11 Apr 2018 15:24:54 +0200 Subject: i2c: i2c-stm32f7: Add slave support This patch adds slave support for I2C controller embedded in STM32F7 SoC Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-stm32f7.c | 434 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 429 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') 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/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index ae0d15c3180a..9bf676ee2509 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -35,6 +35,8 @@ /* 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_TIMINGR 0x10 #define STM32F7_I2C_ISR 0x18 #define STM32F7_I2C_ICR 0x1C @@ -42,6 +44,7 @@ #define STM32F7_I2C_TXDR 0x28 /* STM32F7 I2C control 1 */ +#define STM32F7_I2C_CR1_SBC BIT(16) #define STM32F7_I2C_CR1_ANFOFF BIT(12) #define STM32F7_I2C_CR1_ERRIE BIT(7) #define STM32F7_I2C_CR1_TCIE BIT(6) @@ -57,6 +60,11 @@ | 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_RELOAD BIT(24) @@ -74,7 +82,34 @@ #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_ARLO BIT(9) #define STM32F7_I2C_ISR_BERR BIT(8) @@ -82,14 +117,17 @@ #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_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) @@ -99,6 +137,7 @@ #define STM32F7_I2C_TIMINGR_SCLL(n) ((n) & 0xff) #define STM32F7_I2C_MAX_LEN 0xff +#define STM32F7_I2C_MAX_SLAVE 0x2 #define STM32F7_I2C_DNF_DEFAULT 0 #define STM32F7_I2C_DNF_MAX 16 @@ -209,6 +248,11 @@ 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) */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -223,6 +267,10 @@ 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; }; /** @@ -288,6 +336,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) @@ -572,6 +625,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); } } @@ -669,14 +725,250 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, /* 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 void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) +static bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode) { - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); + 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) @@ -685,6 +977,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; + + /* 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); @@ -706,11 +1005,16 @@ 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); + i2c_dev->master_mode = false; complete(&i2c_dev->complete); } @@ -743,7 +1047,7 @@ 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; + u32 mask, status; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -761,8 +1065,14 @@ 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); + /* 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); + i2c_dev->master_mode = false; complete(&i2c_dev->complete); return IRQ_HANDLED; @@ -808,14 +1118,126 @@ clk_free: return (ret < 0) ? ret : num; } +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 | I2C_FUNC_10BIT_ADDR; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_SLAVE; } static struct i2c_algorithm stm32f7_i2c_algo = { .master_xfer = stm32f7_i2c_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) -- cgit From 9e48155f6bfe3d3896c8596f56cc2f76d344db3a Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 11 Apr 2018 15:24:55 +0200 Subject: i2c: i2c-stm32f7: Add initial SMBus protocols support This patch adds SMBus support for I2C controller embedded in STM32F7 Soc. All SMBus protocols are implemented except SMBus-specific protocols like SMBus Host Notification and SMBus Alert protocols. Implemented: SMBus Quick command, Send byte, Receive byte, Write byte/word, read byte/word, Process call, Block write/read and Block write-block read process call. Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 377 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 368 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 9bf676ee2509..0b81b5dc2eda 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -37,6 +37,7 @@ #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 @@ -44,6 +45,7 @@ #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_ANFOFF BIT(12) #define STM32F7_I2C_CR1_ERRIE BIT(7) @@ -67,6 +69,7 @@ | 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) @@ -111,6 +114,7 @@ (((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) @@ -123,6 +127,7 @@ #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) @@ -225,6 +230,14 @@ struct stm32f7_i2c_timings { * @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_buff: 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 { u16 addr; @@ -232,6 +245,10 @@ struct stm32f7_i2c_msg { u8 *buf; int result; bool stop; + bool smbus; + int size; + char read_write; + u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); }; /** @@ -649,6 +666,29 @@ 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_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) { u32 status; @@ -732,6 +772,237 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, 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; + + 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 TX/RX interrupt */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); + + /* Enable RX/TX interrupt according to msg direction */ + if (cr2 & STM32F7_I2C_CR2_RD_WRN) + cr1 |= STM32F7_I2C_CR1_RXIE; + else + cr1 |= STM32F7_I2C_CR1_TXIE; + + /* 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; + + 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; + + /* Configure Repeated Start */ + cr2 |= STM32F7_I2C_CR2_START; + + /* Write configurations registers */ + writel_relaxed(cr1, base + STM32F7_I2C_CR1); + writel_relaxed(cr2, base + STM32F7_I2C_CR2); +} + +static int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev) +{ + 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; @@ -1023,6 +1294,8 @@ 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 (f7_msg->smbus) { + stm32f7_i2c_smbus_rep_start(i2c_dev); } else { i2c_dev->msg_id++; i2c_dev->msg++; @@ -1030,13 +1303,12 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) } } - /* - * Transfer Complete Reload: 255 data bytes have been transferred - * We have to prepare the I2C controller to transfer the remaining - * data. - */ - if (status & STM32F7_I2C_ISR_TCR) - stm32f7_i2c_reload(i2c_dev); + if (status & STM32F7_I2C_ISR_TCR) { + if (f7_msg->smbus) + stm32f7_i2c_smbus_reload(i2c_dev); + else + stm32f7_i2c_reload(i2c_dev); + } return IRQ_HANDLED; } @@ -1065,6 +1337,12 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) f7_msg->result = -EAGAIN; } + 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; @@ -1089,6 +1367,7 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, 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) { @@ -1118,6 +1397,82 @@ 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 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); + 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); @@ -1229,12 +1584,16 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) static u32 stm32f7_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_SLAVE; + 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, -- cgit From bb8822cbbc5334dc89b7415dbdc6d51421e74773 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 11 Apr 2018 15:24:56 +0200 Subject: i2c: i2c-stm32: Add generic DMA API This patch adds a generic DMA API to implement DMA support for i2c-stm32fx drivers Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32.c | 153 +++++++++++++++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-stm32.h | 37 ++++++++++ 2 files changed, 190 insertions(+) create mode 100644 drivers/i2c/busses/i2c-stm32.c (limited to 'drivers/i2c') 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 + * + * 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 +#include +#include + 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 */ -- cgit From 7ecc8cfde553b92f897bd60b21bf53de9277e3aa Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 11 Apr 2018 15:24:57 +0200 Subject: i2c: i2c-stm32f7: Add DMA support This patch adds DMA support for i2c-stm32f7 driver Signed-off-by: M'boumba Cedric Madianga Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Makefile | 3 +- drivers/i2c/busses/i2c-stm32f7.c | 214 +++++++++++++++++++++++++++++++++++---- 2 files changed, 196 insertions(+), 21 deletions(-) (limited to 'drivers/i2c') 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-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 0b81b5dc2eda..63ea71c5762f 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -47,6 +47,8 @@ /* 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) @@ -142,6 +144,7 @@ #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 @@ -270,6 +273,8 @@ struct stm32f7_i2c_msg { * @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; @@ -288,6 +293,8 @@ struct stm32f7_i2c_dev { struct i2c_client *slave_running; u32 slave_dir; bool master_mode; + struct stm32_i2c_dma *dma; + bool use_dma; }; /** @@ -599,6 +606,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; @@ -653,6 +679,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; @@ -712,6 +741,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; @@ -753,14 +783,35 @@ 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 */ - cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); + /* 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"); + } - /* Enable RX/TX interrupt according to msg direction */ - if (msg->flags & I2C_M_RD) - cr1 |= STM32F7_I2C_CR1_RXIE; - else - cr1 |= STM32F7_I2C_CR1_TXIE; + 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; @@ -780,7 +831,7 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, struct device *dev = i2c_dev->dev; void __iomem *base = i2c_dev->base; u32 cr1, cr2; - int i; + int i, ret; f7_msg->result = 0; reinit_completion(&i2c_dev->complete); @@ -895,14 +946,35 @@ static int stm32f7_i2c_smbus_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 */ - cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); + /* 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"); + } - /* Enable RX/TX interrupt according to msg direction */ - if (cr2 & STM32F7_I2C_CR2_RD_WRN) - cr1 |= STM32F7_I2C_CR1_RXIE; - else - cr1 |= STM32F7_I2C_CR1_TXIE; + 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; @@ -921,6 +993,7 @@ 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); @@ -960,6 +1033,35 @@ static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev) cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); cr1 |= STM32F7_I2C_CR1_RXIE; + /* + * 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_RXDMAEN; + /* Configure Repeated Start */ cr2 |= STM32F7_I2C_CR2_START; @@ -1248,7 +1350,7 @@ 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; + int ret = IRQ_HANDLED; /* Check if the interrupt if for a slave device */ if (!i2c_dev->master_mode) { @@ -1285,8 +1387,12 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) /* Clear STOP flag */ writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - i2c_dev->master_mode = false; - 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 */ @@ -1294,6 +1400,8 @@ 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 { @@ -1310,6 +1418,44 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) 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; + + /* + * Wait for dma transfer completion before sending next message or + * notity the end of xfer to the client + */ + 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; } @@ -1319,6 +1465,7 @@ 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; + struct stm32_i2c_dma *dma = i2c_dev->dma; u32 mask, status; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -1350,6 +1497,12 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) 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); @@ -1361,6 +1514,7 @@ 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; @@ -1388,6 +1542,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; } @@ -1404,6 +1560,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, { 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; @@ -1435,6 +1592,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 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; } @@ -1608,6 +1767,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); @@ -1618,6 +1778,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) { @@ -1664,8 +1825,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); @@ -1717,6 +1881,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; @@ -1739,6 +1908,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); -- cgit From 562de4ff4cd2beb1bd3a1581e22623f05b114c97 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 11 Apr 2018 15:24:58 +0200 Subject: i2c: i2c-stm32f7: Implement I2C release mechanism Feature prevents I2C lock-ups. Mechanism resets I2C state machine and releases SCL/SDA signals but preserves I2C registers. Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 63ea71c5762f..0f87449fc6bd 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -718,6 +718,20 @@ static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev) 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; @@ -727,12 +741,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, @@ -1474,6 +1494,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; } -- cgit From e8f39e9fc0e0b7bce24922da925af820bacb8ef8 Mon Sep 17 00:00:00 2001 From: David Engraf Date: Thu, 26 Apr 2018 11:53:14 +0200 Subject: i2c: at91: Read all available bytes at once With FIFO enabled it is possible to read multiple bytes at once in the interrupt handler as long as RXRDY is set. This may also reduce the number of interrupts. This patch polls RXRDY and reads all available bytes at once. Signed-off-by: David Engraf Acked-by: Ludovic Desroches [wsa: reformatted comment] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') 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, -- cgit From a9c8088c7988e3a8a364cac9c26eba9ee2ea6153 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 25 Apr 2018 11:53:40 +0200 Subject: i2c: i801: Don't restore config registers on runtime PM Restoring configuration registers is only needed when we hand control to the firmware. This is never the case with runtime power management. The device will autosuspend whenever not used, so avoid useless register writes by defining suspend/resume only, and not runtime_suspend/runtime_resume. Signed-off-by: Jean Delvare Reviewed-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e0d59e9ff3c6..ed07f9002710 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -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", -- cgit From 952cfd15815e0308135001dc7a612b8fa7feb2d2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 24 Apr 2018 22:32:34 +0200 Subject: i2c: s3c2410: Remove support for Exynos5440 The Exynos5440 is not actively developed, there are no development boards available and probably there are no real products with it. Remove wide-tree support for Exynos5440. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Sylwester Nawrocki Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c') 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) }, {}, -- cgit From 6e29577fc2a870c4272d10d54d2fdec019301dc0 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 16 Apr 2018 10:32:52 +0800 Subject: i2c: mediatek: use of_device_get_match_data() The usage of of_device_get_match_data() reduce the code size a bit. Also, the only way to call mtk_i2c_probe() is to match an entry in mtk_i2c_of_match[], so of_id cannot be NULL. Signed-off-by: Ryder Lee Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mt65xx.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') 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 #include #include +#include #include #include #include @@ -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; -- cgit From 313ce648b5a4ac8ceed63a36570126b7684165a0 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Tue, 27 Mar 2018 14:01:22 +0000 Subject: i2c: mlxcpld: Add support for extended transaction length for i2c-mlxcpld It adds support for extended length of read and write transactions. New CPLD logic allows double size of the read and write transactions length. This feature is verified through capability register, which is renamed from unclear LPF_REG to CPBLTY_REG. Two bits 5 and 6 of these register are used for length capability detection, while only 01 combination indicates support of extended transaction length. Others mean lack of such support. Signed-off-by: Michael Shych Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 4c28fa28ce76..6434f8c4b8f9 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -45,13 +45,15 @@ #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_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 @@ -230,7 +232,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; @@ -440,6 +442,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 +463,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 +476,11 @@ 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; priv->adap = mlxcpld_i2c_adapter; priv->adap.dev.parent = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; -- cgit From c9bfdc7c16cbc16348ede102f21d0c5c1338cee8 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Tue, 27 Mar 2018 14:01:23 +0000 Subject: i2c: mlxcpld: Add support for smbus block read transaction It adds support for smbus block read transaction. CPLD smbus block read bit of capability register is verified during driver initialization, and driver data is updated if such capability is available. In case an upper layer requests a read transaction of length one and expects that length will be the first received byte, driver will notify CPLD about SMBus block read transaction flavor, so CPLD will know to execute such kind of transaction. Signed-off-by: Michael Shych Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 6434f8c4b8f9..4d8efe0dfe30 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -47,6 +47,7 @@ #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 */ @@ -85,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) @@ -297,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); @@ -326,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); @@ -346,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) { @@ -481,6 +504,9 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) /* 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; priv->adap = mlxcpld_i2c_adapter; priv->adap.dev.parent = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; -- cgit From 845f2a6d00791f1f8541ae4c69a70a6be6d21fb8 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Tue, 27 Mar 2018 14:01:24 +0000 Subject: i2c: mlxcpld: Fix adapter functionality support callback It fixes report about supported functionality. Functionality can be different up to CPLD capability. Fixes: 6bec23bff9149 (i2c: mlxcpld: add master driver for mellanox systems) Signed-off-by: Michael Shych Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 4d8efe0dfe30..7341cee9cfe5 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -450,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 = { -- cgit From ae4aa68dd3e4bf16bff6078c1851b832b0b3db1a Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Tue, 27 Mar 2018 14:01:25 +0000 Subject: i2c: mlxcpld: Allow configurable adapter id for mlxcpld It allows mlxcpld driver to be connected to pre-defined adapter number equal or greater than one, in order to avoid current limitation, assuming usage of id number one only. Signed-off-by: Michael Shych Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 7341cee9cfe5..745ed43a22d6 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -514,6 +514,8 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) /* 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; -- cgit From b1437dcb973de79d1f9bca55c6056e8b40ff7ba7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 28 Apr 2018 22:01:02 +0200 Subject: i2c: rcar: enhance comment to avoid regressions Give a clear testcase for people wishing to change this code. It is also a reminder for me if people ask about it. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c') 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); -- cgit From e6faa71034f6d0692a3a20d6b55565a36b6b8156 Mon Sep 17 00:00:00 2001 From: Tobias Jordan Date: Mon, 30 Apr 2018 16:49:29 +0200 Subject: i2c: axxia: enable clock before calling clk_get_rate() axxia_i2c_init() uses clk_get_rate() for idev->i2c_clk. clk_get_rate() should only be called if the clock is enabled, so ensure that by moving the clk_prepare_enable() call before the call to axxia_i2c_init(). Found by Linux Driver Verification project (linuxtesting.org). Fixes: 08678b850cd0 ("i2c: axxia: Add I2C driver for AXM55xx") Signed-off-by: Tobias Jordan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-axxia.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') 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) -- cgit From 77bade677c3c5616dfadfd21f0220fcddbfa4cbe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 29 Apr 2018 20:41:04 +0200 Subject: i2c: busses: remove superfluous ignoring of children for RPM These days, the I2C core ensures that the embedded adapter device ignores the PM states of its children already. Because the adapter device is an opaque logical device, there is no need for drivers to repeat that again. Signed-off-by: Wolfram Sang Reviewed-by: Linus Walleij Reviewed-by: Ulf Hansson Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-hix5hd2.c | 1 - drivers/i2c/busses/i2c-nomadik.c | 2 -- drivers/i2c/busses/i2c-sh_mobile.c | 11 ----------- 3 files changed, 14 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index bb68957d3da5..1504c3c1a1c0 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -471,7 +471,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-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-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); -- cgit From 9f4659ba384780f8bc5b18717865026d83d455ce Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Sat, 28 Apr 2018 16:56:07 +0300 Subject: i2c: designware: refactor low-level enable/disable Low-level controller enable function __i2c_dw_enable is overloaded to also handle disabling. What's worse, even though the documentation requires polling the IC_ENABLE_STATUS register when disabling, this is not done: polling needs to be requested specifically by calling __i2c_dw_enable_and_wait, which can also poll on enabling, but that doesn't work if the IC_ENABLE_STATUS register is not implemented. This is quite confusing if not in fact backwards. Especially since the documentation says that disabling should be followed by polling, the driver should be using a separate function where it does one-shot disables to make the optimization stand out. This refactors the two functions so that requested status is given in the name rather than in a boolean argument. Specifically: - __i2c_dw_enable: enable without polling (in accordance with docs) - __i2c_dw_disable: disable and do poll (also as suggested by docs) - __i2c_dw_disable_nowait: disable without polling (Linux-specific) No functional change. Signed-off-by: Alexander Monakov Acked-by: Jarkko Nikula [wsa: fixed blank lines in header file] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 20 +++++++++----------- drivers/i2c/busses/i2c-designware-core.h | 14 ++++++++++++-- drivers/i2c/busses/i2c-designware-master.c | 8 ++++---- drivers/i2c/busses/i2c-designware-slave.c | 6 +++--- 4 files changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers/i2c') 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 0cdba29ae0a9..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,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) i2c_dw_disable_int(dev); /* Enable the adapter */ - __i2c_dw_enable(dev, true); + __i2c_dw_enable(dev); /* Dummy read to avoid the register getting stuck on Bay Trail */ dw_readl(dev, DW_IC_ENABLE_STATUS); @@ -462,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; -- cgit From 4fad8868afe7b168c34fab3d959d875f4f8b3624 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 25 Mar 2018 14:49:01 +0200 Subject: i2c: Get rid of i2c_board_info->archdata The only user of i2c_board_info->archdata is the OF parsing code and it just pass a zero-initialized object which has the same effect as leaving ->archdata to NULL since the client object is allocated with kzalloc(). Get rid of this useless field. Signed-off-by: Boris Brezillon Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 4 ---- drivers/i2c/i2c-core-of.c | 2 -- 2 files changed, 6 deletions(-) (limited to 'drivers/i2c') 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")) -- cgit From 043056270b77cd63370923138d857afb3f96cdec Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 11 May 2018 11:33:07 +0200 Subject: i2c: exynos5: simplify transfer function exynos5_i2c_xfer contains lots of dead code, let's remove it and simplify the rest. The patch should not introduce functional changes. Signed-off-by: Andrzej Hajda Suggested-by: Peter Rosin Reviewed-by: Andi Shyti Reviewed-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) (limited to 'drivers/i2c') 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) -- cgit From a5dab8698c70379baa35f23f7803a4c69aed0fc9 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 9 May 2018 21:46:03 +0200 Subject: i2c: hix5hd2: remove some dead code The else branch cannot be taken as i will always equal num. Get rid of the whole construct. Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-hix5hd2.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 1504c3c1a1c0..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); -- cgit From 8e03477cb709b73a2c1e1f4349ee3b7b33c50416 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sat, 5 May 2018 08:02:21 -0500 Subject: i2c: core: smbus: fix a potential missing-check bug In i2c_smbus_xfer_emulated(), the function i2c_transfer() is invoked to transfer i2c messages. The number of actual transferred messages is returned and saved to 'status'. If 'status' is negative, that means an error occurred during the transfer process. In that case, the value of 'status' is an error code to indicate the reason of the transfer failure. In most cases, i2c_transfer() can transfer 'num' messages with no error. And so 'status' == 'num'. However, due to unexpected errors, it is probable that only partial messages are transferred by i2c_transfer(). As a result, 'status' != 'num'. This special case is not checked after the invocation of i2c_transfer() and can potentially lead to unexpected issues in the following execution since it is expected that 'status' == 'num'. This patch checks the return value of i2c_transfer() and returns an error code -EIO if the number of actual transferred messages 'status' is not equal to 'num'. Signed-off-by: Wenwen Wang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c') 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)) { -- cgit From 5e87270bec6d17d3b90e54976f53c9b221f79c1d Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 9 May 2018 21:47:26 +0200 Subject: i2c: synquacer: fix fence-post error in retry loop There is a difference between attempts and retries. Signed-off-by: Peter Rosin Acked-by: Ard Biesheuvel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-synquacer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') 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; -- cgit From 1ee7cdbfcd986b48487d543c678bf305d0d65c5c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 14 May 2018 18:15:52 +0100 Subject: i2c: xiic: fix spelling mistake: "unexpexted" -> "unexpected" Trivial fix to spelling mistakes in dev_dbg messages Signed-off-by: Colin Ian King Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index c80527816ad0..92def988d3c7 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; } -- cgit From 4b2f9bd5e39fb47011074c9a26b64b616acc18f0 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 14 May 2018 11:33:26 +0200 Subject: i2c: i801: fix unused-function warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_PM, we get a harmless build warning: drivers/i2c/busses/i2c-i801.c:1723:12: warning: ‘i801_resume’ defined but not used [-Wunused-function] static int i801_resume(struct device *dev) ^~~~~~~~~~~ drivers/i2c/busses/i2c-i801.c:1714:12: warning: ‘i801_suspend’ defined but not used [-Wunused-function] static int i801_suspend(struct device *dev) ^~~~~~~~~~~~ Follow design pattern from other drivers like i2c-brcmstb, i2c-mpc, i2c-ocores, i2c-pnx, i2c-puv3, i2c-st, i2c-stu300 and i2c-mux-pca954x and changing the ifdef CONFIG_PM to CONFIG_PM_SLEEP. Fixes: a9c8088c7988 ("i2c: i801: Don't restore config registers on runtime PM") Signed-off-by: Anders Roxell Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ed07f9002710..954fb3f3b7fc 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); -- cgit From c599eb4ff6e0f9c525695faab7149d8d48743b1c Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Fri, 11 May 2018 10:20:25 +0200 Subject: i2c: stm32f7: fix documentation typo Some data structure members were either misspelled or missing. Fixes: aeb068c572 ("i2c: i2c-stm32f7: add driver") Fixes: 380b8a85e7 ("i2c: i2c-stm32f7: Add initial SMBus protocols support") Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 0f87449fc6bd..62d023e737d9 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -211,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; @@ -237,7 +238,7 @@ struct stm32f7_i2c_timings { * @size: type of SMBus protocol * @read_write: direction of SMBus protocol * SMBus block read and SMBus block write - block read process call protocols - * @smbus_buff: buffer to be used for SMBus protocol transfer. It will + * @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. -- cgit From 1e9d42194e4c8f0ba3f9d4f72b5f54050ddf7a39 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:07 +0200 Subject: i2c: gpio: move header to platform_data This header only contains platform_data. Move it to the proper directory. Signed-off-by: Wolfram Sang Acked-by: Tony Lindgren Acked-by: Lee Jones Acked-by: Robert Jarzmik Acked-by: Mauro Carvalho Chehab Acked-by: James Hogan Acked-by: Greg Ungerer --- drivers/i2c/busses/i2c-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 58abb3eced58..005e6e0330c2 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From 62ea22c4954f5b147488eefa644d668e843be6f7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:08 +0200 Subject: i2c: mux: gpio: move header to platform_data This header only contains platform_data. Move it to the proper directory. Signed-off-by: Wolfram Sang Acked-by: Peter Korsgaard --- drivers/i2c/busses/i2c-i801.c | 2 +- drivers/i2c/muxes/i2c-mux-gpio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e0d59e9ff3c6..bff160d1ce3f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -106,7 +106,7 @@ #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI #include -#include +#include #endif /* I801 SMBus address offsets */ diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 1a9973ede443..15a7cc0459fb 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include -- cgit From 985ecf00375bde7d80be03a749f5b94d5ba77ac8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:09 +0200 Subject: i2c: ocores: move header to platform_data This header only contains platform_data. Move it to the proper directory. Signed-off-by: Wolfram Sang Acked-by: Lee Jones --- drivers/i2c/busses/i2c-ocores.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 8c42ca7107b2..d7da9adf7ee1 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From 79fc540fd543f47e77e1c7d407f2c082872a4625 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:10 +0200 Subject: i2c: omap: move header to platform_data This header only contains platform_data. Move it to the proper directory. Signed-off-by: Wolfram Sang Acked-by: Tony Lindgren --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b9172f08fd05..65d06a819307 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include -- cgit From e5c7137793a754500e65ffd7477e88ff7a06ac53 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:11 +0200 Subject: i2c: pca-platform: move header to platform_data This header only contains platform_data. Move it to the proper directory. Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pca-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index bc2707ffd409..de3fe6e828cb 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From 7072b75c15271cef07792f659eaf0cc7160f6442 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:12 +0200 Subject: i2c: xiic: move header to platform_data This header only contains platform_data. Move it to the proper directory. Signed-off-by: Wolfram Sang Acked-by: Lee Jones --- drivers/i2c/busses/i2c-xiic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index c80527816ad0..0ff36f6d7a57 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From caaccda136ae3fa1c5f6563aae22ca3c199f563a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 22:00:13 +0200 Subject: i2c: pnx: move header into the driver There are no platform_data users anymore. Move the structs into the driver. Signed-off-by: Wolfram Sang Acked-by: Vladimir Zapolskiy --- drivers/i2c/busses/i2c-pnx.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a542041df0cd..6e0e546ef83f 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -29,6 +28,26 @@ #define I2C_PNX_SPEED_KHZ_DEFAULT 100 #define I2C_PNX_REGION_SIZE 0x100 +struct i2c_pnx_mif { + int ret; /* Return value */ + int mode; /* Interface mode */ + struct completion complete; /* I/O completion */ + struct timer_list timer; /* Timeout */ + u8 * buf; /* Data buffer */ + int len; /* Length of data buffer */ + int order; /* RX Bytes to order via TX */ +}; + +struct i2c_pnx_algo_data { + void __iomem *ioaddr; + struct i2c_pnx_mif mif; + int last; + struct clk *clk; + struct i2c_adapter adapter; + int irq; + u32 timeout; +}; + enum { mstatus_tdi = 0x00000001, mstatus_afi = 0x00000002, -- cgit From f56f316dcfd7d66406303acf6e51711c071b3c63 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 17 Apr 2018 16:32:30 +0200 Subject: i2c: mux: ltc4306: switch to using .probe_new Use the new probe style for i2c drivers. Acked-by: Michael Hennerich Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-ltc4306.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 311b1cced0c0..a9af93259b19 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -206,8 +206,7 @@ static const struct of_device_id ltc4306_of_match[] = { }; MODULE_DEVICE_TABLE(of, ltc4306_of_match); -static int ltc4306_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4306_probe(struct i2c_client *client) { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); const struct chip_desc *chip; @@ -221,7 +220,7 @@ static int ltc4306_probe(struct i2c_client *client, chip = of_device_get_match_data(&client->dev); if (!chip) - chip = &chips[id->driver_data]; + chip = &chips[i2c_match_id(ltc4306_id, client)->driver_data]; idle_disc = device_property_read_bool(&client->dev, "i2c-mux-idle-disconnect"); @@ -310,7 +309,7 @@ static struct i2c_driver ltc4306_driver = { .name = "ltc4306", .of_match_table = of_match_ptr(ltc4306_of_match), }, - .probe = ltc4306_probe, + .probe_new = ltc4306_probe, .remove = ltc4306_remove, .id_table = ltc4306_id, }; -- cgit From fca700d6d2190292f34282d50b613a9efb100f70 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 30 Apr 2018 14:08:42 +0200 Subject: i2c: mux: demux-pinctrl: disable PM user interface The demux device is only a logical device with no children. So, no RuntimePM is needed, let's disable the sysfs interface for it. Signed-off-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-demux-pinctrl.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 33ce032cb701..428de4c97fb2 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -254,6 +255,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); + pm_runtime_no_callbacks(&pdev->dev); + /* switch to first parent as active master */ i2c_demux_activate_master(priv, 0); -- cgit From a2f8445d4ca2796283c07d4ba8e78718071de863 Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 1 May 2018 13:42:12 +0200 Subject: i2c: mux: pca954x: force reset on probe if available Instead of just hogging the reset GPIO into deactivated state, activate and then de-activate the reset. This allows for better recovery if the CPU was reset halfway through an I2C transaction for example. Signed-off-by: Mike Looijmans Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 09bafd3e68fa..fe20b8ec5247 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -36,6 +36,7 @@ */ #include +#include #include #include #include @@ -389,10 +390,16 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, muxc); data->client = client; - /* Get the mux out of reset if a reset GPIO is specified. */ - gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); + /* Reset the mux if a reset GPIO is specified. */ + gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); + if (gpio) { + udelay(1); + gpiod_set_value_cansleep(gpio, 0); + /* Give the chip some time to recover. */ + udelay(1); + } match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) -- cgit From 04782265641839fcead0383e23e3a799f55085e3 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 25 Mar 2018 14:49:02 +0200 Subject: i2c: Retain info->of_node in i2c_new_device() Currently, of_i2c_register_devices() is responsible for retaining info->of_node, but we're about to expose a function to parse I2C board info without registering the I2C device. We could possibly let this function retain ->of_node, but this approach is prone to reference leak since people will have to remember to call of_node_put() if something goes wrong between the OF node parsing and the registration step. Let's just retain the ->of_node in i2c_new_register() instead. Signed-off-by: Boris Brezillon Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 6 ++++-- drivers/i2c/i2c-core-of.c | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index a407022fdc76..c3f17ca55fd3 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -742,7 +742,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; - client->dev.of_node = info->of_node; + client->dev.of_node = of_node_get(info->of_node); client->dev.fwnode = info->fwnode; i2c_dev_set_name(adap, client, info); @@ -753,7 +753,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) dev_err(&adap->dev, "Failed to add properties to client %s: %d\n", client->name, status); - goto out_err; + goto out_err_put_of_node; } } @@ -769,6 +769,8 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) out_free_props: if (info->properties) device_remove_properties(&client->dev); +out_err_put_of_node: + of_node_put(info->of_node); out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n", diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 15bd51eca37b..9fb38e99a6c6 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -55,7 +55,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, } info.addr = addr; - info.of_node = of_node_get(node); + info.of_node = node; if (of_property_read_bool(node, "host-notify")) info.flags |= I2C_CLIENT_HOST_NOTIFY; @@ -66,7 +66,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, client = i2c_new_device(adap, &info); if (!client) { dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node); - of_node_put(node); return ERR_PTR(-EINVAL); } return client; -- cgit From da0086d018223529c686ef46db039533572418d8 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 25 Mar 2018 14:49:03 +0200 Subject: i2c: Export of_i2c_get_board_info() I3C busses have to know about all I2C devices connected on the I3C bus to properly initialize the I3C master, and I2C frames can't be sent on the bus until this initialization is done. We can't let the I2C core parse the DT and instantiate I2C devices as part of its i2c_add_adapter() procedure because, when done this way, I2C devices are directly registered to the device-model and might be attached to drivers which could in turn start sending frames on the bus, which won't work since, as said above, the bus is not yet initialized. Export of_i2c_register_device() in order to let the I3C core parse the I2C device nodes by itself and initialize the bus. Signed-off-by: Boris Brezillon Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-of.c | 48 ++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 9fb38e99a6c6..6cb7ad608bcd 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -22,46 +22,60 @@ #include "i2c-core.h" -static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, - struct device_node *node) +int of_i2c_get_board_info(struct device *dev, struct device_node *node, + struct i2c_board_info *info) { - struct i2c_client *client; - struct i2c_board_info info = {}; u32 addr; int ret; - dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node); + memset(info, 0, sizeof(*info)); - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { - dev_err(&adap->dev, "of_i2c: modalias failure on %pOF\n", - node); - return ERR_PTR(-EINVAL); + if (of_modalias_node(node, info->type, sizeof(info->type)) < 0) { + dev_err(dev, "of_i2c: modalias failure on %pOF\n", node); + return -EINVAL; } ret = of_property_read_u32(node, "reg", &addr); if (ret) { - dev_err(&adap->dev, "of_i2c: invalid reg on %pOF\n", node); - return ERR_PTR(ret); + dev_err(dev, "of_i2c: invalid reg on %pOF\n", node); + return ret; } if (addr & I2C_TEN_BIT_ADDRESS) { addr &= ~I2C_TEN_BIT_ADDRESS; - info.flags |= I2C_CLIENT_TEN; + info->flags |= I2C_CLIENT_TEN; } if (addr & I2C_OWN_SLAVE_ADDRESS) { addr &= ~I2C_OWN_SLAVE_ADDRESS; - info.flags |= I2C_CLIENT_SLAVE; + info->flags |= I2C_CLIENT_SLAVE; } - info.addr = addr; - info.of_node = node; + info->addr = addr; + info->of_node = node; if (of_property_read_bool(node, "host-notify")) - info.flags |= I2C_CLIENT_HOST_NOTIFY; + info->flags |= I2C_CLIENT_HOST_NOTIFY; if (of_get_property(node, "wakeup-source", NULL)) - info.flags |= I2C_CLIENT_WAKE; + info->flags |= I2C_CLIENT_WAKE; + + return 0; +} +EXPORT_SYMBOL_GPL(of_i2c_get_board_info); + +static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, + struct device_node *node) +{ + struct i2c_client *client; + struct i2c_board_info info; + int ret; + + dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node); + + ret = of_i2c_get_board_info(&adap->dev, node, &info); + if (ret) + return ERR_PTR(ret); client = i2c_new_device(adap, &info); if (!client) { -- cgit From 40f4e372cba8a6729c997c0bda1fa03adf7f956e Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 May 2018 00:00:16 -0700 Subject: i2c: xlp9xx: Add support for SMBAlert Add support for SMBus alert mechanism to i2c-xlp9xx driver. The second interrupt is parsed to use for SMBus alert. The first interrupt is the i2c controller main interrupt. Signed-off-by: Kamlakant Patel Signed-off-by: George Cherian Reviewed-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index eb8913eba0c5..fe545127a74b 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,8 @@ struct xlp9xx_i2c_dev { struct device *dev; struct i2c_adapter adapter; struct completion msg_complete; + struct i2c_smbus_alert_setup alert_data; + struct i2c_client *ara; int irq; bool msg_read; bool len_recv; @@ -447,6 +450,19 @@ static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, return 0; } +static int xlp9xx_i2c_smbus_setup(struct xlp9xx_i2c_dev *priv, + struct platform_device *pdev) +{ + if (!priv->alert_data.irq) + return -EINVAL; + + priv->ara = i2c_setup_smbus_alert(&priv->adapter, &priv->alert_data); + if (!priv->ara) + return -ENODEV; + + return 0; +} + static int xlp9xx_i2c_probe(struct platform_device *pdev) { struct xlp9xx_i2c_dev *priv; @@ -467,6 +483,10 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "invalid irq!\n"); return priv->irq; } + /* SMBAlert irq */ + priv->alert_data.irq = platform_get_irq(pdev, 1); + if (priv->alert_data.irq <= 0) + priv->alert_data.irq = 0; xlp9xx_i2c_get_frequency(pdev, priv); xlp9xx_i2c_init(priv); @@ -493,6 +513,10 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) if (err) return err; + err = xlp9xx_i2c_smbus_setup(priv, pdev); + if (err) + dev_dbg(&pdev->dev, "No active SMBus alert %d\n", err); + platform_set_drvdata(pdev, priv); dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); -- cgit From 8d504d804ab657779254bdd37079d2442d75cbe8 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 May 2018 00:00:17 -0700 Subject: i2c: xlp9xx: Fix issue seen when updating receive length The hardware does not handle updates to the length register gracefully if the new value is less than the number of bytes received so far. If this happens, the i2c controller will not stop the receive transaction properly. Fix this by ensuring that the updated length is ok. This is done by making sure that the new length written to hardware is at least few bytes more than the bytes received so far. While at that refactor the length updation to a new function. Signed-off-by: Jayachandran C Signed-off-by: George Cherian Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index fe545127a74b..c268fde5bbd9 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -158,9 +158,28 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) priv->msg_buf += len; } +static void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv) +{ + u32 val, len; + + /* + * Update receive length. Re-read len to get the latest value, + * and then add 4 to have a minimum value that can be safely + * written. This is to account for the byte read above, the + * transfer in progress and any delays in the register I/O + */ + val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); + len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & + XLP9XX_I2C_FIFO_WCNT_MASK; + len = max_t(u32, priv->msg_len, len + 4); + val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | + (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); +} + static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) { - u32 len, i, val; + u32 len, i; u8 rlen, *buf = priv->msg_buf; len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & @@ -171,20 +190,13 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) /* read length byte */ rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); *buf++ = rlen; - len--; - if (priv->client_pec) ++rlen; /* update remaining bytes and message length */ priv->msg_buf_remaining = rlen; priv->msg_len = rlen + 1; priv->len_recv = false; - - /* Update transfer length to read only actual data */ - val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); - val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | - ((rlen + 1) << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); - xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); + xlp9xx_i2c_update_rlen(priv); } else { len = min(priv->msg_buf_remaining, len); for (i = 0; i < len; i++, buf++) -- cgit From 88b4116e7e98454c2131094336e4f8861eebbd85 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 16 May 2018 00:00:18 -0700 Subject: i2c: xlp9xx: Make sure the transfer size is not more than I2C_SMBUS_BLOCK_SIZE For SMBus transactions the max permissible transfer size is I2C_SMBUS_BLOCK_SIZE. It is possible that some clients might not follow it strictly occasionally. This would lead to stack corruption if the driver copies more than I2C_SMBUS_BLOCK_SIZE bytes. Add a check to avoid such conditions. Signed-off-by: Jayachandran C Signed-off-by: George Cherian Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index c268fde5bbd9..1f41a4f89c08 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -172,6 +172,8 @@ static void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv) len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & XLP9XX_I2C_FIFO_WCNT_MASK; len = max_t(u32, priv->msg_len, len + 4); + if (len >= I2C_SMBUS_BLOCK_MAX + 2) + return; val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); @@ -189,14 +191,20 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) if (priv->len_recv) { /* read length byte */ rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); - *buf++ = rlen; - if (priv->client_pec) - ++rlen; - /* update remaining bytes and message length */ - priv->msg_buf_remaining = rlen; - priv->msg_len = rlen + 1; - priv->len_recv = false; + if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) { + rlen = 0; /*abort transfer */ + priv->msg_buf_remaining = 0; + priv->msg_len = 0; + } else { + *buf++ = rlen; + if (priv->client_pec) + ++rlen; /* account for error check byte */ + /* update remaining bytes and message length */ + priv->msg_buf_remaining = rlen; + priv->msg_len = rlen + 1; + } xlp9xx_i2c_update_rlen(priv); + priv->len_recv = false; } else { len = min(priv->msg_buf_remaining, len); for (i = 0; i < len; i++, buf++) @@ -315,10 +323,6 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, XLP9XX_I2C_MFIFOCTRL_RST); - /* set FIFO threshold if reading */ - if (priv->msg_read) - xlp9xx_i2c_update_rx_fifo_thres(priv); - /* set slave addr */ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | @@ -337,9 +341,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, val &= ~XLP9XX_I2C_CTRL_ADDMODE; priv->len_recv = msg->flags & I2C_M_RECV_LEN; - len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len; + len = priv->len_recv ? I2C_SMBUS_BLOCK_MAX + 2 : msg->len; priv->client_pec = msg->flags & I2C_CLIENT_PEC; + /* set FIFO threshold if reading */ + if (priv->msg_read) + xlp9xx_i2c_update_rx_fifo_thres(priv); + /* set data length to be transferred */ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); @@ -393,8 +401,11 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, } /* update msg->len with actual received length */ - if (msg->flags & I2C_M_RECV_LEN) + if (msg->flags & I2C_M_RECV_LEN) { + if (!priv->msg_len) + return -EPROTO; msg->len = priv->msg_len; + } return 0; } -- cgit From b30c08a24caa89b28c84f09f0d1de94e9017cc36 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 1 Feb 2018 17:17:19 +0100 Subject: i2c: mux: reg: failed memory allocation is logged elsewhere Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Alexander Sverdlin Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-reg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index c948e5a4cb04..f624ed64a47b 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -127,10 +127,8 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, values = devm_kzalloc(&pdev->dev, sizeof(*mux->data.values) * mux->data.n_values, GFP_KERNEL); - if (!values) { - dev_err(&pdev->dev, "Cannot allocate values array"); + if (!values) return -ENOMEM; - } for_each_child_of_node(np, child) { of_property_read_u32(child, "reg", values + i); -- cgit From f657c9fe26888274b9d22ad3cdc796dd945be8aa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 21 May 2018 09:34:13 +0200 Subject: i2c: mux: improve error message for failed symlink Trivial, but still: the failed symlink is not *for* the channel but a link *to* the channel. Signed-off-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/i2c-mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 9669ca4937b8..300ab4b672e4 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -418,7 +418,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id); WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj, symlink_name), - "can't create symlink for channel %u\n", chan_id); + "can't create symlink to channel %u\n", chan_id); dev_info(&parent->dev, "Added multiplexed i2c bus %d\n", i2c_adapter_id(&priv->adap)); -- cgit From 5a9dcd81908bb2bc6d8ed22bc4b7eec191024557 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 21 May 2018 09:29:38 +0200 Subject: i2c: mux: demux-pinctrl: use proper parent device for demux adapter Due to a typo, the wrong parent device was assigned to the newly created demuxing adapter device. It got connected to the demuxing platform device but not to the selected parent I2C adapter device. Fix it to get a proper parent-child relationship of the demuxed busses. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-demux-pinctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 428de4c97fb2..035032e20327 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -106,7 +106,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne priv->cur_adap.owner = THIS_MODULE; priv->cur_adap.algo = &priv->algo; priv->cur_adap.algo_data = priv; - priv->cur_adap.dev.parent = priv->dev; + priv->cur_adap.dev.parent = &adap->dev; priv->cur_adap.class = adap->class; priv->cur_adap.retries = adap->retries; priv->cur_adap.timeout = adap->timeout; -- cgit From b10d7a1fd6fcb16f242ffbd87bf0466b337708d6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 21 May 2018 11:49:08 +0200 Subject: i2c: mux: pca954x: merge calls to of_match_device and of_device_get_match_data Drop call to of_match_device, which is subsumed by the subsequent call to of_device_get_match_data. The code becomes simpler, and a temporary variable can be dropped. The semantic match that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r@ local idexpression match; identifier i; expression x, dev, e, e1; @@ - match@i = of_match_device(x, dev); - if (match) e = of_device_get_match_data(dev); - else e = e1; + e = of_device_get_match_data(dev); + if (!e) e = e1; @@ identifier r.i; @@ - const struct of_device_id *i; ... when != i // Signed-off-by: Julia Lawall Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index fe20b8ec5247..fbc748027087 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -374,7 +374,6 @@ static int pca954x_probe(struct i2c_client *client, int num, force, class; struct i2c_mux_core *muxc; struct pca954x *data; - const struct of_device_id *match; int ret; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) @@ -401,10 +400,8 @@ static int pca954x_probe(struct i2c_client *client, udelay(1); } - match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); - if (match) - data->chip = of_device_get_match_data(&client->dev); - else + data->chip = of_device_get_match_data(&client->dev); + if (!data->chip) data->chip = &chips[id->driver_data]; if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) { -- cgit From ef9fc0bad52246f70aa078f679d74db53b5ca675 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 20 May 2018 12:46:35 -0300 Subject: i2c: imx: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d7267dd9c7bf..e0fc3c06b607 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2002 Motorola GSG-China * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * Author: * Darius Augulis, Teltonika Inc. * -- cgit From c216b870657af8b6967445e5fbf3bb95942a53c9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 May 2018 08:50:33 +0200 Subject: i2c: ibm_iic: don't check number of messages in the driver Since commit 1eace8344c02 ("i2c: add param sanity check to i2c_transfer()"), the I2C core does this check now. We can remove it from drivers. Signed-off-by: Wolfram Sang Reviewed-by: Peter Rosin --- drivers/i2c/busses/i2c-ibm_iic.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 961c5f42d956..6f6e1dfe7cce 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -561,9 +561,6 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num); - if (!num) - return 0; - /* Check the sanity of the passed messages. * Uhh, generic i2c layer is more suitable place for such code... */ -- cgit From 05d4707d468dc7497a680d811e102fcc71ef93ef Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 May 2018 08:50:34 +0200 Subject: i2c: opal: don't check number of messages in the driver Since commit 1eace8344c02 ("i2c: add param sanity check to i2c_transfer()") and b7f625840267 ("i2c: add quirk checks to core"), the I2C core does this check now. We can remove it here. Signed-off-by: Wolfram Sang Reviewed-by: Peter Rosin --- drivers/i2c/busses/i2c-opal.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index 0aabb7eca0c5..dc2a23f4fb52 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -94,8 +94,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, */ memset(&req, 0, sizeof(req)); switch(num) { - case 0: - return 0; case 1: req.type = (msgs[0].flags & I2C_M_RD) ? OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE; @@ -114,8 +112,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, req.size = cpu_to_be32(msgs[1].len); req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf)); break; - default: - return -EOPNOTSUPP; } rc = i2c_opal_send_request(opal_id, &req); -- cgit From 17dd94796c4e039fdf8f9a813fbe71582ceff65e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 18 May 2018 08:45:30 +0800 Subject: i2c: rk3x: Don't print visible virtual mapping MMIO address Now %p doesn't print visible pointer address unless the user really want it. According to Documentation/core-api/printk-formats.rst, %px should be used instead, otherwise we could see: rk3x-i2c ff110000.i2c: Initialized RK3xxx I2C bus at (____ptrval____) rk3x-i2c ff130000.i2c: Initialized RK3xxx I2C bus at (____ptrval____) rk3x-i2c ff3c0000.i2c: Initialized RK3xxx I2C bus at (____ptrval____) rk3x-i2c ff3d0000.i2c: Initialized RK3xxx I2C bus at (____ptrval____) But I don't really understand why we need dump it in the first place! Let's remove the whole pointless log. Signed-off-by: Shawn Lin Reviewed-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index e1a18d989f83..b8a2728dd4b6 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1326,8 +1326,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) if (ret < 0) goto err_clk_notifier; - dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); - return 0; err_clk_notifier: -- cgit From 7fb29b958dfff9c8eddfe4250aa0ed3614446c62 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 9 May 2018 21:46:57 +0200 Subject: i2c: robotfuzz-osif: remove pointless local variable Just use the value directly instead of assigning it to a variable first. And then drop the unused variable. Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-robotfuzz-osif.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index 9c0f52b7ff7e..51d93b4b00f2 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -63,26 +63,23 @@ static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, struct osif_priv *priv = adapter->algo_data; struct i2c_msg *pmsg; int ret = 0; - int i, cmd; + int i; for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; if (pmsg->flags & I2C_M_RD) { - cmd = OSIFI2C_READ; - - ret = osif_usb_read(adapter, cmd, pmsg->flags, - pmsg->addr, pmsg->buf, - pmsg->len); + ret = osif_usb_read(adapter, OSIFI2C_READ, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len); if (ret != pmsg->len) { dev_err(&adapter->dev, "failure reading data\n"); return -EREMOTEIO; } } else { - cmd = OSIFI2C_WRITE; - - ret = osif_usb_write(adapter, cmd, pmsg->flags, - pmsg->addr, pmsg->buf, pmsg->len); + ret = osif_usb_write(adapter, OSIFI2C_WRITE, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len); if (ret != pmsg->len) { dev_err(&adapter->dev, "failure writing data\n"); return -EREMOTEIO; -- cgit From 6a0c0d0d009e6c09700cf92dec0860ade1f56f4c Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 9 May 2018 21:46:58 +0200 Subject: i2c: robotfuzz-osif: drop pointless test In the for-loop test, ret will be either 0 or 1. So, the comparison is pointless. Drop it, and drop the initializer which is then also pointless. Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-robotfuzz-osif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index 51d93b4b00f2..d848cf515234 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -62,10 +62,10 @@ static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, { struct osif_priv *priv = adapter->algo_data; struct i2c_msg *pmsg; - int ret = 0; + int ret; int i; - for (i = 0; ret >= 0 && i < num; i++) { + for (i = 0; i < num; i++) { pmsg = &msgs[i]; if (pmsg->flags & I2C_M_RD) { -- cgit From 902a91a02bdf027e9466ac29d0cdce7b8687fff3 Mon Sep 17 00:00:00 2001 From: Austin Christ Date: Thu, 10 May 2018 10:13:54 -0600 Subject: i2c: qup: add probe path for Centriq ACPI devices Add support for Qualcomm Centriq devices that are qup-v2 compatible but do not support DMA, so nodma needs to be set. Signed-off-by: Austin Christ Reviewed-by: Sricharan R Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 904dfec7ab96..c024f85e73d1 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1648,6 +1648,14 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) clk_disable_unprepare(qup->pclk); } +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id qup_i2c_acpi_match[] = { + { "QCOM8010"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); +#endif + static int qup_i2c_probe(struct platform_device *pdev) { static const int blk_sizes[] = {4, 16, 32}; @@ -1682,7 +1690,10 @@ static int qup_i2c_probe(struct platform_device *pdev) } else { qup->adap.algo = &qup_i2c_algo_v2; is_qup_v1 = false; - ret = qup_i2c_req_dma(qup); + if (acpi_match_device(qup_i2c_acpi_match, qup->dev)) + goto nodma; + else + ret = qup_i2c_req_dma(qup); if (ret == -EPROBE_DEFER) goto fail_dma; @@ -1959,14 +1970,6 @@ static const struct of_device_id qup_i2c_dt_match[] = { }; MODULE_DEVICE_TABLE(of, qup_i2c_dt_match); -#if IS_ENABLED(CONFIG_ACPI) -static const struct acpi_device_id qup_i2c_acpi_match[] = { - { "QCOM8010"}, - { }, -}; -MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); -#endif - static struct platform_driver qup_i2c_driver = { .probe = qup_i2c_probe, .remove = qup_i2c_remove, -- cgit From 109b8c42b7e28ddf843488f01f243a9c9eba032b Mon Sep 17 00:00:00 2001 From: Austin Christ Date: Thu, 10 May 2018 10:13:55 -0600 Subject: i2c: qup: Add support for Fast Mode Plus Previously the QUP driver limited operation mode to I2C Fast Mode. Add Fast Mode Plus functionality by raising SCL limit from 400kHz to 1MHz. Signed-off-by: Austin Christ Reviewed-by: Sricharan R Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index c024f85e73d1..ce5f215cd7e8 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -136,8 +136,13 @@ */ #define TOUT_MIN 2 +/* I2C Frequency Modes */ +#define I2C_STANDARD_FREQ 100000 +#define I2C_FAST_MODE_FREQ 400000 +#define I2C_FAST_MODE_PLUS_FREQ 1000000 + /* Default values. Use these if FW query fails */ -#define DEFAULT_CLK_FREQ 100000 +#define DEFAULT_CLK_FREQ I2C_STANDARD_FREQ #define DEFAULT_SRC_CLK 20000000 /* @@ -1745,8 +1750,8 @@ static int qup_i2c_probe(struct platform_device *pdev) } nodma: - /* We support frequencies up to FAST Mode (400KHz) */ - if (!clk_freq || clk_freq > 400000) { + /* We support frequencies up to FAST Mode Plus (1MHz) */ + if (!clk_freq || clk_freq > I2C_FAST_MODE_PLUS_FREQ) { dev_err(qup->dev, "clock frequency not supported %d\n", clk_freq); return -EINVAL; -- cgit From 71fbafcc45fed7c647987495900b8f6ff29fc5aa Mon Sep 17 00:00:00 2001 From: Austin Christ Date: Thu, 10 May 2018 10:13:56 -0600 Subject: i2c: qup: Correct duty cycle for FM and FM+ The I2C spec UM10204 Rev. 6 specifies the following timings. Standard Fast Mode Fast Mode Plus SCL low 4.7us 1.3us 0.5us SCL high 4.0us 0.6us 0.26us This results in a 33%/66% duty cycle as opposed to the 50%/50% duty cycle used for Standard-mode. Add High Time Divider settings to correct duty cycle for FM(400kHz) and FM+(1MHz). Signed-off-by: Austin Christ Reviewed-by: Sricharan R Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index ce5f215cd7e8..f87f29f5be65 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1855,9 +1855,15 @@ nodma: size = QUP_INPUT_FIFO_SIZE(io_mode); qup->in_fifo_sz = qup->in_blk_sz * (2 << size); - fs_div = ((src_clk_freq / clk_freq) / 2) - 3; hs_div = 3; - qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff); + if (clk_freq <= I2C_STANDARD_FREQ) { + fs_div = ((src_clk_freq / clk_freq) / 2) - 3; + qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff); + } else { + /* 33%/66% duty cycle */ + fs_div = ((src_clk_freq / clk_freq) - 6) * 2 / 3; + qup->clk_ctl = ((fs_div / 2) << 16) | (hs_div << 8) | (fs_div & 0xff); + } /* * Time it takes for a byte to be clocked out on the bus. -- cgit From d9f52281bc09bd49374486f5e21fad7b8d3a5b3c Mon Sep 17 00:00:00 2001 From: Austin Christ Date: Thu, 10 May 2018 10:13:57 -0600 Subject: i2c: qup: Add command-line parameter to override SCL frequency Add a module parameter to override SCL frequency provided by firmware. This can be useful when testing spec compliance for I2C modes or when debugging issues across multiple operating frequencies. Signed-off-by: Austin Christ Reviewed-by: Sricharan R Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index f87f29f5be65..c1bbeaae2095 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -155,6 +155,10 @@ /* TAG length for DATA READ in RX FIFO */ #define READ_RX_TAGS_LEN 2 +static unsigned int scl_freq; +module_param_named(scl_freq, scl_freq, uint, 0444); +MODULE_PARM_DESC(scl_freq, "SCL frequency override"); + /* * count: no of blocks * pos: current block number @@ -1682,10 +1686,15 @@ static int qup_i2c_probe(struct platform_device *pdev) init_completion(&qup->xfer); platform_set_drvdata(pdev, qup); - ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq); - if (ret) { - dev_notice(qup->dev, "using default clock-frequency %d", - DEFAULT_CLK_FREQ); + if (scl_freq) { + dev_notice(qup->dev, "Using override frequency of %u\n", scl_freq); + clk_freq = scl_freq; + } else { + ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq); + if (ret) { + dev_notice(qup->dev, "using default clock-frequency %d", + DEFAULT_CLK_FREQ); + } } if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { -- cgit From ac6d5298f6af763b587495d62041fe57a2fb89e6 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 16 May 2018 09:16:46 +0200 Subject: i2c: algos: make use of i2c_8bit_addr_from_msg Because it looks neater. Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/algos/i2c-algo-bit.c | 4 +--- drivers/i2c/algos/i2c-algo-pca.c | 5 +---- drivers/i2c/algos/i2c-algo-pcf.c | 8 ++------ 3 files changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 3df0efd69ae3..4a34f311e1ff 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -519,9 +519,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) } } } else { /* normal 7bit address */ - addr = msg->addr << 1; - if (flags & I2C_M_RD) - addr |= 1; + addr = i2c_8bit_addr_from_msg(msg); if (flags & I2C_M_REV_DIR_ADDR) addr ^= 1; ret = try_address(i2c_adap, addr, retries); diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index e370804ec8bc..883a290f6a4d 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -112,11 +112,8 @@ static int pca_address(struct i2c_algo_pca_data *adap, struct i2c_msg *msg) { int sta = pca_get_con(adap); - int addr; + int addr = i2c_8bit_addr_from_msg(msg); - addr = ((0x7f & msg->addr) << 1); - if (msg->flags & I2C_M_RD) - addr |= 1; DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n", msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr); diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 270d84bfc2c6..5c29a4d397cf 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -291,13 +291,9 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, static int pcf_doAddress(struct i2c_algo_pcf_data *adap, struct i2c_msg *msg) { - unsigned short flags = msg->flags; - unsigned char addr; + unsigned char addr = i2c_8bit_addr_from_msg(msg); - addr = msg->addr << 1; - if (flags & I2C_M_RD) - addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR) + if (msg->flags & I2C_M_REV_DIR_ADDR) addr ^= 1; i2c_outb(adap, addr); -- cgit From 30a6475744cf11f31a296cb85b43bab40ebbea92 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 16 May 2018 09:16:47 +0200 Subject: i2c: busses: make use of i2c_8bit_addr_from_msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because it looks neater. For diolan, this allows factoring out some code that is now common between if and else. For eg20t, pch_i2c_writebytes is always called with a write in msgs->flags, and pch_i2c_readbytes with a read. For imx, i2c_imx_dma_write and i2c_imx_write are always called with a write in msgs->flags, and i2c_imx_read with a read. For qup, qup_i2c_write_tx_fifo_v1 is always called with a write in qup->msg->flags. For stu300, also restructure debug output for resends, since that code as a result is only handling debug output. Reviewed-by: Guenter Roeck [diolan] Acked-by: Uwe Kleine-König [efm32 and imx] Acked-by: Linus Walleij [stu300] Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-aspeed.c | 3 +-- drivers/i2c/busses/i2c-axxia.c | 5 +++-- drivers/i2c/busses/i2c-diolan-u2c.c | 11 ++++------- drivers/i2c/busses/i2c-efm32.c | 3 +-- drivers/i2c/busses/i2c-eg20t.c | 5 ++--- drivers/i2c/busses/i2c-emev2.c | 2 +- drivers/i2c/busses/i2c-hix5hd2.c | 9 ++------- drivers/i2c/busses/i2c-imx-lpi2c.c | 4 +--- drivers/i2c/busses/i2c-imx.c | 10 +++++----- drivers/i2c/busses/i2c-kempld.c | 7 +++---- drivers/i2c/busses/i2c-mxs.c | 9 +++------ drivers/i2c/busses/i2c-ocores.c | 5 +---- drivers/i2c/busses/i2c-pasemi.c | 2 +- drivers/i2c/busses/i2c-qup.c | 2 +- drivers/i2c/busses/i2c-rcar.c | 2 +- drivers/i2c/busses/i2c-riic.c | 5 ++--- drivers/i2c/busses/i2c-stu300.c | 22 +++++++++++++--------- drivers/i2c/busses/i2c-xiic.c | 11 ++--------- 18 files changed, 47 insertions(+), 70 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 7d4aeb4465b3..60e4d0e939a3 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -335,13 +335,12 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) { u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; - u8 slave_addr = msg->addr << 1; + u8 slave_addr = i2c_8bit_addr_from_msg(msg); bus->master_state = ASPEED_I2C_MASTER_START; bus->buf_index = 0; if (msg->flags & I2C_M_RD) { - slave_addr |= 1; command |= ASPEED_I2CD_M_RX_CMD; /* Need to let the hardware know to NACK after RX. */ if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index 12f92369888b..8e60048a33f8 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -351,13 +351,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) * addr_2: addr[7:0] */ addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06); + if (i2c_m_rd(msg)) + addr_1 |= 1; /* Set the R/nW bit of the address */ addr_2 = msg->addr & 0xFF; } else { /* 7-bit address * addr_1: addr[6:0] | (R/nW) * addr_2: dont care */ - addr_1 = (msg->addr << 1) & 0xFF; + addr_1 = i2c_8bit_addr_from_msg(msg); addr_2 = 0; } @@ -365,7 +367,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) /* I2C read transfer */ rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len; tx_xfer = 0; - addr_1 |= 1; /* Set the R/nW bit of the address */ } else { /* I2C write transfer */ rx_xfer = 0; diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index f718ee4e3332..3f28317cde39 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -360,11 +360,11 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, if (ret < 0) goto abort; } + ret = diolan_i2c_put_byte_ack(dev, + i2c_8bit_addr_from_msg(pmsg)); + if (ret < 0) + goto abort; if (pmsg->flags & I2C_M_RD) { - ret = - diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1); - if (ret < 0) - goto abort; for (j = 0; j < pmsg->len; j++) { u8 byte; bool ack = j < pmsg->len - 1; @@ -393,9 +393,6 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, pmsg->buf[j] = byte; } } else { - ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1); - if (ret < 0) - goto abort; for (j = 0; j < pmsg->len; j++) { ret = diolan_i2c_put_byte_ack(dev, pmsg->buf[j]); diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index aa336ba89aa3..5f2bab878b2c 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -144,8 +144,7 @@ static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata) struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg]; efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START); - efm32_i2c_write32(ddata, REG_TXDATA, cur_msg->addr << 1 | - (cur_msg->flags & I2C_M_RD ? 1 : 0)); + efm32_i2c_write32(ddata, REG_TXDATA, i2c_8bit_addr_from_msg(cur_msg)); } static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata) diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index bdeab0174fec..835d54ac2971 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -414,7 +414,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, iowrite32(addr_8_lsb, p + PCH_I2CDR); } else { /* set 7 bit slave address and R/W bit as 0 */ - iowrite32(addr << 1, p + PCH_I2CDR); + iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR); if (first) pch_i2c_start(adap); } @@ -538,8 +538,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); } else { /* 7 address bits + R/W bit */ - addr = (((addr) << 1) | (I2C_RD)); - iowrite32(addr, p + PCH_I2CDR); + iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR); } /* check if it is the first message */ diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index d2e84480fbe9..ba9b6ea48a31 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -149,7 +149,7 @@ static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0); /* Send slave address and R/W type */ - writeb((msg->addr << 1) | read, priv->base + I2C_OFS_IIC0); + writeb(i2c_8bit_addr_from_msg(msg), priv->base + I2C_OFS_IIC0); /* Wait for transaction */ status = em_i2c_wait_for_event(priv); diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index f69dd6e46f2d..061a4bfb03f4 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -73,7 +73,6 @@ #define I2C_OVER_INTR BIT(0) #define HIX5I2C_MAX_FREQ 400000 /* 400k */ -#define HIX5I2C_READ_OPERATION 0x01 enum hix5hd2_i2c_state { HIX5I2C_STAT_RW_ERR = -1, @@ -311,12 +310,8 @@ static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop) hix5hd2_i2c_clr_all_irq(priv); hix5hd2_i2c_enable_irq(priv); - if (priv->msg->flags & I2C_M_RD) - writel_relaxed((priv->msg->addr << 1) | HIX5I2C_READ_OPERATION, - priv->regs + HIX5I2C_TXR); - else - writel_relaxed(priv->msg->addr << 1, - priv->regs + HIX5I2C_TXR); + writel_relaxed(i2c_8bit_addr_from_msg(priv->msg), + priv->regs + HIX5I2C_TXR); writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index e6da2c7a9a3e..159d23211600 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -180,15 +180,13 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msgs) { unsigned int temp; - u8 read; temp = readl(lpi2c_imx->base + LPI2C_MCR); temp |= MCR_RRF | MCR_RTF; writel(temp, lpi2c_imx->base + LPI2C_MCR); writel(0x7f00, lpi2c_imx->base + LPI2C_MSR); - read = msgs->flags & I2C_M_RD; - temp = (msgs->addr << 1 | read) | (GEN_START << 8); + temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8); writel(temp, lpi2c_imx->base + LPI2C_MTDR); return lpi2c_imx_bus_busy(lpi2c_imx); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index e0fc3c06b607..0207e194f84b 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -621,7 +621,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, * Write slave address. * The first byte must be transmitted by the CPU. */ - imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); reinit_completion(&i2c_imx->dma->cmd_complete); time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, @@ -751,10 +751,10 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) int i, result; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", - __func__, msgs->addr << 1); + __func__, i2c_8bit_addr_from_msg(msgs)); /* write slave address */ - imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); result = i2c_imx_trx_complete(i2c_imx); if (result) return result; @@ -787,10 +787,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", - __func__, (msgs->addr << 1) | 0x01); + __func__, i2c_8bit_addr_from_msg(msgs)); /* write slave address */ - imx_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_imx, IMX_I2C_I2DR); + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); result = i2c_imx_trx_complete(i2c_imx); if (result) return result; diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index e879190b5d1d..1c874aaa0447 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -124,15 +124,14 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c) /* 10 bit address? */ if (i2c->msg->flags & I2C_M_TEN) { addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6); + /* Set read bit if necessary */ + addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; i2c->state = STATE_ADDR10; } else { - addr = (i2c->msg->addr << 1); + addr = i2c_8bit_addr_from_msg(i2c->msg); i2c->state = STATE_START; } - /* Set read bit if necessary */ - addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; - kempld_write8(pld, KEMPLD_I2C_DATA, addr); kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index e617bd600794..f62ae3d42232 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -180,9 +180,10 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, struct dma_async_tx_descriptor *desc; struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); + i2c->addr_data = i2c_8bit_addr_from_msg(msg); + if (msg->flags & I2C_M_RD) { i2c->dma_read = true; - i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; /* * SELECT command. @@ -240,7 +241,6 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, } } else { i2c->dma_read = false; - i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; /* * WRITE command. @@ -371,7 +371,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, uint32_t flags) { struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); - uint32_t addr_data = msg->addr << 1; + uint32_t addr_data = i2c_8bit_addr_from_msg(msg); uint32_t data = 0; int i, ret, xlen = 0, xmit = 0; uint32_t start; @@ -411,8 +411,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, */ BUG_ON(msg->len > 4); - addr_data |= I2C_SMBUS_READ; - /* SELECT command. */ mxs_i2c_pio_trigger_write_cmd(i2c, MXS_CMD_I2C_SELECT, addr_data); @@ -450,7 +448,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, * fast enough. It is possible to transfer arbitrary amount * of data using PIO write. */ - addr_data |= I2C_SMBUS_WRITE; /* * The LSB of data buffer is the first byte blasted across diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index d7da9adf7ee1..c214e29cb19b 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -222,10 +222,7 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) i2c->nmsgs = num; i2c->state = STATE_START; - oc_setreg(i2c, OCI2C_DATA, - (i2c->msg->addr << 1) | - ((i2c->msg->flags & I2C_M_RD) ? 1:0)); - + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index df1dbc92a024..55fd5c6f3cca 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -121,7 +121,7 @@ static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter, read = msg->flags & I2C_M_RD ? 1 : 0; - TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read); + TXFIFO_WR(smbus, MTXFIFO_START | i2c_8bit_addr_from_msg(msg)); if (read) { TXFIFO_WR(smbus, msg->len | MTXFIFO_READ | diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index c1bbeaae2095..4f793b5d0c3b 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -462,7 +462,7 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) { struct qup_i2c_block *blk = &qup->blk; struct i2c_msg *msg = qup->msg; - u32 addr = msg->addr << 1; + u32 addr = i2c_8bit_addr_from_msg(msg); u32 qup_tag; int idx; u32 val; diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 9d8d5b91220f..5e310efd9446 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -329,7 +329,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) if (priv->msgs_left == 1) priv->flags |= ID_LAST_MSG; - rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); + rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg)); /* * We don't have a test case but the HW engineers say that the write order * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 95c2f1ce3cad..5f1fca7880b1 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -167,15 +167,14 @@ static irqreturn_t riic_tdre_isr(int irq, void *data) return IRQ_NONE; if (riic->bytes_left == RIIC_INIT_MSG) { - val = !!(riic->msg->flags & I2C_M_RD); - if (val) + if (riic->msg->flags & I2C_M_RD) /* On read, switch over to receive interrupt */ riic_clear_set_bit(riic, ICIER_TIE, ICIER_RIE, RIIC_ICIER); else /* On write, initialize length */ riic->bytes_left = riic->msg->len; - val |= (riic->msg->addr << 1); + val = i2c_8bit_addr_from_msg(riic->msg); } else { val = *riic->buf; riic->buf++; diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index dc63236b45b2..e866c481bfc3 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -602,20 +602,24 @@ static int stu300_send_address(struct stu300_dev *dev, u32 val; int ret; - if (msg->flags & I2C_M_TEN) + if (msg->flags & I2C_M_TEN) { /* This is probably how 10 bit addresses look */ val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) & I2C_DR_D_MASK; - else - val = ((msg->addr << 1) & I2C_DR_D_MASK); + if (msg->flags & I2C_M_RD) + /* This is the direction bit */ + val |= 0x01; + } else { + val = i2c_8bit_addr_from_msg(msg); + } - if (msg->flags & I2C_M_RD) { - /* This is the direction bit */ - val |= 0x01; - if (resend) + if (resend) { + if (msg->flags & I2C_M_RD) dev_dbg(&dev->pdev->dev, "read resend\n"); - } else if (resend) - dev_dbg(&dev->pdev->dev, "write resend\n"); + else + dev_dbg(&dev->pdev->dev, "write resend\n"); + } + stu300_wr8(val, dev->virtbase + I2C_DR); /* For 10bit addressing, await 10bit request (EVENT 9) */ diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index e3161fe048eb..9a71e50d21f1 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -143,12 +143,6 @@ struct xiic_i2c { #define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS) -/* The following constants are used with the following macros to specify the - * operation, a read or write operation. - */ -#define XIIC_READ_OPERATION 1 -#define XIIC_WRITE_OPERATION 0 - /* * Tx Fifo upper bit masks. */ @@ -556,8 +550,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, - (msg->addr << 1) | XIIC_READ_OPERATION | - XIIC_TX_DYN_START_MASK); + i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK); xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); @@ -585,7 +578,7 @@ static void xiic_start_send(struct xiic_i2c *i2c) if (!(msg->flags & I2C_M_NOSTART)) { /* write the address */ - u16 data = ((msg->addr << 1) & 0xfe) | XIIC_WRITE_OPERATION | + u16 data = i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK; if ((i2c->nmsgs == 1) && msg->len == 0) /* no data and last message -> add STOP */ -- cgit From ed49aaeefdb9c436142ccbea37bdf13079b199e6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 30 May 2018 16:35:54 -0300 Subject: i2c: mxs: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index f62ae3d42232..642c58946d8d 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale MXS I2C bus driver * @@ -7,12 +8,6 @@ * based on a (non-working) driver which was: * * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #include -- cgit From eedeaed289315726f0d9ea83094f49d8523623ac Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 30 May 2018 16:35:55 -0300 Subject: i2c: imx-lpi2c: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx-lpi2c.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 159d23211600..6d975f5221ca 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * This is i.MX low power i2c controller driver. * * Copyright 2016 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include -- cgit From 535ba90472da812a55e5b95d30a916597c4f5f90 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 14 May 2018 00:13:47 +0300 Subject: i2c: tegra: Remove suspend-resume Nothing prevents I2C clients to access I2C while Tegra's driver is being suspended, this results in -EBUSY error returned to the clients and that may have unfortunate consequences. In particular this causes problems for the TPS6586x MFD driver which emits hundreds of "failed to read interrupt status" error messages on resume from suspend. This happens if TPS6586X is used to wake system from suspend by the expired RTC alarm timer because TPS6586X is an I2C device driver and its IRQ handler reads the status register while Tegra's I2C driver is suspended, i.e. just after kernel enabled IRQ's during of resume-from-suspend process. Note that the removed tegra_i2c_resume() invoked tegra_i2c_init() which performs HW reset. That seems was also not entirely correct because moving tegra_i2c_resume to an earlier stage of resume-from-suspend process causes I2C transfer to fail in the case of TPS6586X. It is fine to remove the HW-reinitialization for now because it should be only needed in a case of using lowest power-mode during suspend, which upstream kernel doesn't support. Signed-off-by: Dmitry Osipenko Acked-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 60292d243e24..5fccd1f1bca8 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -173,7 +173,6 @@ struct tegra_i2c_hw_feature { * @msg_buf_remaining: size of unsent data in the message buffer * @msg_read: identifies read transfers * @bus_clk_rate: current i2c bus clock rate - * @is_suspended: prevents i2c controller accesses after suspend is called */ struct tegra_i2c_dev { struct device *dev; @@ -194,7 +193,6 @@ struct tegra_i2c_dev { int msg_read; u32 bus_clk_rate; u16 clk_divisor_non_hs_mode; - bool is_suspended; bool is_multimaster_mode; spinlock_t xfer_lock; }; @@ -734,9 +732,6 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int i; int ret = 0; - if (i2c_dev->is_suspended) - return -EBUSY; - ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) { dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret); @@ -1051,37 +1046,9 @@ static int tegra_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int tegra_i2c_suspend(struct device *dev) -{ - struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); - - i2c_lock_adapter(&i2c_dev->adapter); - i2c_dev->is_suspended = true; - i2c_unlock_adapter(&i2c_dev->adapter); - - return 0; -} - -static int tegra_i2c_resume(struct device *dev) -{ - struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); - int ret; - - i2c_lock_adapter(&i2c_dev->adapter); - - ret = tegra_i2c_init(i2c_dev); - if (!ret) - i2c_dev->is_suspended = false; - - i2c_unlock_adapter(&i2c_dev->adapter); - - return ret; -} - static const struct dev_pm_ops tegra_i2c_pm = { SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) }; #define TEGRA_I2C_PM (&tegra_i2c_pm) #else -- cgit From 53e39628ac228fada53cc0106be62c6f65f67501 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 30 May 2018 23:31:49 +0200 Subject: i2c: qup: fix building without CONFIG_ACPI The added Centriq support broke compilation with CONFIG_ACPI disabled: drivers/i2c/busses/i2c-qup.c: In function 'qup_i2c_probe': drivers/i2c/busses/i2c-qup.c:1707:25: error: 'qup_i2c_acpi_match' undeclared (first use in this function); did you mean 'qup_i2c_recv_data'? This fixes it by removing the extraneous #ifdef. All ACPI specific code will be dropped implicitly when that option is disabled, but the compiler first needs to see it. Fixes: 902a91a02bdf ("i2c: qup: add probe path for Centriq ACPI devices") Signed-off-by: Arnd Bergmann Reviewed-by: Austin Christ Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4f793b5d0c3b..9cfcc0473227 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1657,13 +1657,11 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) clk_disable_unprepare(qup->pclk); } -#if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id qup_i2c_acpi_match[] = { { "QCOM8010"}, { }, }; MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); -#endif static int qup_i2c_probe(struct platform_device *pdev) { -- cgit