From f1c87ceb02912201dff70e58fd15761292951b09 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Jan 2018 13:11:29 +0100 Subject: [PATCH 01/53] i2c: of: change log level of failed device creation If we cannot create a device, this is an error, not a warning. Fix the log level. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 8d474bb1dc15..b652579ed04e 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -103,7 +103,7 @@ void of_i2c_register_devices(struct i2c_adapter *adap) client = of_i2c_register_device(adap, node); if (IS_ERR(client)) { - dev_warn(&adap->dev, + dev_err(&adap->dev, "Failed to create I2C device for %pOF\n", node); of_node_clear_flag(node, OF_POPULATED); From e6db2d3278ac2fff9e0e33e9cc4274ae7f14d9f2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Jan 2018 13:11:30 +0100 Subject: [PATCH 02/53] i2c: of: make ref counting more visible When debugging a ref counting problem, I overlooked this snipplet a few times. Might be taste, but I think the new location is visually easier recognizable. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index b652579ed04e..5e2d55b3daac 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -64,8 +64,8 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, } info.addr = addr; - info.of_node = of_node_get(node); info.archdata = &dev_ad; + info.of_node = of_node_get(node); if (of_property_read_bool(node, "host-notify")) info.flags |= I2C_CLIENT_HOST_NOTIFY; From c49b0e077594b2cb5531eacd88664badb2635e7f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Jan 2018 13:11:31 +0100 Subject: [PATCH 03/53] i2c: of: rename variable to meet expectations 'result' is mostly used in the kernel as int for functions returning errno on failure. Here it is a pointer to the client struct, so let's call it this way (as the parent function does, too). Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-of.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 5e2d55b3daac..4b573ee4a820 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -25,7 +25,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, struct device_node *node) { - struct i2c_client *result; + struct i2c_client *client; struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr_be; @@ -73,13 +73,13 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; - result = i2c_new_device(adap, &info); - if (result == NULL) { + 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 result; + return client; } void of_i2c_register_devices(struct i2c_adapter *adap) From 4f3ae38acb3c93cbd8aab9a9fb76d5f661ab578d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Jan 2018 13:11:32 +0100 Subject: [PATCH 04/53] i2c: of: remove duplicated check for valid address The very same check is done when calling i2c_new_device(). Remove it here to avoid code duplication. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-of.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 4b573ee4a820..bbfff3f61b1f 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -57,12 +57,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, info.flags |= I2C_CLIENT_SLAVE; } - if (i2c_check_addr_validity(addr, info.flags)) { - dev_err(&adap->dev, "of_i2c: invalid addr=%x on %pOF\n", - addr, node); - return ERR_PTR(-EINVAL); - } - info.addr = addr; info.archdata = &dev_ad; info.of_node = of_node_get(node); From a1671af2863376abb9f200c5db3c9097c0490e87 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Jan 2018 13:11:33 +0100 Subject: [PATCH 05/53] i2c: of: simplify reading the "reg" property of_get_property() is a bit cumbersome to use. Replace it with the newer of_property_read_u32() for more readable code. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-of.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index bbfff3f61b1f..c405270a98b4 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -4,7 +4,7 @@ * Copyright (C) 2008 Jochen Friedrich * based on a previous patch from Jon Smirl * - * Copyright (C) 2013 Wolfram Sang + * Copyright (C) 2013, 2018 Wolfram Sang * * 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 @@ -28,9 +28,8 @@ 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 = {}; - const __be32 *addr_be; u32 addr; - int len; + int ret; dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node); @@ -40,13 +39,12 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, return ERR_PTR(-EINVAL); } - addr_be = of_get_property(node, "reg", &len); - if (!addr_be || (len < sizeof(*addr_be))) { + 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(-EINVAL); + return ERR_PTR(ret); } - addr = be32_to_cpup(addr_be); if (addr & I2C_TEN_BIT_ADDRESS) { addr &= ~I2C_TEN_BIT_ADDRESS; info.flags |= I2C_CLIENT_TEN; From d0adf769df210248f60d33e62b1d4d14df271c02 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Mon, 29 Jan 2018 16:45:47 +0100 Subject: [PATCH 06/53] dt-bindings: i2c: document R8A77995 bindings R-Car D3 (R8A77995) SoC has a R-Car Gen3-compatible I2C controller. Signed-off-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-rcar.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index a777477e4547..e91dbafe71e5 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -14,6 +14,7 @@ Required properties: "renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC. "renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC. "renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC. + "renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC. "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device. "renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible device. From c2a3b3cce8df1cafeda2ab03563d7e703c51a4ac Mon Sep 17 00:00:00 2001 From: Dmitry Bazhenov Date: Thu, 18 Jan 2018 05:39:21 +0000 Subject: [PATCH 07/53] i2c: xlp9xx: return ENXIO on slave address NACK Fix the driver violation of the common practice to return ENXIO error on a slave address NACK. Signed-off-by: Dmitry Bazhenov Signed-off-by: George Cherian Tested-by: dann frazier Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index b970bf8f38e5..6d78cdc5cf91 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -324,7 +324,8 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) xlp9xx_i2c_init(priv); - return -EIO; + return (priv->msg_err & XLP9XX_I2C_INTEN_NACKADDR) ? + -ENXIO : -EIO; } if (timeleft == 0) { From 41b1d4de96323e84c0a902e7e4b2c0f367e77f92 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Thu, 18 Jan 2018 05:39:22 +0000 Subject: [PATCH 08/53] i2c: xlp9xx: Handle transactions with I2C_M_RECV_LEN properly In case of transaction with I2C_M_RECV_LEN set, make sure the driver reads the first byte and then updates the RX fifo with the expected length. Set threshold to 1 byte so that driver gets an interrupt on receiving the first byte. After which the transfer length is updated depending on the received length. Also report SMBus block read functionality. Signed-off-by: George Cherian Tested-by: dann frazier Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 35 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 6d78cdc5cf91..1f6d78087af9 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -125,7 +125,16 @@ static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv) { u32 thres; - thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); + if (priv->len_recv) + /* interrupt after the first read to examine + * the length byte before proceeding further + */ + thres = 1; + else if (priv->msg_buf_remaining > XLP9XX_I2C_FIFO_SIZE) + thres = XLP9XX_I2C_FIFO_SIZE; + else + thres = priv->msg_buf_remaining; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT); } @@ -144,7 +153,7 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) { - u32 len, i; + u32 len, i, val; u8 rlen, *buf = priv->msg_buf; len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & @@ -156,19 +165,27 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) 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); + } else { + len = min(priv->msg_buf_remaining, len); + for (i = 0; i < len; i++, buf++) + *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + + priv->msg_buf_remaining -= len; } - len = min(priv->msg_buf_remaining, len); - for (i = 0; i < len; i++, buf++) - *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); - - priv->msg_buf_remaining -= len; priv->msg_buf = buf; if (priv->msg_buf_remaining) @@ -357,8 +374,8 @@ static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | - I2C_FUNC_10BIT_ADDR; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; } static const struct i2c_algorithm xlp9xx_i2c_algo = { From 939c5a46e5cac7524b327d43ae826fd6941fa2aa Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 27 Feb 2018 08:19:00 +0100 Subject: [PATCH 09/53] i2c: exynos5: rework HSI2C_MASTER_ST_LOSE state handling HSI2C_MASTER_ST_LOSE state is not documented properly, extensive tests show that hardware is usually able to recover from this state without interrupting the transfer. Moreover documentation says that such state can be caused by slave clock stretching, and should not be treated as an error during transaction. The only place it indicates an error is just before starting transaction. In such case bus recovery procedure should be performed - master should pulse SCL line nine times and then send STOP condition, it can be repeated until SDA goes high. The procedure can be performed using manual commands HSI2C_CMD_READ_DATA and HSI2C_CMD_SEND_STOP. Signed-off-by: Andrzej Hajda Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 63 +++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index b02428498f6d..12ec8484e653 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -128,6 +128,10 @@ #define HSI2C_TIMEOUT_EN (1u << 31) #define HSI2C_TIMEOUT_MASK 0xff +/* I2C_MANUAL_CMD register bits */ +#define HSI2C_CMD_READ_DATA (1u << 4) +#define HSI2C_CMD_SEND_STOP (1u << 2) + /* I2C_TRANS_STATUS register bits */ #define HSI2C_MASTER_BUSY (1u << 17) #define HSI2C_SLAVE_BUSY (1u << 16) @@ -441,12 +445,6 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->state = -ETIMEDOUT; goto stop; } - - trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); - if ((trans_status & HSI2C_MASTER_ST_MASK) == HSI2C_MASTER_ST_LOSE) { - i2c->state = -EAGAIN; - goto stop; - } } else if (int_status & HSI2C_INT_I2C) { trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); if (trans_status & HSI2C_NO_DEV_ACK) { @@ -544,6 +542,57 @@ static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c) return -EBUSY; } +static void exynos5_i2c_bus_recover(struct exynos5_i2c *i2c) +{ + u32 val; + + val = readl(i2c->regs + HSI2C_CTL) | HSI2C_RXCHON; + writel(val, i2c->regs + HSI2C_CTL); + val = readl(i2c->regs + HSI2C_CONF) & ~HSI2C_AUTO_MODE; + writel(val, i2c->regs + HSI2C_CONF); + + /* + * Specification says master should send nine clock pulses. It can be + * emulated by sending manual read command (nine pulses for read eight + * bits + one pulse for NACK). + */ + writel(HSI2C_CMD_READ_DATA, i2c->regs + HSI2C_MANUAL_CMD); + exynos5_i2c_wait_bus_idle(i2c); + writel(HSI2C_CMD_SEND_STOP, i2c->regs + HSI2C_MANUAL_CMD); + exynos5_i2c_wait_bus_idle(i2c); + + val = readl(i2c->regs + HSI2C_CTL) & ~HSI2C_RXCHON; + writel(val, i2c->regs + HSI2C_CTL); + val = readl(i2c->regs + HSI2C_CONF) | HSI2C_AUTO_MODE; + writel(val, i2c->regs + HSI2C_CONF); +} + +static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) +{ + unsigned long timeout; + + if (i2c->variant->hw != HSI2C_EXYNOS7) + return; + + /* + * HSI2C_MASTER_ST_LOSE state in EXYNOS7 variant before transaction + * indicates that bus is stuck (SDA is low). In such case bus recovery + * can be performed. + */ + timeout = jiffies + msecs_to_jiffies(100); + for (;;) { + u32 st = readl(i2c->regs + HSI2C_TRANS_STATUS); + + if ((st & HSI2C_MASTER_ST_MASK) != HSI2C_MASTER_ST_LOSE) + return; + + if (time_is_before_jiffies(timeout)) + return; + + exynos5_i2c_bus_recover(i2c); + } +} + /* * exynos5_i2c_message_start: Configures the bus and starts the xfer * i2c: struct exynos5_i2c pointer for the current bus @@ -598,6 +647,8 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL); writel(i2c_ctl, i2c->regs + HSI2C_CTL); + exynos5_i2c_bus_check(i2c); + /* * Enable interrupts before starting the transfer so that we don't * miss any INT_I2C interrupts. From bead21687f293cb1e1365703f11cf1cc6aaaf833 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Jan 2018 17:44:04 +0000 Subject: [PATCH 10/53] i2c-stm32f4: remove redundant initialization of pointer reg The pointer reg is assigned a value that is never read, it is later overwritten with a new value, hence the redundant initialization can be removed. Cleans up clang warning: drivers/i2c/busses/i2c-stm32f4.c:352:16: warning: Value stored to 'reg' during its initialization is never read Signed-off-by: Colin Ian King Acked-by: Alexandre TORGUE Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 47c8d00de53f..ba600d77a3f8 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -349,7 +349,7 @@ static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev) static void stm32f4_i2c_terminate_xfer(struct stm32f4_i2c_dev *i2c_dev) { struct stm32f4_i2c_msg *msg = &i2c_dev->msg; - void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2; + void __iomem *reg; stm32f4_i2c_disable_irq(i2c_dev); From 84cb55c422816d96e8871f7663194949eca98fa6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 26 Feb 2018 16:26:43 +0100 Subject: [PATCH 11/53] dt-bindings: i2c: sh_mobile: Document R-Car M3-N support Document support for the IIC Bus Interface for DVFS (IIC for DVFS) in the Renesas M3-N (r8a77965) SoC. No driver update is needed. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt index 224390999e81..fc7e17802746 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt @@ -13,6 +13,7 @@ Required properties: - "renesas,iic-r8a7794" (R-Car E2) - "renesas,iic-r8a7795" (R-Car H3) - "renesas,iic-r8a7796" (R-Car M3-W) + - "renesas,iic-r8a77965" (R-Car M3-N) - "renesas,iic-sh73a0" (SH-Mobile AG5) - "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1 compatible device) From be5b928038ba1906f064290affb35bcd3bc74844 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 26 Feb 2018 22:17:53 +0100 Subject: [PATCH 12/53] i2c: reformat comments around i2c_smbus_xfer_emulated() Use Kernel coding style for better readability. Signed-off-by: Wolfram Sang Reviewed-by: Peter Rosin --- drivers/i2c/i2c-core-smbus.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 59d5cf376f6a..b5aec33002c3 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -308,17 +308,21 @@ static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val) msg->buf[0] = init_val; } -/* Simulate a SMBus command using the i2c protocol - No checking of parameters is done! */ +/* + * Simulate a SMBus command using the I2C protocol. + * No checking of parameters is done! + */ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { - /* So we need to generate a series of msgs. In the case of writing, we - need to use only one message; when reading, we need two. We initialize - most things with sane defaults, to keep the code below somewhat - simpler. */ + /* + * So we need to generate a series of msgs. In the case of writing, we + * need to use only one message; when reading, we need two. We + * initialize most things with sane defaults, to keep the code below + * somewhat simpler. + */ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ ? 2 : 1; From 0e89b2fec748177899c1f9ebfbe87714ffa248eb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 26 Feb 2018 12:46:52 -0800 Subject: [PATCH 13/53] i2c: piix4: Use usleep_range() The piix4 i2c driver is extremely slow. Replacing msleep() with usleep_range() increases its speed substantially. Use sleep ranges similar to those used in the i2c-801 driver to keep things simple. Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-piix4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 462948e2c535..4c1f6aaec0fc 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -462,13 +462,13 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter) /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */ - msleep(2); + usleep_range(2000, 2100); else - msleep(1); + usleep_range(250, 500); while ((++timeout < MAX_TIMEOUT) && ((temp = inb_p(SMBHSTSTS)) & 0x01)) - msleep(1); + usleep_range(250, 500); /* If the SMBus is still busy, we give up */ if (timeout == MAX_TIMEOUT) { From 04b6fcaba346e1ce76321ba9b0fd549da4c37ac2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 26 Feb 2018 12:46:53 -0800 Subject: [PATCH 14/53] i2c: piix4: Use request_muxed_region Accesses to SB800_PIIX4_SMB_IDX can occur from multiple drivers. One example for another driver is the sp5100_tco driver. Use request_muxed_region() to ensure synchronization. Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-piix4.c | 55 ++++++++++++++++------------------ 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 4c1f6aaec0fc..90946a8b9a75 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -40,7 +40,6 @@ #include #include #include -#include /* PIIX4 SMBus address offsets */ @@ -153,10 +152,7 @@ static const struct dmi_system_id piix4_dmi_ibm[] = { /* * SB800 globals - * piix4_mutex_sb800 protects piix4_port_sel_sb800 and the pair - * of I/O ports at SB800_PIIX4_SMB_IDX. */ -static DEFINE_MUTEX(piix4_mutex_sb800); static u8 piix4_port_sel_sb800; static u8 piix4_port_mask_sb800; static u8 piix4_port_shift_sb800; @@ -298,12 +294,19 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, else smb_en = (aux) ? 0x28 : 0x2c; - mutex_lock(&piix4_mutex_sb800); + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) { + dev_err(&PIIX4_dev->dev, + "SMB base address index region 0x%x already in use.\n", + SB800_PIIX4_SMB_IDX); + return -EBUSY; + } + outb_p(smb_en, SB800_PIIX4_SMB_IDX); smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX); smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1); - mutex_unlock(&piix4_mutex_sb800); + + release_region(SB800_PIIX4_SMB_IDX, 2); if (!smb_en) { smb_en_status = smba_en_lo & 0x10; @@ -373,7 +376,12 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, break; } } else { - mutex_lock(&piix4_mutex_sb800); + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, + "sb800_piix4_smb")) { + release_region(piix4_smba, SMBIOSIZE); + return -EBUSY; + } + outb_p(SB800_PIIX4_PORT_IDX_SEL, SB800_PIIX4_SMB_IDX); port_sel = inb_p(SB800_PIIX4_SMB_IDX + 1); piix4_port_sel_sb800 = (port_sel & 0x01) ? @@ -381,7 +389,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, SB800_PIIX4_PORT_IDX; piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK; piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT; - mutex_unlock(&piix4_mutex_sb800); + release_region(SB800_PIIX4_SMB_IDX, 2); } dev_info(&PIIX4_dev->dev, @@ -679,7 +687,8 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, u8 port; int retval; - mutex_lock(&piix4_mutex_sb800); + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) + return -EBUSY; /* Request the SMBUS semaphore, avoid conflicts with the IMC */ smbslvcnt = inb_p(SMBSLVCNT); @@ -695,8 +704,8 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, } while (--retries); /* SMBus is still owned by the IMC, we give up */ if (!retries) { - mutex_unlock(&piix4_mutex_sb800); - return -EBUSY; + retval = -EBUSY; + goto release; } /* @@ -753,8 +762,8 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, if ((size == I2C_SMBUS_BLOCK_DATA) && adapdata->notify_imc) piix4_imc_wakeup(); - mutex_unlock(&piix4_mutex_sb800); - +release: + release_region(SB800_PIIX4_SMB_IDX, 2); return retval; } @@ -899,13 +908,6 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) bool notify_imc = false; is_sb800 = true; - if (!request_region(SB800_PIIX4_SMB_IDX, 2, "smba_idx")) { - dev_err(&dev->dev, - "SMBus base address index region 0x%x already in use!\n", - SB800_PIIX4_SMB_IDX); - return -EBUSY; - } - if (dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) { u8 imc; @@ -922,20 +924,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) /* base address location etc changed in SB800 */ retval = piix4_setup_sb800(dev, id, 0); - if (retval < 0) { - release_region(SB800_PIIX4_SMB_IDX, 2); + if (retval < 0) return retval; - } /* * Try to register multiplexed main SMBus adapter, * give up if we can't */ retval = piix4_add_adapters_sb800(dev, retval, notify_imc); - if (retval < 0) { - release_region(SB800_PIIX4_SMB_IDX, 2); + if (retval < 0) return retval; - } } else { retval = piix4_setup(dev, id); if (retval < 0) @@ -983,11 +981,8 @@ static void piix4_adap_remove(struct i2c_adapter *adap) if (adapdata->smba) { i2c_del_adapter(adap); - if (adapdata->port == (0 << piix4_port_shift_sb800)) { + if (adapdata->port == (0 << piix4_port_shift_sb800)) release_region(adapdata->smba, SMBIOSIZE); - if (adapdata->sb800_main) - release_region(SB800_PIIX4_SMB_IDX, 2); - } kfree(adapdata); kfree(adap); } From e9d09d97af7c8047959fcaae4217d80c26b2949c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 1 Mar 2018 09:04:13 +0100 Subject: [PATCH 15/53] i2c: scmi: Use standard device message logging functions ACPI_ERROR and ACPI_DEBUG_PRINT are not intended to be used by device drivers. Use acpi_handle message logging functions instead. As a nice side effect, it removes the following compiler warnings which were printed when ACPI debug is disabled: drivers/i2c/busses/i2c-scmi.c: In function "acpi_smbus_cmi_add_cap": drivers/i2c/busses/i2c-scmi.c:328:39: warning: suggest braces around empty body in an "else" statement [-Wempty-body] drivers/i2c/busses/i2c-scmi.c:338:12: warning: suggest braces around empty body in an "else" statement [-Wempty-body] Suggested-by: "Rafael J. Wysocki" Signed-off-by: Jean Delvare Reviewed-by: Rafael J. Wysocki Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-scmi.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 7aa7b9cb6203..a01389b85f13 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -182,7 +182,8 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, status = acpi_evaluate_object(smbus_cmi->handle, method, &input, &buffer); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Evaluating %s: %i", method, status)); + acpi_handle_err(smbus_cmi->handle, + "Failed to evaluate %s: %i\n", method, status); return -EIO; } @@ -190,19 +191,19 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, if (pkg && pkg->type == ACPI_TYPE_PACKAGE) obj = pkg->package.elements; else { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n"); result = -EIO; goto out; } if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n"); result = -EIO; goto out; } result = obj->integer.value; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s return status: %i\n", - method, result)); + acpi_handle_debug(smbus_cmi->handle, "%s return status: %i\n", method, + result); switch (result) { case ACPI_SMBUS_STATUS_OK: @@ -227,7 +228,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, obj = pkg->package.elements + 1; if (obj->type != ACPI_TYPE_INTEGER) { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n"); result = -EIO; goto out; } @@ -239,7 +240,8 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE_DATA: case I2C_SMBUS_WORD_DATA: if (obj->type != ACPI_TYPE_INTEGER) { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(smbus_cmi->handle, + "Invalid argument type\n"); result = -EIO; goto out; } @@ -250,7 +252,8 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, break; case I2C_SMBUS_BLOCK_DATA: if (obj->type != ACPI_TYPE_BUFFER) { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(smbus_cmi->handle, + "Invalid argument type\n"); result = -EIO; goto out; } @@ -300,6 +303,7 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, const char *name) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_handle *handle = smbus_cmi->handle; union acpi_object *obj; acpi_status status; @@ -308,8 +312,8 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, smbus_cmi->methods->mt_info, NULL, &buffer); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Evaluating %s: %i", - smbus_cmi->methods->mt_info, status)); + acpi_handle_err(handle, "Failed to evaluate %s: %i\n", + smbus_cmi->methods->mt_info, status); return -EIO; } @@ -317,18 +321,18 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, if (obj && obj->type == ACPI_TYPE_PACKAGE) obj = obj->package.elements; else { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(handle, "Invalid argument type\n"); kfree(buffer.pointer); return -EIO; } if (obj->type != ACPI_TYPE_INTEGER) { - ACPI_ERROR((AE_INFO, "Invalid argument type")); + acpi_handle_err(handle, "Invalid argument type\n"); kfree(buffer.pointer); return -EIO; } else - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SMBus CMI Version %x" - "\n", (int)obj->integer.value)); + acpi_handle_debug(handle, "SMBus CMI Version %x\n", + (int)obj->integer.value); kfree(buffer.pointer); smbus_cmi->cap_info = 1; @@ -337,8 +341,7 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, else if (!strcmp(name, smbus_cmi->methods->mt_sbw)) smbus_cmi->cap_write = 1; else - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", - name)); + acpi_handle_debug(handle, "Unsupported CMI method: %s\n", name); return 0; } From af503716ac1444db61d80cb6d17cfe62929c21df Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sun, 3 Dec 2017 22:40:50 +0100 Subject: [PATCH 16/53] i2c: core: report OF style module alias for devices registered via OF The buses should honor the firmware interface used to register the device, but the I2C core reports a MODALIAS of the form i2c: even for I2C devices registered via OF. This means that user-space will never get an OF stype uevent MODALIAS even when the drivers modules contain aliases exported from both the I2C and OF device ID tables. For example, an Atmel maXTouch Touchscreen registered by a DT node with compatible "atmel,maxtouch" has the following module alias: $ cat /sys/class/i2c-adapter/i2c-8/8-004b/modalias i2c:maxtouch So udev won't be able to auto-load a module for an OF-only device driver. Many OF-only drivers duplicate the OF device ID table entries in an I2C ID table only has a workaround for how the I2C core reports the module alias. This patch changes the I2C core to report an OF related MODALIAS uevent if the device was registered via OF. So for the previous example, after this patch, the reported MODALIAS for the Atmel maXTouch will be the following: $ cat /sys/class/i2c-adapter/i2c-8/8-004b/modalias of:NtrackpadTCatmel,maxtouch NOTE: This patch may break out-of-tree drivers that were relying on this behavior, and only had an I2C device ID table even when the device was registered via OF. There are no remaining drivers in mainline that do this, but out-of-tree drivers have to be fixed and define a proper OF device ID table to have module auto-loading working. Signed-off-by: Javier Martinez Canillas Tested-by: Dmitry Mastykin Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 5a00bf443d06..edfc23e49630 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -124,6 +124,10 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) struct i2c_client *client = to_i2c_client(dev); int rc; + rc = of_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; + rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; @@ -439,6 +443,10 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf) struct i2c_client *client = to_i2c_client(dev); int len; + len = of_device_modalias(dev, buf, PAGE_SIZE); + if (len != -ENODEV) + return len; + len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; From dde67eb1beebcd8493e7b30e74a80f0865ab7e36 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 22 Jan 2018 08:32:01 +0100 Subject: [PATCH 17/53] i2c: add i2c_get_device_id() to get the standard i2c device id Can be used during probe to double check that the probed device is what is expected. Loosely based on code from Adrian Fiergolski . Tested-by: Adrian Fiergolski Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/i2c-core-base.c | 33 +++++++++++++++++++++++++++++++++ include/linux/i2c.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 5a00bf443d06..aa03eeb43814 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -58,6 +58,8 @@ #define I2C_ADDR_7BITS_MAX 0x77 #define I2C_ADDR_7BITS_COUNT (I2C_ADDR_7BITS_MAX + 1) +#define I2C_ADDR_DEVICE_ID 0x7c + /* * core_lock protects i2c_adapter_idr, and guarantees that device detection, * deletion of detected devices, and attach_adapter calls are serialized @@ -1968,6 +1970,37 @@ int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, } EXPORT_SYMBOL(i2c_transfer_buffer_flags); +/** + * i2c_get_device_id - get manufacturer, part id and die revision of a device + * @client: The device to query + * @id: The queried information + * + * Returns negative errno on error, zero on success. + */ +int i2c_get_device_id(const struct i2c_client *client, + struct i2c_device_identity *id) +{ + struct i2c_adapter *adap = client->adapter; + union i2c_smbus_data raw_id; + int ret; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) + return -EOPNOTSUPP; + + raw_id.block[0] = 3; + ret = i2c_smbus_xfer(adap, I2C_ADDR_DEVICE_ID, 0, + I2C_SMBUS_READ, client->addr << 1, + I2C_SMBUS_I2C_BLOCK_DATA, &raw_id); + if (ret) + return ret; + + id->manufacturer_id = (raw_id.block[1] << 4) | (raw_id.block[2] >> 4); + id->part_id = ((raw_id.block[2] & 0xf) << 5) | (raw_id.block[3] >> 3); + id->die_revision = raw_id.block[3] & 0x7; + return 0; +} +EXPORT_SYMBOL_GPL(i2c_get_device_id); + /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 419a38e7c315..44ad14e016b5 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -47,6 +47,7 @@ struct i2c_algorithm; struct i2c_adapter; struct i2c_client; struct i2c_driver; +struct i2c_device_identity; union i2c_smbus_data; struct i2c_board_info; enum i2c_slave_event; @@ -186,8 +187,37 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, extern s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, u8 command, u8 length, u8 *values); +int i2c_get_device_id(const struct i2c_client *client, + struct i2c_device_identity *id); #endif /* I2C */ +/** + * struct i2c_device_identity - i2c client device identification + * @manufacturer_id: 0 - 4095, database maintained by NXP + * @part_id: 0 - 511, according to manufacturer + * @die_revision: 0 - 7, according to manufacturer + */ +struct i2c_device_identity { + u16 manufacturer_id; +#define I2C_DEVICE_ID_NXP_SEMICONDUCTORS 0 +#define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_1 1 +#define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_2 2 +#define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_3 3 +#define I2C_DEVICE_ID_RAMTRON_INTERNATIONAL 4 +#define I2C_DEVICE_ID_ANALOG_DEVICES 5 +#define I2C_DEVICE_ID_STMICROELECTRONICS 6 +#define I2C_DEVICE_ID_ON_SEMICONDUCTOR 7 +#define I2C_DEVICE_ID_SPRINTEK_CORPORATION 8 +#define I2C_DEVICE_ID_ESPROS_PHOTONICS_AG 9 +#define I2C_DEVICE_ID_FUJITSU_SEMICONDUCTOR 10 +#define I2C_DEVICE_ID_FLIR 11 +#define I2C_DEVICE_ID_O2MICRO 12 +#define I2C_DEVICE_ID_ATMEL 13 +#define I2C_DEVICE_ID_NONE 0xffff + u16 part_id; + u8 die_revision; +}; + enum i2c_alert_protocol { I2C_PROTOCOL_SMBUS_ALERT, I2C_PROTOCOL_SMBUS_HOST_NOTIFY, From 2d74187d5b4e29776e151ffcc09bdaedfd46e002 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 22 Jan 2018 08:40:02 +0100 Subject: [PATCH 18/53] i2c: mux: pca954x: verify the device id of the pca984x chips Make sure to not disallow the chips on adapters that are not capable of reading the device id, but also make sure to check the device id before writing to the chip. Tested-by: Adrian Fiergolski Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 55 +++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index fbb84c7ef282..09bafd3e68fa 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -77,6 +77,7 @@ struct chip_desc { pca954x_ismux = 0, pca954x_isswi } muxtype; + struct i2c_device_identity id; }; struct pca954x { @@ -97,59 +98,83 @@ static const struct chip_desc chips[] = { .nchans = 2, .enable = 0x4, .muxtype = pca954x_ismux, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9542] = { .nchans = 2, .enable = 0x4, .has_irq = 1, .muxtype = pca954x_ismux, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9543] = { .nchans = 2, .has_irq = 1, .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9544] = { .nchans = 4, .enable = 0x4, .has_irq = 1, .muxtype = pca954x_ismux, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9545] = { .nchans = 4, .has_irq = 1, .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9546] = { .nchans = 4, .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9547] = { .nchans = 8, .enable = 0x8, .muxtype = pca954x_ismux, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9548] = { .nchans = 8, .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9846] = { .nchans = 4, .muxtype = pca954x_isswi, + .id = { + .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, + .part_id = 0x10b, + }, }, [pca_9847] = { .nchans = 8, .enable = 0x8, .muxtype = pca954x_ismux, + .id = { + .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, + .part_id = 0x108, + }, }, [pca_9848] = { .nchans = 8, .muxtype = pca954x_isswi, + .id = { + .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, + .part_id = 0x10a, + }, }, [pca_9849] = { .nchans = 4, .enable = 0x4, .muxtype = pca954x_ismux, + .id = { + .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, + .part_id = 0x109, + }, }, }; @@ -369,6 +394,30 @@ static int pca954x_probe(struct i2c_client *client, if (IS_ERR(gpio)) return PTR_ERR(gpio); + 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 = &chips[id->driver_data]; + + if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) { + struct i2c_device_identity id; + + ret = i2c_get_device_id(client, &id); + if (ret && ret != -EOPNOTSUPP) + return ret; + + if (!ret && + (id.manufacturer_id != data->chip->id.manufacturer_id || + id.part_id != data->chip->id.part_id)) { + dev_warn(&client->dev, + "unexpected device id %03x-%03x-%x\n", + id.manufacturer_id, id.part_id, + id.die_revision); + return -ENODEV; + } + } + /* Write the mux register at addr to verify * that the mux is in fact present. This also * initializes the mux to disconnected state. @@ -378,12 +427,6 @@ static int pca954x_probe(struct i2c_client *client, return -ENODEV; } - 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 = &chips[id->driver_data]; - data->last_chan = 0; /* force the first selection */ idle_disconnect_dt = of_node && From 74d23319fd16cae28a2cbb53a213fe0765ac2028 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Sat, 10 Mar 2018 09:40:56 -0800 Subject: [PATCH 19/53] i2c: xiic: Make suspend function names consistent Suspend functions seem to have been copied from i2c-cadence driver. Rename the functions to match the rest of the driver. Signed-off-by: Moritz Fischer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index ae6ed254e01d..c80527816ad0 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -851,7 +851,7 @@ static const struct of_device_id xiic_of_match[] = { MODULE_DEVICE_TABLE(of, xiic_of_match); #endif -static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) +static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) { struct xiic_i2c *i2c = dev_get_drvdata(dev); @@ -860,7 +860,7 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) +static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev) { struct xiic_i2c *i2c = dev_get_drvdata(dev); int ret; @@ -875,8 +875,8 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) } static const struct dev_pm_ops xiic_dev_pm_ops = { - SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend, - cdns_i2c_runtime_resume, NULL) + SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend, + xiic_i2c_runtime_resume, NULL) }; static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, From 31184d8c6ea49ea0676d100cdd7e1f102ad025b5 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 14 Mar 2018 18:03:40 +0100 Subject: [PATCH 20/53] i2c: mv64xxx: Apply errata delay only in standard mode The errata FE-8471889 description has been updated. There is still a timing violation for repeated start. But the errata now states that it was only the case for the Standard mode (100 kHz), in Fast mode (400 kHz) there is no issue. This patch limit the errata fix to the Standard mode. It has been tesed successfully on the clearfog (Aramda 388 based board). Signed-off-by: Gregory CLEMENT Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 440fe4a96e68..a5a95ea5b81a 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -845,12 +845,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, */ if (of_device_is_compatible(np, "marvell,mv78230-i2c")) { drv_data->offload_enabled = true; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) { drv_data->offload_enabled = false; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) From 03e73e6349662e32d9d2e64c453affcd03b864a4 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 14 Mar 2018 18:08:11 +0100 Subject: [PATCH 21/53] MAINTAINERS: i2c-mv64xxx: update email address for Gregory CLEMENT Free Electrons is now Bootlin, change my email address accordingly Signed-off-by: Gregory CLEMENT Signed-off-by: Wolfram Sang --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 93a12af4f180..1c5a2d0e993a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6572,7 +6572,7 @@ F: drivers/i2c/muxes/ F: include/linux/i2c-mux.h I2C MV64XXX MARVELL AND ALLWINNER DRIVER -M: Gregory CLEMENT +M: Gregory CLEMENT L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-mv64xxx.c From 7a20e707aae2562ad1e6fc39bbc0fa9fd47a6390 Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Thu, 8 Mar 2018 16:23:53 +0300 Subject: [PATCH 22/53] i2c: designware: suppress unneeded SDA hold time warnings The hardware may not support SDA hold time configuration, but if it is not set in the Device Tree either, there is no need to print a warning. Reported-by: Thomas Petazzoni Signed-off-by: Alexander Monakov Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 05732531829f..fd36c39ddf4e 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -163,7 +163,7 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); - } else { + } else if (dev->sda_hold_time) { dev_warn(dev->dev, "Hardware too old to adjust SDA hold time.\n"); } From d3898a78521cd383d287b3ed5683f914c48c3be9 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Tue, 27 Feb 2018 13:26:18 +0000 Subject: [PATCH 23/53] i2c: xlp9xx: Check for Bus state before every transfer I2C bus enters the STOP condition after the DATA_DONE interrupt is raised. Essentially the driver should be checking the bus state before sending any transaction. In case a transaction is initiated while the bus is busy, the prior transaction's stop condition is not achieved. Add the check to make sure the bus is not busy before every transaction. Signed-off-by: George Cherian Reviewed-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 1f6d78087af9..42dd1fa0b644 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -16,6 +16,7 @@ #include #include #include +#include #define XLP9XX_I2C_DIV 0x0 #define XLP9XX_I2C_CTRL 0x1 @@ -36,6 +37,8 @@ #define XLP9XX_I2C_TIMEOUT 0X10 #define XLP9XX_I2C_GENCALLADDR 0x11 +#define XLP9XX_I2C_STATUS_BUSY BIT(0) + #define XLP9XX_I2C_CMD_START BIT(7) #define XLP9XX_I2C_CMD_STOP BIT(6) #define XLP9XX_I2C_CMD_READ BIT(5) @@ -71,6 +74,7 @@ #define XLP9XX_I2C_HIGH_FREQ 400000 #define XLP9XX_I2C_FIFO_SIZE 0x80U #define XLP9XX_I2C_TIMEOUT_MS 1000 +#define XLP9XX_I2C_BUSY_TIMEOUT 50 #define XLP9XX_I2C_FIFO_WCNT_MASK 0xff #define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \ @@ -241,6 +245,26 @@ xfer_done: return IRQ_HANDLED; } +static int xlp9xx_i2c_check_bus_status(struct xlp9xx_i2c_dev *priv) +{ + u32 status; + u32 busy_timeout = XLP9XX_I2C_BUSY_TIMEOUT; + + while (busy_timeout) { + status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_STATUS); + if ((status & XLP9XX_I2C_STATUS_BUSY) == 0) + break; + + busy_timeout--; + usleep_range(1000, 1100); + } + + if (!busy_timeout) + return -EIO; + + return 0; +} + static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) { u32 prescale; @@ -363,6 +387,14 @@ static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int i, ret; struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap); + ret = xlp9xx_i2c_check_bus_status(priv); + if (ret) { + xlp9xx_i2c_init(priv); + ret = xlp9xx_i2c_check_bus_status(priv); + if (ret) + return ret; + } + for (i = 0; i < num; i++) { ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1); if (ret != 0) From e349d7d08e7044caf37a36409305edbd5af013c7 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Tue, 27 Feb 2018 13:26:19 +0000 Subject: [PATCH 24/53] i2c: xlp9xx: Handle NACK on DATA properly In case we receive NACK on DATA we shouldn't be resetting the controller, rather we should issue STOP command. This will terminate the current transaction and -EIO is returned. While at that handle the SMBus Quick Command properly. We shouldn't be setting the XLP9XX_I2C_CMD_READ/WRITE for such transactions. Signed-off-by: George Cherian Reviewed-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 42dd1fa0b644..eb8913eba0c5 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -352,7 +352,9 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, /* set cmd reg */ cmd = XLP9XX_I2C_CMD_START; - cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); + if (msg->len) + cmd |= (priv->msg_read ? + XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); if (last_msg) cmd |= XLP9XX_I2C_CMD_STOP; @@ -361,12 +363,12 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS); timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft); - if (priv->msg_err) { + if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) { dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); - if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) - xlp9xx_i2c_init(priv); - return (priv->msg_err & XLP9XX_I2C_INTEN_NACKADDR) ? - -ENXIO : -EIO; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, XLP9XX_I2C_CMD_STOP); + return -EIO; + } else if (priv->msg_err & XLP9XX_I2C_INTEN_NACKADDR) { + return -ENXIO; } if (timeleft == 0) { From c0a2676c911c73cf7c753083fdd8f775063d324b Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 16 Jan 2018 17:06:16 +0100 Subject: [PATCH 25/53] dt-bindings: at24: add compatible for nxp,se97b The datasheet talks about the chip being an spd, but the chip is writable so atmel,24c02 is more appropriate as fallback. Signed-off-by: Peter Rosin Reviewed-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/eeprom/at24.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt index abfae1beca2b..edf9247613f6 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.txt +++ b/Documentation/devicetree/bindings/eeprom/at24.txt @@ -46,6 +46,7 @@ Required properties: Some vendors use different model names for chips which are just variants of the above. Known such exceptions are listed below: + "nxp,se97b" - the fallback is "atmel,24c02", "renesas,r1ex24002" - the fallback is "atmel,24c02" - reg: The I2C address of the EEPROM. From 3644784caa017cc3cf4188fb0bfbf3421e8aa7ad Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Fri, 2 Mar 2018 11:14:16 +0100 Subject: [PATCH 26/53] dt-bindings: at24: add bindings for Rohm BR24T01 Both manufacturer and name variant. Signed-off-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Reviewed-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/eeprom/at24.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt index edf9247613f6..a201a1183118 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.txt +++ b/Documentation/devicetree/bindings/eeprom/at24.txt @@ -41,6 +41,7 @@ Required properties: "nxp", "ramtron", "renesas", + "rohm", "st", Some vendors use different model names for chips which are just @@ -48,6 +49,7 @@ Required properties: "nxp,se97b" - the fallback is "atmel,24c02", "renesas,r1ex24002" - the fallback is "atmel,24c02" + "rohm,br24t01" - the fallback is "atmel,24c01" - reg: The I2C address of the EEPROM. From 84e10623c0b9c81557918804f309d66aec86a233 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 2 Mar 2018 17:56:37 +0100 Subject: [PATCH 27/53] dt-bindings: at24: add Renesas R1EX24128 Document the compatible value for the Renesas R1EX24128ASAS0A two-wire serial interface EEPROM, so it can be used in DTS files without causing checkpatch warnings. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Acked-by: Wolfram Sang Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/eeprom/at24.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt index a201a1183118..61d833abafbf 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.txt +++ b/Documentation/devicetree/bindings/eeprom/at24.txt @@ -49,6 +49,7 @@ Required properties: "nxp,se97b" - the fallback is "atmel,24c02", "renesas,r1ex24002" - the fallback is "atmel,24c02" + "renesas,r1ex24128" - the fallback is "atmel,24c128" "rohm,br24t01" - the fallback is "atmel,24c01" - reg: The I2C address of the EEPROM. From 0668bc44a42672626666e4f66aa1f2c22528e8a5 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:50 +0530 Subject: [PATCH 28/53] i2c: qup: fix copyrights and update to SPDX identifier The file has been updated from 2016 to 2018 so fixed the copyright years. Signed-off-by: Abhishek Sahu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 08f8e0107642..ac5edfac2d5c 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2014, Sony Mobile Communications AB. * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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 From 7239872fb3400b21a8f5547257f9f86455867bd6 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:51 +0530 Subject: [PATCH 29/53] i2c: qup: fixed releasing dma without flush operation completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QUP BSLP BAM generates the following error sometimes if the current I2C DMA transfer fails and the flush operation has been scheduled “bam-dma-engine 7884000.dma: Cannot free busy channel” If any I2C error comes during BAM DMA transfer, then the QUP I2C interrupt will be generated and the flush operation will be carried out to make I2C consume all scheduled DMA transfer. Currently, the same completion structure is being used for BAM transfer which has already completed without reinit. It will make flush operation wait_for_completion_timeout completed immediately and will proceed for freeing the DMA resources where the descriptors are still in process. Signed-off-by: Abhishek Sahu Acked-by: Sricharan R Reviewed-by: Austin Christ Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index ac5edfac2d5c..75e9819a161c 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -835,6 +835,8 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, } if (ret || qup->bus_err || qup->qup_err) { + reinit_completion(&qup->xfer); + if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { dev_err(qup->dev, "change to run state timed out"); goto desc_err; From eb422b539c1f39faf576826b54be93e84d9cb32a Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:52 +0530 Subject: [PATCH 30/53] i2c: qup: minor code reorganization for use_dma 1. Assigns use_dma in qup_dev structure itself which will help in subsequent patches to determine the mode in IRQ handler. 2. Does minor code reorganization for loops to reduce the unnecessary comparison and assignment. Signed-off-by: Abhishek Sahu Reviewed-by: Austin Christ Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 75e9819a161c..f6ea07422ccc 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -181,6 +181,8 @@ struct qup_i2c_dev { /* dma parameters */ bool is_dma; + /* To check if the current transfer is using DMA */ + bool use_dma; struct dma_pool *dpool; struct qup_i2c_tag start_tag; struct qup_i2c_bam brx; @@ -1288,7 +1290,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, int num) { struct qup_i2c_dev *qup = i2c_get_adapdata(adap); - int ret, len, idx = 0, use_dma = 0; + int ret, len, idx = 0; qup->bus_err = 0; qup->qup_err = 0; @@ -1317,13 +1319,12 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, len = (msgs[idx].len > qup->out_fifo_sz) || (msgs[idx].len > qup->in_fifo_sz); - if ((!is_vmalloc_addr(msgs[idx].buf)) && len) { - use_dma = 1; - } else { - use_dma = 0; + if (is_vmalloc_addr(msgs[idx].buf) || !len) break; - } } + + if (idx == num) + qup->use_dma = true; } idx = 0; @@ -1347,15 +1348,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, reinit_completion(&qup->xfer); - if (use_dma) { + if (qup->use_dma) { ret = qup_i2c_bam_xfer(adap, &msgs[idx], num); + qup->use_dma = false; + break; } else { if (msgs[idx].flags & I2C_M_RD) ret = qup_i2c_read_one_v2(qup, &msgs[idx]); else ret = qup_i2c_write_one_v2(qup, &msgs[idx]); } - } while ((idx++ < (num - 1)) && !use_dma && !ret); + } while ((idx++ < (num - 1)) && !ret); if (!ret) ret = qup_i2c_change_state(qup, QUP_RESET_STATE); From 6d5f37f166bb07b04b4d42e9d1f5427b7931cd3c Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:53 +0530 Subject: [PATCH 31/53] i2c: qup: remove redundant variables for BAM SG count The rx_nents and tx_nents are redundant. rx_buf and tx_buf can be used for total number of SG entries. Since rx_buf and tx_buf give the impression that it is buffer instead of count so rename it to tx_cnt and rx_cnt for giving it more meaningful variable name. Signed-off-by: Abhishek Sahu Reviewed-by: Austin Christ Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 42 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index f6ea07422ccc..d97045898447 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -683,8 +683,8 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, struct dma_async_tx_descriptor *txd, *rxd = NULL; int ret = 0, idx = 0, limit = QUP_READ_LIMIT; dma_cookie_t cookie_rx, cookie_tx; - u32 rx_nents = 0, tx_nents = 0, len, blocks, rem; - u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0; + u32 len, blocks, rem; + u32 i, tlen, tx_len, tx_cnt = 0, rx_cnt = 0, off = 0; u8 *tags; while (idx < num) { @@ -698,9 +698,6 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, rem = msg->len - (blocks - 1) * limit; if (msg->flags & I2C_M_RD) { - rx_nents += (blocks * 2) + 1; - tx_nents += 1; - while (qup->blk.pos < blocks) { tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + len]; @@ -708,14 +705,14 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, qup->blk.data_len -= tlen; /* scratch buf to read the start and len tags */ - ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], + ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], &qup->brx.tag.start[0], 2, qup, DMA_FROM_DEVICE); if (ret) return ret; - ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], + ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], &msg->buf[limit * i], tlen, qup, DMA_FROM_DEVICE); @@ -725,7 +722,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, i++; qup->blk.pos = i; } - ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], + ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &qup->start_tag.start[off], len, qup, DMA_TO_DEVICE); if (ret) @@ -733,28 +730,26 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, off += len; /* scratch buf to read the BAM EOT and FLUSH tags */ - ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], + ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], &qup->brx.tag.start[0], 2, qup, DMA_FROM_DEVICE); if (ret) return ret; } else { - tx_nents += (blocks * 2); - while (qup->blk.pos < blocks) { tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + tx_len]; len = qup_i2c_set_tags(tags, qup, msg, 1); qup->blk.data_len -= tlen; - ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], + ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], tags, len, qup, DMA_TO_DEVICE); if (ret) return ret; tx_len += len; - ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], + ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &msg->buf[limit * i], tlen, qup, DMA_TO_DEVICE); if (ret) @@ -766,26 +761,25 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, if (idx == (num - 1)) { len = 1; - if (rx_nents) { + if (rx_cnt) { qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT; len++; } qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP; - ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], + ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &qup->btx.tag.start[0], len, qup, DMA_TO_DEVICE); if (ret) return ret; - tx_nents += 1; } } idx++; msg++; } - txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_nents, + txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_PREP_FENCE); if (!txd) { @@ -794,7 +788,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, goto desc_err; } - if (!rx_nents) { + if (!rx_cnt) { txd->callback = qup_i2c_bam_cb; txd->callback_param = qup; } @@ -807,9 +801,9 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, dma_async_issue_pending(qup->btx.dma); - if (rx_nents) { + if (rx_cnt) { rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg, - rx_nents, DMA_DEV_TO_MEM, + rx_cnt, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!rxd) { dev_err(qup->dev, "failed to get rx desc\n"); @@ -844,7 +838,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, goto desc_err; } - if (rx_nents) + if (rx_cnt) writel(QUP_BAM_INPUT_EOT, qup->base + QUP_OUT_FIFO_BASE); @@ -862,10 +856,10 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, } desc_err: - dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE); + dma_unmap_sg(qup->dev, qup->btx.sg, tx_cnt, DMA_TO_DEVICE); - if (rx_nents) - dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents, + if (rx_cnt) + dma_unmap_sg(qup->dev, qup->brx.sg, rx_cnt, DMA_FROM_DEVICE); return ret; From c5adc0fa63a930e3313c74bb7c1d4d158130eb41 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:54 +0530 Subject: [PATCH 32/53] i2c: qup: schedule EOT and FLUSH tags at the end of transfer The role of FLUSH and EOT tag is to flush already scheduled descriptors in BAM HW in case of error. EOT is required only when descriptors are scheduled in RX FIFO. If all the messages are WRITE, then only FLUSH tag will be used. A single BAM transfer can have multiple read and write messages. The EOT and FLUSH tags should be scheduled at the end of BAM HW descriptors. Since the READ and WRITE can be present in any order so for some of the cases, these tags are not being written correctly. Following is one of the example READ, READ, READ, READ Currently EOT and FLUSH tags are being written after each READ. If QUP gets NACK for first READ itself, then flush will be triggered. It will look for first FLUSH tag in TX FIFO and will stop there so only descriptors for first READ descriptors be flushed. All the scheduled descriptors should be cleared to generate BAM DMA completion. Now this patch is scheduling FLUSH and EOT only once after all the descriptors. So, flush will clear all the scheduled descriptors and BAM will generate the completion interrupt. Signed-off-by: Abhishek Sahu Reviewed-by: Sricharan R Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 39 ++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index d97045898447..b2e8f574cd15 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -551,7 +551,7 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup, } static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, - struct i2c_msg *msg, int is_dma) + struct i2c_msg *msg) { u16 addr = i2c_8bit_addr_from_msg(msg); int len = 0; @@ -592,11 +592,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, else tags[len++] = data_len; - if ((msg->flags & I2C_M_RD) && last && is_dma) { - tags[len++] = QUP_BAM_INPUT_EOT; - tags[len++] = QUP_BAM_FLUSH_STOP; - } - return len; } @@ -605,7 +600,7 @@ static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) int data_len = 0, tag_len, index; int ret; - tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0); + tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg); index = msg->len - qup->blk.data_len; /* only tags are written for read */ @@ -701,7 +696,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, while (qup->blk.pos < blocks) { tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + len]; - len += qup_i2c_set_tags(tags, qup, msg, 1); + len += qup_i2c_set_tags(tags, qup, msg); qup->blk.data_len -= tlen; /* scratch buf to read the start and len tags */ @@ -729,17 +724,11 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, return ret; off += len; - /* scratch buf to read the BAM EOT and FLUSH tags */ - ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], - &qup->brx.tag.start[0], - 2, qup, DMA_FROM_DEVICE); - if (ret) - return ret; } else { while (qup->blk.pos < blocks) { tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + tx_len]; - len = qup_i2c_set_tags(tags, qup, msg, 1); + len = qup_i2c_set_tags(tags, qup, msg); qup->blk.data_len -= tlen; ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], @@ -779,6 +768,26 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, msg++; } + /* schedule the EOT and FLUSH I2C tags */ + len = 1; + if (rx_cnt) { + qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT; + len++; + + /* scratch buf to read the BAM EOT and FLUSH tags */ + ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], + &qup->brx.tag.start[0], + 2, qup, DMA_FROM_DEVICE); + if (ret) + return ret; + } + + qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP; + ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &qup->btx.tag.start[0], + len, qup, DMA_TO_DEVICE); + if (ret) + return ret; + txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_PREP_FENCE); From 7e6c35fe602df6821b3e7db5b1ba656162750fda Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:55 +0530 Subject: [PATCH 33/53] i2c: qup: fix the transfer length for BAM RX EOT FLUSH tags In case of FLUSH operation, BAM copies INPUT EOT FLUSH (0x94) instead of normal EOT (0x93) tag in input data stream when an input EOT tag is received during flush operation. So only one tag will be written instead of 2 separate tags. Signed-off-by: Abhishek Sahu Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index b2e8f574cd15..73a288068632 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -774,10 +774,10 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT; len++; - /* scratch buf to read the BAM EOT and FLUSH tags */ + /* scratch buf to read the BAM EOT FLUSH tags */ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], &qup->brx.tag.start[0], - 2, qup, DMA_FROM_DEVICE); + 1, qup, DMA_FROM_DEVICE); if (ret) return ret; } From 3f450d3eea14799b14192231840c1753a660f150 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:56 +0530 Subject: [PATCH 34/53] i2c: qup: proper error handling for i2c error in BAM mode Currently the i2c error handling in BAM mode is not working properly in stress condition. 1. After an error, the FIFO are being written with FLUSH and EOT tags which should not be required since already these tags have been written in BAM descriptor itself. 2. QUP state is being moved to RESET in IRQ handler in case of error. When QUP HW encounters an error in BAM mode then it moves the QUP STATE to PAUSE state. In this case, I2C_FLUSH command needs to be executed while moving to RUN_STATE by writing to the QUP_STATE register with the I2C_FLUSH bit set to 1. 3. In Error case, sometimes, QUP generates more than one interrupt which will trigger the complete again. After an error, the flush operation will be scheduled after doing reinit_completion which should be triggered by BAM IRQ callback. If the second QUP IRQ comes during this time then it will call the complete and the transfer function will assume the all the BAM HW descriptors have been completed. 4. The release DMA is being called after each error which will free the DMA tx and rx channels. The error like NACK is very common in I2C transfer and every time this will be overhead. Now, since the error handling is proper so this release channel can be completely avoided. Signed-off-by: Abhishek Sahu Reviewed-by: Sricharan R Reviewed-by: Austin Christ Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 73a288068632..d16361df1bfb 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -219,9 +219,24 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) if (bus_err) writel(bus_err, qup->base + QUP_I2C_STATUS); + /* + * Check for BAM mode and returns if already error has come for current + * transfer. In Error case, sometimes, QUP generates more than one + * interrupt. + */ + if (qup->use_dma && (qup->qup_err || qup->bus_err)) + return IRQ_HANDLED; + /* Reset the QUP State in case of error */ if (qup_err || bus_err) { - writel(QUP_RESET_STATE, qup->base + QUP_STATE); + /* + * Don’t reset the QUP state in case of BAM mode. The BAM + * flush operation needs to be scheduled in transfer function + * which will clear the remaining schedule descriptors in BAM + * HW FIFO and generates the BAM interrupt. + */ + if (!qup->use_dma) + writel(QUP_RESET_STATE, qup->base + QUP_STATE); goto done; } @@ -847,20 +862,12 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, goto desc_err; } - if (rx_cnt) - writel(QUP_BAM_INPUT_EOT, - qup->base + QUP_OUT_FIFO_BASE); - - writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE); - qup_i2c_flush(qup); /* wait for remaining interrupts to occur */ if (!wait_for_completion_timeout(&qup->xfer, HZ)) dev_err(qup->dev, "flush timed out\n"); - qup_i2c_rel_dma(qup); - ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; } From 08f15963bc751bc818294c0f75a9aaca299c4052 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:57 +0530 Subject: [PATCH 35/53] i2c: qup: use the complete transfer length to choose DMA mode Currently each message length in complete transfer is being checked for determining DMA mode and if any of the message length is less than FIFO length then non DMA mode is being used which will increase overhead. DMA can be used for any length and it should be determined with complete transfer length. Now, this patch selects DMA mode if the total length is greater than FIFO length. Signed-off-by: Abhishek Sahu Reviewed-by: Austin Christ Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index d16361df1bfb..bf1b7eec8a4c 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1300,7 +1300,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, int num) { struct qup_i2c_dev *qup = i2c_get_adapdata(adap); - int ret, len, idx = 0; + int ret, idx = 0; + unsigned int total_len = 0; qup->bus_err = 0; qup->qup_err = 0; @@ -1326,14 +1327,14 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, goto out; } - len = (msgs[idx].len > qup->out_fifo_sz) || - (msgs[idx].len > qup->in_fifo_sz); - - if (is_vmalloc_addr(msgs[idx].buf) || !len) + if (is_vmalloc_addr(msgs[idx].buf)) break; + + total_len += msgs[idx].len; } - if (idx == num) + if (idx == num && (total_len > qup->out_fifo_sz || + total_len > qup->in_fifo_sz)) qup->use_dma = true; } From ecb6e1e5f4352055a5761b945a833a925d51bf8d Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:58 +0530 Subject: [PATCH 36/53] i2c: qup: change completion timeout according to transfer length Currently the completion timeout is being taken according to maximum transfer length which is too high if SCL is operating in high frequency. This patch calculates timeout on the basis of one-byte transfer time and uses the same for completion timeout. Signed-off-by: Abhishek Sahu Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index bf1b7eec8a4c..13c751e2dd9a 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -121,8 +121,12 @@ #define MX_TX_RX_LEN SZ_64K #define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) -/* Max timeout in ms for 32k bytes */ -#define TOUT_MAX 300 +/* + * Minimum transfer timeout for i2c transfers in seconds. It will be added on + * the top of maximum transfer time calculated from i2c bus speed to compensate + * the overheads. + */ +#define TOUT_MIN 2 /* Default values. Use these if FW query fails */ #define DEFAULT_CLK_FREQ 100000 @@ -163,6 +167,7 @@ struct qup_i2c_dev { int in_blk_sz; unsigned long one_byte_t; + unsigned long xfer_timeout; struct qup_i2c_block blk; struct i2c_msg *msg; @@ -849,7 +854,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, dma_async_issue_pending(qup->brx.dma); } - if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) { + if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) { dev_err(qup->dev, "normal trans timed out\n"); ret = -ETIMEDOUT; } @@ -1605,6 +1610,8 @@ nodma: */ one_bit_t = (USEC_PER_SEC / clk_freq) + 1; qup->one_byte_t = one_bit_t * 9; + qup->xfer_timeout = TOUT_MIN * HZ + + usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t); dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n", qup->in_blk_sz, qup->in_fifo_sz, From 6f2f0f6465acbd59391c43352ff0df77df1f01db Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:44:59 +0530 Subject: [PATCH 37/53] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BAM mode requires buffer for start tag data and tx, rx SG list. Currently, this is being taken for maximum transfer length (65K). But an I2C transfer can have multiple messages and each message can be of this maximum length so the buffer overflow will happen in this case. Since increasing buffer length won’t be feasible since an I2C transfer can contain any number of messages so this patch does following changes to make i2c transfers working for multiple messages case. 1. Calculate the required buffers for 2 maximum length messages (65K * 2). 2. Split the descriptor formation and descriptor scheduling. The idea is to fit as many messages in one DMA transfers for 65K threshold value (max_xfer_sg_len). Whenever the sg_cnt is crossing this, then schedule the BAM transfer and subsequent transfer will again start from zero. Signed-off-by: Abhishek Sahu Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 198 ++++++++++++++++++++--------------- 1 file changed, 112 insertions(+), 86 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 13c751e2dd9a..5bb7ebe70f3c 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -118,8 +118,12 @@ #define ONE_BYTE 0x1 #define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) +/* Maximum transfer length for single DMA descriptor */ #define MX_TX_RX_LEN SZ_64K #define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) +/* Maximum transfer length for all DMA descriptors */ +#define MX_DMA_TX_RX_LEN (2 * MX_TX_RX_LEN) +#define MX_DMA_BLOCKS (MX_DMA_TX_RX_LEN / QUP_READ_LIMIT) /* * Minimum transfer timeout for i2c transfers in seconds. It will be added on @@ -150,6 +154,7 @@ struct qup_i2c_bam { struct qup_i2c_tag tag; struct dma_chan *dma; struct scatterlist *sg; + unsigned int sg_cnt; }; struct qup_i2c_dev { @@ -188,6 +193,8 @@ struct qup_i2c_dev { bool is_dma; /* To check if the current transfer is using DMA */ bool use_dma; + unsigned int max_xfer_sg_len; + unsigned int tag_buf_pos; struct dma_pool *dpool; struct qup_i2c_tag start_tag; struct qup_i2c_bam brx; @@ -692,102 +699,87 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup) return 0; } -static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, - int num) +static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg) { - struct dma_async_tx_descriptor *txd, *rxd = NULL; - int ret = 0, idx = 0, limit = QUP_READ_LIMIT; - dma_cookie_t cookie_rx, cookie_tx; - u32 len, blocks, rem; - u32 i, tlen, tx_len, tx_cnt = 0, rx_cnt = 0, off = 0; + int ret = 0, limit = QUP_READ_LIMIT; + u32 len = 0, blocks, rem; + u32 i = 0, tlen, tx_len = 0; u8 *tags; - while (idx < num) { - tx_len = 0, len = 0, i = 0; + qup_i2c_set_blk_data(qup, msg); - qup->is_last = (idx == (num - 1)); + blocks = qup->blk.count; + rem = msg->len - (blocks - 1) * limit; - qup_i2c_set_blk_data(qup, msg); + if (msg->flags & I2C_M_RD) { + while (qup->blk.pos < blocks) { + tlen = (i == (blocks - 1)) ? rem : limit; + tags = &qup->start_tag.start[qup->tag_buf_pos + len]; + len += qup_i2c_set_tags(tags, qup, msg); + qup->blk.data_len -= tlen; - blocks = qup->blk.count; - rem = msg->len - (blocks - 1) * limit; + /* scratch buf to read the start and len tags */ + ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++], + &qup->brx.tag.start[0], + 2, qup, DMA_FROM_DEVICE); - if (msg->flags & I2C_M_RD) { - while (qup->blk.pos < blocks) { - tlen = (i == (blocks - 1)) ? rem : limit; - tags = &qup->start_tag.start[off + len]; - len += qup_i2c_set_tags(tags, qup, msg); - qup->blk.data_len -= tlen; - - /* scratch buf to read the start and len tags */ - ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], - &qup->brx.tag.start[0], - 2, qup, DMA_FROM_DEVICE); - - if (ret) - return ret; - - ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++], - &msg->buf[limit * i], - tlen, qup, - DMA_FROM_DEVICE); - if (ret) - return ret; - - i++; - qup->blk.pos = i; - } - ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], - &qup->start_tag.start[off], - len, qup, DMA_TO_DEVICE); if (ret) return ret; - off += len; - } else { - while (qup->blk.pos < blocks) { - tlen = (i == (blocks - 1)) ? rem : limit; - tags = &qup->start_tag.start[off + tx_len]; - len = qup_i2c_set_tags(tags, qup, msg); - qup->blk.data_len -= tlen; + ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++], + &msg->buf[limit * i], + tlen, qup, + DMA_FROM_DEVICE); + if (ret) + return ret; - ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], - tags, len, - qup, DMA_TO_DEVICE); - if (ret) - return ret; - - tx_len += len; - ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], - &msg->buf[limit * i], - tlen, qup, DMA_TO_DEVICE); - if (ret) - return ret; - i++; - qup->blk.pos = i; - } - off += tx_len; - - if (idx == (num - 1)) { - len = 1; - if (rx_cnt) { - qup->btx.tag.start[0] = - QUP_BAM_INPUT_EOT; - len++; - } - qup->btx.tag.start[len - 1] = - QUP_BAM_FLUSH_STOP; - ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], - &qup->btx.tag.start[0], - len, qup, DMA_TO_DEVICE); - if (ret) - return ret; - } + i++; + qup->blk.pos = i; } - idx++; - msg++; + ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++], + &qup->start_tag.start[qup->tag_buf_pos], + len, qup, DMA_TO_DEVICE); + if (ret) + return ret; + + qup->tag_buf_pos += len; + } else { + while (qup->blk.pos < blocks) { + tlen = (i == (blocks - 1)) ? rem : limit; + tags = &qup->start_tag.start[qup->tag_buf_pos + tx_len]; + len = qup_i2c_set_tags(tags, qup, msg); + qup->blk.data_len -= tlen; + + ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++], + tags, len, + qup, DMA_TO_DEVICE); + if (ret) + return ret; + + tx_len += len; + ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++], + &msg->buf[limit * i], + tlen, qup, DMA_TO_DEVICE); + if (ret) + return ret; + i++; + qup->blk.pos = i; + } + + qup->tag_buf_pos += tx_len; } + return 0; +} + +static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup) +{ + struct dma_async_tx_descriptor *txd, *rxd = NULL; + int ret = 0; + dma_cookie_t cookie_rx, cookie_tx; + u32 len = 0; + u32 tx_cnt = qup->btx.sg_cnt, rx_cnt = qup->brx.sg_cnt; + /* schedule the EOT and FLUSH I2C tags */ len = 1; if (rx_cnt) { @@ -886,11 +878,19 @@ desc_err: return ret; } +static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup) +{ + qup->btx.sg_cnt = 0; + qup->brx.sg_cnt = 0; + qup->tag_buf_pos = 0; +} + static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) { struct qup_i2c_dev *qup = i2c_get_adapdata(adap); int ret = 0; + int idx = 0; enable_irq(qup->irq); ret = qup_i2c_req_dma(qup); @@ -913,9 +913,34 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, goto out; writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); + qup_i2c_bam_clear_tag_buffers(qup); + + for (idx = 0; idx < num; idx++) { + qup->msg = msg + idx; + qup->is_last = idx == (num - 1); + + ret = qup_i2c_bam_make_desc(qup, qup->msg); + if (ret) + break; + + /* + * Make DMA descriptor and schedule the BAM transfer if its + * already crossed the maximum length. Since the memory for all + * tags buffers have been taken for 2 maximum possible + * transfers length so it will never cross the buffer actual + * length. + */ + if (qup->btx.sg_cnt > qup->max_xfer_sg_len || + qup->brx.sg_cnt > qup->max_xfer_sg_len || + qup->is_last) { + ret = qup_i2c_bam_schedule_desc(qup); + if (ret) + break; + + qup_i2c_bam_clear_tag_buffers(qup); + } + } - qup->msg = msg; - ret = qup_i2c_bam_do_xfer(qup, qup->msg, num); out: disable_irq(qup->irq); @@ -1468,7 +1493,8 @@ static int qup_i2c_probe(struct platform_device *pdev) else if (ret != 0) goto nodma; - blocks = (MX_BLOCKS << 1) + 1; + qup->max_xfer_sg_len = (MX_BLOCKS << 1); + blocks = (MX_DMA_BLOCKS << 1) + 1; qup->btx.sg = devm_kzalloc(&pdev->dev, sizeof(*qup->btx.sg) * blocks, GFP_KERNEL); @@ -1611,7 +1637,7 @@ nodma: one_bit_t = (USEC_PER_SEC / clk_freq) + 1; qup->one_byte_t = one_bit_t * 9; qup->xfer_timeout = TOUT_MIN * HZ + - usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t); + usecs_to_jiffies(MX_DMA_TX_RX_LEN * qup->one_byte_t); dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n", qup->in_blk_sz, qup->in_fifo_sz, From f7714b4e451bdcb7918b9aad14af22684ceac638 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:45:00 +0530 Subject: [PATCH 38/53] i2c: qup: send NACK for last read sub transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to I2c specification, “If a master-receiver sends a repeated START condition, it sends a not-acknowledge (A) just before the repeated START condition”. QUP v2 supports sending of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the same. Signed-off-by: Abhishek Sahu Reviewed-by: Austin Christ Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 5bb7ebe70f3c..4ebd9226dd87 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -104,6 +104,7 @@ #define QUP_TAG_V2_DATAWR 0x82 #define QUP_TAG_V2_DATAWR_STOP 0x83 #define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_NACK 0x86 #define QUP_TAG_V2_DATARD_STOP 0x87 /* Status, Error flags */ @@ -606,7 +607,9 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, tags[len++] = QUP_TAG_V2_DATAWR_STOP; } else { if (msg->flags & I2C_M_RD) - tags[len++] = QUP_TAG_V2_DATARD; + tags[len++] = qup->blk.pos == (qup->blk.count - 1) ? + QUP_TAG_V2_DATARD_NACK : + QUP_TAG_V2_DATARD; else tags[len++] = QUP_TAG_V2_DATAWR; } From fbfab1ab065879370541caf0e514987368eb41b2 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:45:01 +0530 Subject: [PATCH 39/53] i2c: qup: reorganization of driver code to remove polling for qup v1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following are the major issues in current driver code 1. The current driver simply assumes the transfer completion whenever its gets any non-error interrupts and then simply do the polling of available/free bytes in FIFO. 2. The block mode is not working properly since no handling in being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ. Because of above, i2c v1 transfers of size greater than 32 are failing with following error message i2c_qup 78b6000.i2c: timeout for fifo out full To make block mode working properly and move to use the interrupts instead of polling, major code reorganization is required. Following are the major changes done in this patch 1. Remove the polling of TX FIFO free space and RX FIFO available bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE, QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ interrupts to handle FIFO’s properly so check all these interrupts. 2. During write, For FIFO mode, TX FIFO can be directly written without checking for FIFO space. For block mode, the QUP will generate OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available space. 3. During read, both TX and RX FIFO will be used. TX will be used for writing tags and RX will be used for receiving the data. In QUP, TX and RX can operate in separate mode so configure modes accordingly. 4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which will be generated after all the bytes have been copied in RX FIFO. For read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts whenever it has block size of available data. Signed-off-by: Abhishek Sahu Reviewed-by: Sricharan R Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 368 +++++++++++++++++++++-------------- 1 file changed, 224 insertions(+), 144 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4ebd9226dd87..3bf3c349dc70 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -64,8 +64,11 @@ #define QUP_IN_SVC_FLAG BIT(9) #define QUP_MX_OUTPUT_DONE BIT(10) #define QUP_MX_INPUT_DONE BIT(11) +#define OUT_BLOCK_WRITE_REQ BIT(12) +#define IN_BLOCK_READ_REQ BIT(13) /* I2C mini core related values */ +#define QUP_NO_INPUT BIT(7) #define QUP_CLOCK_AUTO_GATE BIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 @@ -137,13 +140,36 @@ #define DEFAULT_CLK_FREQ 100000 #define DEFAULT_SRC_CLK 20000000 +/* + * count: no of blocks + * pos: current block number + * tx_tag_len: tx tag length for current block + * rx_tag_len: rx tag length for current block + * data_len: remaining data length for current message + * total_tx_len: total tx length including tag bytes for current QUP transfer + * total_rx_len: total rx length including tag bytes for current QUP transfer + * tx_fifo_free: number of free bytes in current QUP block write. + * fifo_available: number of available bytes in RX FIFO for current + * QUP block read + * rx_bytes_read: if all the bytes have been read from rx FIFO. + * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer. + * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer. + * tags: contains tx tag bytes for current QUP transfer + */ struct qup_i2c_block { - int count; - int pos; - int tx_tag_len; - int rx_tag_len; - int data_len; - u8 tags[6]; + int count; + int pos; + int tx_tag_len; + int rx_tag_len; + int data_len; + int total_tx_len; + int total_rx_len; + int tx_fifo_free; + int fifo_available; + bool rx_bytes_read; + bool is_tx_blk_mode; + bool is_rx_blk_mode; + u8 tags[6]; }; struct qup_i2c_tag { @@ -186,6 +212,7 @@ struct qup_i2c_dev { /* To check if this is the last msg */ bool is_last; + bool is_qup_v1; /* To configure when bus is in run state */ int config_run; @@ -202,11 +229,18 @@ struct qup_i2c_dev { struct qup_i2c_bam btx; struct completion xfer; + /* function to write data in tx fifo */ + void (*write_tx_fifo)(struct qup_i2c_dev *qup); + /* function to read data from rx fifo */ + void (*read_rx_fifo)(struct qup_i2c_dev *qup); + /* function to write tags in tx fifo for i2c read transfer */ + void (*write_rx_tags)(struct qup_i2c_dev *qup); }; static irqreturn_t qup_i2c_interrupt(int irq, void *dev) { struct qup_i2c_dev *qup = dev; + struct qup_i2c_block *blk = &qup->blk; u32 bus_err; u32 qup_err; u32 opflags; @@ -253,11 +287,47 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) goto done; } - if (opflags & QUP_IN_SVC_FLAG) + if (!qup->is_qup_v1) + goto done; + + if (opflags & QUP_OUT_SVC_FLAG) { + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); + + if (opflags & OUT_BLOCK_WRITE_REQ) { + blk->tx_fifo_free += qup->out_blk_sz; + if (qup->msg->flags & I2C_M_RD) + qup->write_rx_tags(qup); + else + qup->write_tx_fifo(qup); + } + } + + if (opflags & QUP_IN_SVC_FLAG) { writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL); - if (opflags & QUP_OUT_SVC_FLAG) - writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); + if (!blk->is_rx_blk_mode) { + blk->fifo_available += qup->in_fifo_sz; + qup->read_rx_fifo(qup); + } else if (opflags & IN_BLOCK_READ_REQ) { + blk->fifo_available += qup->in_blk_sz; + qup->read_rx_fifo(qup); + } + } + + if (qup->msg->flags & I2C_M_RD) { + if (!blk->rx_bytes_read) + return IRQ_HANDLED; + } else { + /* + * Ideally, QUP_MAX_OUTPUT_DONE_FLAG should be checked + * for FIFO mode also. But, QUP_MAX_OUTPUT_DONE_FLAG lags + * behind QUP_OUTPUT_SERVICE_FLAG sometimes. The only reason + * of interrupt for write message in FIFO mode is + * QUP_MAX_OUTPUT_DONE_FLAG condition. + */ + if (blk->is_tx_blk_mode && !(opflags & QUP_MX_OUTPUT_DONE)) + return IRQ_HANDLED; + } done: qup->qup_err = qup_err; @@ -324,6 +394,28 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } +/* Check if I2C bus returns to IDLE state */ +static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) +{ + unsigned long timeout; + u32 status; + int ret = 0; + + timeout = jiffies + len * 4; + for (;;) { + status = readl(qup->base + QUP_I2C_STATUS); + if (!(status & I2C_STATUS_BUS_ACTIVE)) + break; + + if (time_after(jiffies, timeout)) + ret = -ETIMEDOUT; + + usleep_range(len, len * 2); + } + + return ret; +} + /** * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path * @qup: The qup_i2c_dev device @@ -394,23 +486,6 @@ static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup, } } -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; - - if (total < qup->out_fifo_sz) { - /* FIFO mode */ - writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_WRITE_CNT); - } else { - /* BLOCK mode (transfer data on chunks) */ - writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN, - qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_OUTPUT_CNT); - } -} - static int check_for_fifo_space(struct qup_i2c_dev *qup) { int ret; @@ -443,28 +518,25 @@ out: return ret; } -static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +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 qup_tag; int idx; u32 val; - int ret = 0; if (qup->pos == 0) { val = QUP_TAG_START | addr; idx = 1; + blk->tx_fifo_free--; } else { val = 0; idx = 0; } - while (qup->pos < msg->len) { - /* Check that there's space in the FIFO for our pair */ - ret = check_for_fifo_space(qup); - if (ret) - return ret; - + while (blk->tx_fifo_free && qup->pos < msg->len) { if (qup->pos == msg->len - 1) qup_tag = QUP_TAG_STOP; else @@ -481,11 +553,8 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) qup->pos++; idx++; + blk->tx_fifo_free--; } - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - - return ret; } static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup, @@ -1006,64 +1075,6 @@ err: return ret; } -static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - int ret; - - qup->msg = msg; - qup->pos = 0; - - enable_irq(qup->irq); - - qup_i2c_set_write_mode(qup, msg); - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto err; - - writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); - - do { - ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); - if (ret) - goto err; - - ret = qup_i2c_issue_write(qup, msg); - if (ret) - goto err; - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto err; - - ret = qup_i2c_wait_for_complete(qup, msg); - if (ret) - goto err; - } while (qup->pos < msg->len); - - /* Wait for the outstanding data in the fifo to drain */ - ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); -err: - disable_irq(qup->irq); - qup->msg = NULL; - - return ret; -} - -static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len) -{ - if (len < qup->in_fifo_sz) { - /* FIFO mode */ - writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(len, qup->base + QUP_MX_READ_CNT); - } else { - /* BLOCK mode (transfer data on chunks) */ - writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN, - qup->base + QUP_IO_MODE); - writel(len, qup->base + QUP_MX_INPUT_CNT); - } -} - static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len) { int tx_len = qup->blk.tx_tag_len; @@ -1086,44 +1097,27 @@ static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len) } } -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - u32 addr, len, val; - - addr = i2c_8bit_addr_from_msg(msg); - - /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */ - len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len; - - val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr; - writel(val, qup->base + QUP_OUT_FIFO_BASE); -} - - -static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup) { + struct qup_i2c_block *blk = &qup->blk; + struct i2c_msg *msg = qup->msg; u32 val = 0; - int idx; - int ret = 0; + int idx = 0; - for (idx = 0; qup->pos < msg->len; idx++) { + while (blk->fifo_available && qup->pos < msg->len) { if ((idx & 1) == 0) { - /* Check that FIFO have data */ - ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, - SET_BIT, 4 * ONE_BYTE); - if (ret) - return ret; - /* Reading 2 words at time */ val = readl(qup->base + QUP_IN_FIFO_BASE); - msg->buf[qup->pos++] = val & 0xFF; } else { msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT; } + idx++; + blk->fifo_available--; } - return ret; + if (qup->pos == msg->len) + blk->rx_bytes_read = true; } static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, @@ -1224,49 +1218,130 @@ err: return ret; } -static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_write_rx_tags_v1(struct qup_i2c_dev *qup) { + struct i2c_msg *msg = qup->msg; + u32 addr, len, val; + + addr = i2c_8bit_addr_from_msg(msg); + + /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */ + len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len; + + val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr; + writel(val, qup->base + QUP_OUT_FIFO_BASE); +} + +static void qup_i2c_conf_v1(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + u32 qup_config = I2C_MINI_CORE | I2C_N_VAL; + u32 io_mode = QUP_REPACK_EN; + + blk->is_tx_blk_mode = + blk->total_tx_len > qup->out_fifo_sz ? true : false; + blk->is_rx_blk_mode = + blk->total_rx_len > qup->in_fifo_sz ? true : false; + + if (blk->is_tx_blk_mode) { + io_mode |= QUP_OUTPUT_BLK_MODE; + writel(0, qup->base + QUP_MX_WRITE_CNT); + writel(blk->total_tx_len, qup->base + QUP_MX_OUTPUT_CNT); + } else { + writel(0, qup->base + QUP_MX_OUTPUT_CNT); + writel(blk->total_tx_len, qup->base + QUP_MX_WRITE_CNT); + } + + if (blk->total_rx_len) { + if (blk->is_rx_blk_mode) { + io_mode |= QUP_INPUT_BLK_MODE; + writel(0, qup->base + QUP_MX_READ_CNT); + writel(blk->total_rx_len, qup->base + QUP_MX_INPUT_CNT); + } else { + writel(0, qup->base + QUP_MX_INPUT_CNT); + writel(blk->total_rx_len, qup->base + QUP_MX_READ_CNT); + } + } else { + qup_config |= QUP_NO_INPUT; + } + + writel(qup_config, qup->base + QUP_CONFIG); + writel(io_mode, qup->base + QUP_IO_MODE); +} + +static void qup_i2c_clear_blk_v1(struct qup_i2c_block *blk) +{ + blk->tx_fifo_free = 0; + blk->fifo_available = 0; + blk->rx_bytes_read = false; +} + +static int qup_i2c_conf_xfer_v1(struct qup_i2c_dev *qup, bool is_rx) +{ + struct qup_i2c_block *blk = &qup->blk; int ret; - qup->msg = msg; - qup->pos = 0; - - enable_irq(qup->irq); - qup_i2c_set_read_mode(qup, msg->len); - + qup_i2c_clear_blk_v1(blk); + qup_i2c_conf_v1(qup); ret = qup_i2c_change_state(qup, QUP_RUN_STATE); if (ret) - goto err; + return ret; writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); if (ret) - goto err; + return ret; - qup_i2c_issue_read(qup, msg); + reinit_completion(&qup->xfer); + enable_irq(qup->irq); + if (!blk->is_tx_blk_mode) { + blk->tx_fifo_free = qup->out_fifo_sz; + + if (is_rx) + qup_i2c_write_rx_tags_v1(qup); + else + qup_i2c_write_tx_fifo_v1(qup); + } ret = qup_i2c_change_state(qup, QUP_RUN_STATE); if (ret) goto err; - do { - ret = qup_i2c_wait_for_complete(qup, msg); - if (ret) - goto err; + ret = qup_i2c_wait_for_complete(qup, qup->msg); + if (ret) + goto err; - ret = qup_i2c_read_fifo(qup, msg); - if (ret) - goto err; - } while (qup->pos < msg->len); + ret = qup_i2c_bus_active(qup, ONE_BYTE); err: disable_irq(qup->irq); - qup->msg = NULL; - return ret; } +static int qup_i2c_write_one(struct qup_i2c_dev *qup) +{ + struct i2c_msg *msg = qup->msg; + struct qup_i2c_block *blk = &qup->blk; + + qup->pos = 0; + blk->total_tx_len = msg->len + 1; + blk->total_rx_len = 0; + + return qup_i2c_conf_xfer_v1(qup, false); +} + +static int qup_i2c_read_one(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + + qup->pos = 0; + blk->total_tx_len = 2; + blk->total_rx_len = qup->msg->len; + + return qup_i2c_conf_xfer_v1(qup, true); +} + static int qup_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -1305,10 +1380,11 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, goto out; } + qup->msg = &msgs[idx]; if (msgs[idx].flags & I2C_M_RD) - ret = qup_i2c_read_one(qup, &msgs[idx]); + ret = qup_i2c_read_one(qup); else - ret = qup_i2c_write_one(qup, &msgs[idx]); + ret = qup_i2c_write_one(qup); if (ret) break; @@ -1487,6 +1563,10 @@ static int qup_i2c_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { qup->adap.algo = &qup_i2c_algo; qup->adap.quirks = &qup_i2c_quirks; + qup->is_qup_v1 = true; + qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1; + qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1; + qup->write_rx_tags = qup_i2c_write_rx_tags_v1; } else { qup->adap.algo = &qup_i2c_algo_v2; ret = qup_i2c_req_dma(qup); From 7545c7dba169c4c29ba5f6ab8706267a84c0febe Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 12 Mar 2018 18:45:02 +0530 Subject: [PATCH 40/53] i2c: qup: reorganization of driver code to remove polling for qup v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following are the major issues in current driver code 1. The current driver simply assumes the transfer completion whenever its gets any non-error interrupts and then simply do the polling of available/free bytes in FIFO. 2. The block mode is not working properly since no handling in being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_READ. 3. An i2c transfer can contain multiple message and QUP v2 supports reconfiguration during run in which the mode should be same for all the sub transfer. Currently the mode is being programmed before every sub transfer which is functionally wrong. If one message is less than FIFO length and other message is greater than FIFO length, then transfers will fail. Because of above, i2c v2 transfers of size greater than 64 are failing with following error message i2c_qup 78b6000.i2c: timeout for fifo out full To make block mode working properly and move to use the interrupts instead of polling, major code reorganization is required. Following are the major changes done in this patch 1. Remove the polling of TX FIFO free space and RX FIFO available bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE, QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ interrupts to handle FIFO’s properly so check all these interrupts. 2. Determine the mode for transfer before starting by checking all the tx/rx data length in each message. The complete message can be transferred either in DMA mode or Programmed IO by FIFO/Block mode. in DMA mode, both tx and rx uses same mode but in PIO mode, the TX and RX can be in different mode. 3. During write, For FIFO mode, TX FIFO can be directly written without checking for FIFO space. For block mode, the QUP will generate OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available space. 4. During read, both TX and RX FIFO will be used. TX will be used for writing tags and RX will be used for receiving the data. In QUP, TX and RX can operate in separate mode so configure modes accordingly. 5. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which will be generated after all the bytes have been copied in RX FIFO. For read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts whenever it has block size of available data. 6. Split the transfer in chunk of one QUP block size(256 bytes) and schedule each block separately. QUP v2 supports reconfiguration during run in which QUP can transfer multiple blocks without issuing a stop events. 7. Port the SMBus block read support for new code changes. Signed-off-by: Abhishek Sahu Reviewed-by: Sricharan R Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 902 ++++++++++++++++++++--------------- 1 file changed, 516 insertions(+), 386 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3bf3c349dc70..904dfec7ab96 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -140,18 +140,41 @@ #define DEFAULT_CLK_FREQ 100000 #define DEFAULT_SRC_CLK 20000000 +/* + * Max tags length (start, stop and maximum 2 bytes address) for each QUP + * data transfer + */ +#define QUP_MAX_TAGS_LEN 4 +/* Max data length for each DATARD tags */ +#define RECV_MAX_DATA_LEN 254 +/* TAG length for DATA READ in RX FIFO */ +#define READ_RX_TAGS_LEN 2 + /* * count: no of blocks * pos: current block number * tx_tag_len: tx tag length for current block * rx_tag_len: rx tag length for current block * data_len: remaining data length for current message + * cur_blk_len: data length for current block * total_tx_len: total tx length including tag bytes for current QUP transfer * total_rx_len: total rx length including tag bytes for current QUP transfer + * tx_fifo_data_pos: current byte number in TX FIFO word * tx_fifo_free: number of free bytes in current QUP block write. + * rx_fifo_data_pos: current byte number in RX FIFO word * fifo_available: number of available bytes in RX FIFO for current * QUP block read + * tx_fifo_data: QUP TX FIFO write works on word basis (4 bytes). New byte write + * to TX FIFO will be appended in this data and will be written to + * TX FIFO when all the 4 bytes are available. + * rx_fifo_data: QUP RX FIFO read works on word basis (4 bytes). This will + * contains the 4 bytes of RX data. + * cur_data: pointer to tell cur data position for current message + * cur_tx_tags: pointer to tell cur position in tags + * tx_tags_sent: all tx tag bytes have been written in FIFO word + * send_last_word: for tx FIFO, last word send is pending in current block * rx_bytes_read: if all the bytes have been read from rx FIFO. + * rx_tags_fetched: all the rx tag bytes have been fetched from rx fifo word * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer. * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer. * tags: contains tx tag bytes for current QUP transfer @@ -162,10 +185,20 @@ struct qup_i2c_block { int tx_tag_len; int rx_tag_len; int data_len; + int cur_blk_len; int total_tx_len; int total_rx_len; + int tx_fifo_data_pos; int tx_fifo_free; + int rx_fifo_data_pos; int fifo_available; + u32 tx_fifo_data; + u32 rx_fifo_data; + u8 *cur_data; + u8 *cur_tx_tags; + bool tx_tags_sent; + bool send_last_word; + bool rx_tags_fetched; bool rx_bytes_read; bool is_tx_blk_mode; bool is_rx_blk_mode; @@ -198,6 +231,7 @@ struct qup_i2c_dev { int out_blk_sz; int in_blk_sz; + int blk_xfer_limit; unsigned long one_byte_t; unsigned long xfer_timeout; struct qup_i2c_block blk; @@ -212,10 +246,10 @@ struct qup_i2c_dev { /* To check if this is the last msg */ bool is_last; - bool is_qup_v1; + bool is_smbus_read; /* To configure when bus is in run state */ - int config_run; + u32 config_run; /* dma parameters */ bool is_dma; @@ -223,6 +257,8 @@ struct qup_i2c_dev { bool use_dma; unsigned int max_xfer_sg_len; unsigned int tag_buf_pos; + /* The threshold length above which block mode will be used */ + unsigned int blk_mode_threshold; struct dma_pool *dpool; struct qup_i2c_tag start_tag; struct qup_i2c_bam brx; @@ -287,9 +323,6 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) goto done; } - if (!qup->is_qup_v1) - goto done; - if (opflags & QUP_OUT_SVC_FLAG) { writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); @@ -416,108 +449,6 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) return ret; } -/** - * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path - * @qup: The qup_i2c_dev device - * @op: The bit/event to wait on - * @val: value of the bit to wait on, 0 or 1 - * @len: The length the bytes to be transferred - */ -static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, - int len) -{ - unsigned long timeout; - u32 opflags; - u32 status; - u32 shift = __ffs(op); - int ret = 0; - - len *= qup->one_byte_t; - /* timeout after a wait of twice the max time */ - timeout = jiffies + len * 4; - - for (;;) { - opflags = readl(qup->base + QUP_OPERATIONAL); - status = readl(qup->base + QUP_I2C_STATUS); - - if (((opflags & op) >> shift) == val) { - if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) { - if (!(status & I2C_STATUS_BUS_ACTIVE)) { - ret = 0; - goto done; - } - } else { - ret = 0; - goto done; - } - } - - if (time_after(jiffies, timeout)) { - ret = -ETIMEDOUT; - goto done; - } - usleep_range(len, len * 2); - } - -done: - if (qup->bus_err || qup->qup_err) - ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; - - return ret; -} - -static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup, - struct i2c_msg *msg) -{ - /* Number of entries to shift out, including the tags */ - int total = msg->len + qup->blk.tx_tag_len; - - total |= qup->config_run; - - if (total < qup->out_fifo_sz) { - /* FIFO mode */ - writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_WRITE_CNT); - } else { - /* BLOCK mode (transfer data on chunks) */ - writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN, - qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_OUTPUT_CNT); - } -} - -static int check_for_fifo_space(struct qup_i2c_dev *qup) -{ - int ret; - - ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); - if (ret) - goto out; - - ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, - RESET_BIT, 4 * ONE_BYTE); - if (ret) { - /* Fifo is full. Drain out the fifo */ - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto out; - - ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, - RESET_BIT, 256 * ONE_BYTE); - if (ret) { - dev_err(qup->dev, "timeout for fifo out full"); - goto out; - } - - ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); - if (ret) - goto out; - } - -out: - return ret; -} - static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) { struct qup_i2c_block *blk = &qup->blk; @@ -560,60 +491,17 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup, struct i2c_msg *msg) { - memset(&qup->blk, 0, sizeof(qup->blk)); - + qup->blk.pos = 0; qup->blk.data_len = msg->len; - qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT; - - /* 4 bytes for first block and 2 writes for rest */ - qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2; - - /* There are 2 tag bytes that are read in to fifo for every block */ - if (msg->flags & I2C_M_RD) - qup->blk.rx_tag_len = qup->blk.count * 2; -} - -static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf, - int dlen, u8 *dbuf) -{ - u32 val = 0, idx = 0, pos = 0, i = 0, t; - int len = tlen + dlen; - u8 *buf = tbuf; - int ret = 0; - - while (len > 0) { - ret = check_for_fifo_space(qup); - if (ret) - return ret; - - t = (len >= 4) ? 4 : len; - - while (idx < t) { - if (!i && (pos >= tlen)) { - buf = dbuf; - pos = 0; - i = 1; - } - val |= buf[pos++] << (idx++ * 8); - } - - writel(val, qup->base + QUP_OUT_FIFO_BASE); - idx = 0; - val = 0; - len -= 4; - } - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - - return ret; + qup->blk.count = DIV_ROUND_UP(msg->len, qup->blk_xfer_limit); } static int qup_i2c_get_data_len(struct qup_i2c_dev *qup) { int data_len; - if (qup->blk.data_len > QUP_READ_LIMIT) - data_len = QUP_READ_LIMIT; + if (qup->blk.data_len > qup->blk_xfer_limit) + data_len = qup->blk_xfer_limit; else data_len = qup->blk.data_len; @@ -630,9 +518,9 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup, { int len = 0; - if (msg->len > 1) { + if (qup->is_smbus_read) { tags[len++] = QUP_TAG_V2_DATARD_STOP; - tags[len++] = qup_i2c_get_data_len(qup) - 1; + tags[len++] = qup_i2c_get_data_len(qup); } else { tags[len++] = QUP_TAG_V2_START; tags[len++] = addr & 0xff; @@ -694,24 +582,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, return len; } -static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - int data_len = 0, tag_len, index; - int ret; - - tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg); - index = msg->len - qup->blk.data_len; - - /* only tags are written for read */ - if (!(msg->flags & I2C_M_RD)) - data_len = qup_i2c_get_data_len(qup); - - ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags, - data_len, &msg->buf[index]); - qup->blk.data_len -= data_len; - - return ret; -} static void qup_i2c_bam_cb(void *data) { @@ -778,6 +648,7 @@ static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg) u32 i = 0, tlen, tx_len = 0; u8 *tags; + qup->blk_xfer_limit = QUP_READ_LIMIT; qup_i2c_set_blk_data(qup, msg); blocks = qup->blk.count; @@ -1026,7 +897,7 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup, unsigned long left; int ret = 0; - left = wait_for_completion_timeout(&qup->xfer, HZ); + left = wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout); if (!left) { writel(1, qup->base + QUP_SW_RESET); ret = -ETIMEDOUT; @@ -1038,65 +909,6 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup, return ret; } -static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - int ret = 0; - - qup->msg = msg; - qup->pos = 0; - enable_irq(qup->irq); - qup_i2c_set_blk_data(qup, msg); - qup_i2c_set_write_mode_v2(qup, msg); - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto err; - - writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); - - do { - ret = qup_i2c_issue_xfer_v2(qup, msg); - if (ret) - goto err; - - ret = qup_i2c_wait_for_complete(qup, msg); - if (ret) - goto err; - - qup->blk.pos++; - } while (qup->blk.pos < qup->blk.count); - - ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE); - -err: - disable_irq(qup->irq); - qup->msg = NULL; - - return ret; -} - -static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len) -{ - int tx_len = qup->blk.tx_tag_len; - - len += qup->blk.rx_tag_len; - len |= qup->config_run; - tx_len |= qup->config_run; - - if (len < qup->in_fifo_sz) { - /* FIFO mode */ - writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(tx_len, qup->base + QUP_MX_WRITE_CNT); - writel(len, qup->base + QUP_MX_READ_CNT); - } else { - /* BLOCK mode (transfer data on chunks) */ - writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN, - qup->base + QUP_IO_MODE); - writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT); - writel(len, qup->base + QUP_MX_INPUT_CNT); - } -} - static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup) { struct qup_i2c_block *blk = &qup->blk; @@ -1120,104 +932,6 @@ static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup) blk->rx_bytes_read = true; } -static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, - struct i2c_msg *msg) -{ - u32 val; - int idx, pos = 0, ret = 0, total, msg_offset = 0; - - /* - * If the message length is already read in - * the first byte of the buffer, account for - * that by setting the offset - */ - if (qup_i2c_check_msg_len(msg) && (msg->len > 1)) - msg_offset = 1; - total = qup_i2c_get_data_len(qup); - total -= msg_offset; - - /* 2 extra bytes for read tags */ - while (pos < (total + 2)) { - /* Check that FIFO have data */ - ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, - SET_BIT, 4 * ONE_BYTE); - if (ret) { - dev_err(qup->dev, "timeout for fifo not empty"); - return ret; - } - val = readl(qup->base + QUP_IN_FIFO_BASE); - - for (idx = 0; idx < 4; idx++, val >>= 8, pos++) { - /* first 2 bytes are tag bytes */ - if (pos < 2) - continue; - - if (pos >= (total + 2)) - goto out; - msg->buf[qup->pos + msg_offset] = val & 0xff; - qup->pos++; - } - } - -out: - qup->blk.data_len -= total; - - return ret; -} - -static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - int ret = 0; - - qup->msg = msg; - qup->pos = 0; - enable_irq(qup->irq); - qup_i2c_set_blk_data(qup, msg); - qup_i2c_set_read_mode_v2(qup, msg->len); - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto err; - - writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); - - do { - ret = qup_i2c_issue_xfer_v2(qup, msg); - if (ret) - goto err; - - ret = qup_i2c_wait_for_complete(qup, msg); - if (ret) - goto err; - - ret = qup_i2c_read_fifo_v2(qup, msg); - if (ret) - goto err; - - qup->blk.pos++; - - /* Handle SMBus block read length */ - if (qup_i2c_check_msg_len(msg) && (msg->len == 1)) { - if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) { - ret = -EPROTO; - goto err; - } - msg->len += msg->buf[0]; - qup->pos = 0; - qup_i2c_set_blk_data(qup, msg); - /* set tag length for block read */ - qup->blk.tx_tag_len = 2; - qup_i2c_set_read_mode_v2(qup, msg->buf[0]); - } - } while (qup->blk.pos < qup->blk.count); - -err: - disable_irq(qup->irq); - qup->msg = NULL; - - return ret; -} - static void qup_i2c_write_rx_tags_v1(struct qup_i2c_dev *qup) { struct i2c_msg *msg = qup->msg; @@ -1404,13 +1118,434 @@ out: return ret; } +/* + * Configure registers related with reconfiguration during run and call it + * before each i2c sub transfer. + */ +static void qup_i2c_conf_count_v2(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + u32 qup_config = I2C_MINI_CORE | I2C_N_VAL_V2; + + if (blk->is_tx_blk_mode) + writel(qup->config_run | blk->total_tx_len, + qup->base + QUP_MX_OUTPUT_CNT); + else + writel(qup->config_run | blk->total_tx_len, + qup->base + QUP_MX_WRITE_CNT); + + if (blk->total_rx_len) { + if (blk->is_rx_blk_mode) + writel(qup->config_run | blk->total_rx_len, + qup->base + QUP_MX_INPUT_CNT); + else + writel(qup->config_run | blk->total_rx_len, + qup->base + QUP_MX_READ_CNT); + } else { + qup_config |= QUP_NO_INPUT; + } + + writel(qup_config, qup->base + QUP_CONFIG); +} + +/* + * Configure registers related with transfer mode (FIFO/Block) + * before starting of i2c transfer. It will be called only once in + * QUP RESET state. + */ +static void qup_i2c_conf_mode_v2(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + u32 io_mode = QUP_REPACK_EN; + + if (blk->is_tx_blk_mode) { + io_mode |= QUP_OUTPUT_BLK_MODE; + writel(0, qup->base + QUP_MX_WRITE_CNT); + } else { + writel(0, qup->base + QUP_MX_OUTPUT_CNT); + } + + if (blk->is_rx_blk_mode) { + io_mode |= QUP_INPUT_BLK_MODE; + writel(0, qup->base + QUP_MX_READ_CNT); + } else { + writel(0, qup->base + QUP_MX_INPUT_CNT); + } + + writel(io_mode, qup->base + QUP_IO_MODE); +} + +/* Clear required variables before starting of any QUP v2 sub transfer. */ +static void qup_i2c_clear_blk_v2(struct qup_i2c_block *blk) +{ + blk->send_last_word = false; + blk->tx_tags_sent = false; + blk->tx_fifo_data = 0; + blk->tx_fifo_data_pos = 0; + blk->tx_fifo_free = 0; + + blk->rx_tags_fetched = false; + blk->rx_bytes_read = false; + blk->rx_fifo_data = 0; + blk->rx_fifo_data_pos = 0; + blk->fifo_available = 0; +} + +/* Receive data from RX FIFO for read message in QUP v2 i2c transfer. */ +static void qup_i2c_recv_data(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + int j; + + for (j = blk->rx_fifo_data_pos; + blk->cur_blk_len && blk->fifo_available; + blk->cur_blk_len--, blk->fifo_available--) { + if (j == 0) + blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE); + + *(blk->cur_data++) = blk->rx_fifo_data; + blk->rx_fifo_data >>= 8; + + if (j == 3) + j = 0; + else + j++; + } + + blk->rx_fifo_data_pos = j; +} + +/* Receive tags for read message in QUP v2 i2c transfer. */ +static void qup_i2c_recv_tags(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + + blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE); + blk->rx_fifo_data >>= blk->rx_tag_len * 8; + blk->rx_fifo_data_pos = blk->rx_tag_len; + blk->fifo_available -= blk->rx_tag_len; +} + +/* + * Read the data and tags from RX FIFO. Since in read case, the tags will be + * preceded by received data bytes so + * 1. Check if rx_tags_fetched is false i.e. the start of QUP block so receive + * all tag bytes and discard that. + * 2. Read the data from RX FIFO. When all the data bytes have been read then + * set rx_bytes_read to true. + */ +static void qup_i2c_read_rx_fifo_v2(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + + if (!blk->rx_tags_fetched) { + qup_i2c_recv_tags(qup); + blk->rx_tags_fetched = true; + } + + qup_i2c_recv_data(qup); + if (!blk->cur_blk_len) + blk->rx_bytes_read = true; +} + +/* + * Write bytes in TX FIFO for write message in QUP v2 i2c transfer. QUP TX FIFO + * write works on word basis (4 bytes). Append new data byte write for TX FIFO + * in tx_fifo_data and write to TX FIFO when all the 4 bytes are present. + */ +static void +qup_i2c_write_blk_data(struct qup_i2c_dev *qup, u8 **data, unsigned int *len) +{ + struct qup_i2c_block *blk = &qup->blk; + unsigned int j; + + for (j = blk->tx_fifo_data_pos; *len && blk->tx_fifo_free; + (*len)--, blk->tx_fifo_free--) { + blk->tx_fifo_data |= *(*data)++ << (j * 8); + if (j == 3) { + writel(blk->tx_fifo_data, + qup->base + QUP_OUT_FIFO_BASE); + blk->tx_fifo_data = 0x0; + j = 0; + } else { + j++; + } + } + + blk->tx_fifo_data_pos = j; +} + +/* Transfer tags for read message in QUP v2 i2c transfer. */ +static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + + qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, &blk->tx_tag_len); + if (blk->tx_fifo_data_pos) + writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE); +} + +/* + * Write the data and tags in TX FIFO. Since in write case, both tags and data + * need to be written and QUP write tags can have maximum 256 data length, so + * + * 1. Check if tx_tags_sent is false i.e. the start of QUP block so write the + * tags to TX FIFO and set tx_tags_sent to true. + * 2. Check if send_last_word is true. It will be set when last few data bytes + * (less than 4 bytes) are reamining to be written in FIFO because of no FIFO + * space. All this data bytes are available in tx_fifo_data so write this + * in FIFO. + * 3. Write the data to TX FIFO and check for cur_blk_len. If it is non zero + * then more data is pending otherwise following 3 cases can be possible + * a. if tx_fifo_data_pos is zero i.e. all the data bytes in this block + * have been written in TX FIFO so nothing else is required. + * b. tx_fifo_free is non zero i.e tx FIFO is free so copy the remaining data + * from tx_fifo_data to tx FIFO. Since, qup_i2c_write_blk_data do write + * in 4 bytes and FIFO space is in multiple of 4 bytes so tx_fifo_free + * will be always greater than or equal to 4 bytes. + * c. tx_fifo_free is zero. In this case, last few bytes (less than 4 + * bytes) are copied to tx_fifo_data but couldn't be sent because of + * FIFO full so make send_last_word true. + */ +static void qup_i2c_write_tx_fifo_v2(struct qup_i2c_dev *qup) +{ + struct qup_i2c_block *blk = &qup->blk; + + if (!blk->tx_tags_sent) { + qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, + &blk->tx_tag_len); + blk->tx_tags_sent = true; + } + + if (blk->send_last_word) + goto send_last_word; + + qup_i2c_write_blk_data(qup, &blk->cur_data, &blk->cur_blk_len); + if (!blk->cur_blk_len) { + if (!blk->tx_fifo_data_pos) + return; + + if (blk->tx_fifo_free) + goto send_last_word; + + blk->send_last_word = true; + } + + return; + +send_last_word: + writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE); +} + +/* + * Main transfer function which read or write i2c data. + * The QUP v2 supports reconfiguration during run in which multiple i2c sub + * transfers can be scheduled. + */ +static int +qup_i2c_conf_xfer_v2(struct qup_i2c_dev *qup, bool is_rx, bool is_first, + bool change_pause_state) +{ + struct qup_i2c_block *blk = &qup->blk; + struct i2c_msg *msg = qup->msg; + int ret; + + /* + * Check if its SMBus Block read for which the top level read will be + * done into 2 QUP reads. One with message length 1 while other one is + * with actual length. + */ + if (qup_i2c_check_msg_len(msg)) { + if (qup->is_smbus_read) { + /* + * If the message length is already read in + * the first byte of the buffer, account for + * that by setting the offset + */ + blk->cur_data += 1; + is_first = false; + } else { + change_pause_state = false; + } + } + + qup->config_run = is_first ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN; + + qup_i2c_clear_blk_v2(blk); + qup_i2c_conf_count_v2(qup); + + /* If it is first sub transfer, then configure i2c bus clocks */ + if (is_first) { + ret = qup_i2c_change_state(qup, QUP_RUN_STATE); + if (ret) + return ret; + + writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); + + ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); + if (ret) + return ret; + } + + reinit_completion(&qup->xfer); + enable_irq(qup->irq); + /* + * In FIFO mode, tx FIFO can be written directly while in block mode the + * it will be written after getting OUT_BLOCK_WRITE_REQ interrupt + */ + if (!blk->is_tx_blk_mode) { + blk->tx_fifo_free = qup->out_fifo_sz; + + if (is_rx) + qup_i2c_write_rx_tags_v2(qup); + else + qup_i2c_write_tx_fifo_v2(qup); + } + + ret = qup_i2c_change_state(qup, QUP_RUN_STATE); + if (ret) + goto err; + + ret = qup_i2c_wait_for_complete(qup, msg); + if (ret) + goto err; + + /* Move to pause state for all the transfers, except last one */ + if (change_pause_state) { + ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); + if (ret) + goto err; + } + +err: + disable_irq(qup->irq); + return ret; +} + +/* + * Transfer one read/write message in i2c transfer. It splits the message into + * multiple of blk_xfer_limit data length blocks and schedule each + * QUP block individually. + */ +static int qup_i2c_xfer_v2_msg(struct qup_i2c_dev *qup, int msg_id, bool is_rx) +{ + int ret = 0; + unsigned int data_len, i; + struct i2c_msg *msg = qup->msg; + struct qup_i2c_block *blk = &qup->blk; + u8 *msg_buf = msg->buf; + + qup->blk_xfer_limit = is_rx ? RECV_MAX_DATA_LEN : QUP_READ_LIMIT; + qup_i2c_set_blk_data(qup, msg); + + for (i = 0; i < blk->count; i++) { + data_len = qup_i2c_get_data_len(qup); + blk->pos = i; + blk->cur_tx_tags = blk->tags; + blk->cur_blk_len = data_len; + blk->tx_tag_len = + qup_i2c_set_tags(blk->cur_tx_tags, qup, qup->msg); + + blk->cur_data = msg_buf; + + if (is_rx) { + blk->total_tx_len = blk->tx_tag_len; + blk->rx_tag_len = 2; + blk->total_rx_len = blk->rx_tag_len + data_len; + } else { + blk->total_tx_len = blk->tx_tag_len + data_len; + blk->total_rx_len = 0; + } + + ret = qup_i2c_conf_xfer_v2(qup, is_rx, !msg_id && !i, + !qup->is_last || i < blk->count - 1); + if (ret) + return ret; + + /* Handle SMBus block read length */ + if (qup_i2c_check_msg_len(msg) && msg->len == 1 && + !qup->is_smbus_read) { + if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + + msg->len = msg->buf[0]; + qup->is_smbus_read = true; + ret = qup_i2c_xfer_v2_msg(qup, msg_id, true); + qup->is_smbus_read = false; + if (ret) + return ret; + + msg->len += 1; + } + + msg_buf += data_len; + blk->data_len -= qup->blk_xfer_limit; + } + + return ret; +} + +/* + * QUP v2 supports 3 modes + * Programmed IO using FIFO mode : Less than FIFO size + * Programmed IO using Block mode : Greater than FIFO size + * DMA using BAM : Appropriate for any transaction size but the address should + * be DMA applicable + * + * This function determines the mode which will be used for this transfer. An + * i2c transfer contains multiple message. Following are the rules to determine + * the mode used. + * 1. Determine complete length, maximum tx and rx length for complete transfer. + * 2. If complete transfer length is greater than fifo size then use the DMA + * mode. + * 3. In FIFO or block mode, tx and rx can operate in different mode so check + * for maximum tx and rx length to determine mode. + */ +static int +qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup, + struct i2c_msg msgs[], int num) +{ + int idx; + bool no_dma = false; + unsigned int max_tx_len = 0, max_rx_len = 0, total_len = 0; + + /* All i2c_msgs should be transferred using either dma or cpu */ + for (idx = 0; idx < num; idx++) { + if (msgs[idx].len == 0) + return -EINVAL; + + if (msgs[idx].flags & I2C_M_RD) + max_rx_len = max_t(unsigned int, max_rx_len, + msgs[idx].len); + else + max_tx_len = max_t(unsigned int, max_tx_len, + msgs[idx].len); + + if (is_vmalloc_addr(msgs[idx].buf)) + no_dma = true; + + total_len += msgs[idx].len; + } + + if (!no_dma && qup->is_dma && + (total_len > qup->out_fifo_sz || total_len > qup->in_fifo_sz)) { + qup->use_dma = true; + } else { + qup->blk.is_tx_blk_mode = max_tx_len > qup->out_fifo_sz - + QUP_MAX_TAGS_LEN ? true : false; + qup->blk.is_rx_blk_mode = max_rx_len > qup->in_fifo_sz - + READ_RX_TAGS_LEN ? true : false; + } + + return 0; +} + static int qup_i2c_xfer_v2(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct qup_i2c_dev *qup = i2c_get_adapdata(adap); int ret, idx = 0; - unsigned int total_len = 0; qup->bus_err = 0; qup->qup_err = 0; @@ -1419,6 +1554,10 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, if (ret < 0) goto out; + ret = qup_i2c_determine_mode_v2(qup, msgs, num); + if (ret) + goto out; + writel(1, qup->base + QUP_SW_RESET); ret = qup_i2c_poll_state(qup, QUP_RESET_STATE); if (ret) @@ -1428,60 +1567,35 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG); writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN); - if ((qup->is_dma)) { - /* All i2c_msgs should be transferred using either dma or cpu */ - for (idx = 0; idx < num; idx++) { - if (msgs[idx].len == 0) { - ret = -EINVAL; - goto out; - } - - if (is_vmalloc_addr(msgs[idx].buf)) - break; - - total_len += msgs[idx].len; - } - - if (idx == num && (total_len > qup->out_fifo_sz || - total_len > qup->in_fifo_sz)) - qup->use_dma = true; + if (qup_i2c_poll_state_i2c_master(qup)) { + ret = -EIO; + goto out; } - idx = 0; - - do { - if (msgs[idx].len == 0) { - ret = -EINVAL; - goto out; - } - - if (qup_i2c_poll_state_i2c_master(qup)) { - ret = -EIO; - goto out; - } - - qup->is_last = (idx == (num - 1)); - if (idx) - qup->config_run = QUP_I2C_MX_CONFIG_DURING_RUN; - else - qup->config_run = 0; - + if (qup->use_dma) { reinit_completion(&qup->xfer); + ret = qup_i2c_bam_xfer(adap, &msgs[0], num); + qup->use_dma = false; + } else { + qup_i2c_conf_mode_v2(qup); - if (qup->use_dma) { - ret = qup_i2c_bam_xfer(adap, &msgs[idx], num); - qup->use_dma = false; - break; - } else { - if (msgs[idx].flags & I2C_M_RD) - ret = qup_i2c_read_one_v2(qup, &msgs[idx]); - else - ret = qup_i2c_write_one_v2(qup, &msgs[idx]); + for (idx = 0; idx < num; idx++) { + qup->msg = &msgs[idx]; + qup->is_last = idx == (num - 1); + + ret = qup_i2c_xfer_v2_msg(qup, idx, + !!(msgs[idx].flags & I2C_M_RD)); + if (ret) + break; } - } while ((idx++ < (num - 1)) && !ret); + qup->msg = NULL; + } if (!ret) - ret = qup_i2c_change_state(qup, QUP_RESET_STATE); + ret = qup_i2c_bus_active(qup, ONE_BYTE); + + if (!ret) + qup_i2c_change_state(qup, QUP_RESET_STATE); if (ret == 0) ret = num; @@ -1545,6 +1659,7 @@ static int qup_i2c_probe(struct platform_device *pdev) u32 src_clk_freq = DEFAULT_SRC_CLK; u32 clk_freq = DEFAULT_CLK_FREQ; int blocks; + bool is_qup_v1; qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL); if (!qup) @@ -1563,12 +1678,10 @@ static int qup_i2c_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { qup->adap.algo = &qup_i2c_algo; qup->adap.quirks = &qup_i2c_quirks; - qup->is_qup_v1 = true; - qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1; - qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1; - qup->write_rx_tags = qup_i2c_write_rx_tags_v1; + is_qup_v1 = true; } else { qup->adap.algo = &qup_i2c_algo_v2; + is_qup_v1 = false; ret = qup_i2c_req_dma(qup); if (ret == -EPROBE_DEFER) @@ -1694,14 +1807,31 @@ nodma: ret = -EIO; goto fail; } - qup->out_blk_sz = blk_sizes[size] / 2; + qup->out_blk_sz = blk_sizes[size]; size = QUP_INPUT_BLOCK_SIZE(io_mode); if (size >= ARRAY_SIZE(blk_sizes)) { ret = -EIO; goto fail; } - qup->in_blk_sz = blk_sizes[size] / 2; + qup->in_blk_sz = blk_sizes[size]; + + if (is_qup_v1) { + /* + * in QUP v1, QUP_CONFIG uses N as 15 i.e 16 bits constitutes a + * single transfer but the block size is in bytes so divide the + * in_blk_sz and out_blk_sz by 2 + */ + qup->in_blk_sz /= 2; + qup->out_blk_sz /= 2; + qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1; + qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1; + qup->write_rx_tags = qup_i2c_write_rx_tags_v1; + } else { + qup->write_tx_fifo = qup_i2c_write_tx_fifo_v2; + qup->read_rx_fifo = qup_i2c_read_rx_fifo_v2; + qup->write_rx_tags = qup_i2c_write_rx_tags_v2; + } size = QUP_OUTPUT_FIFO_SIZE(io_mode); qup->out_fifo_sz = qup->out_blk_sz * (2 << size); From df0d32348aa81208a0037b959dc23c4739439c02 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 5 Jul 2017 22:13:55 +1200 Subject: [PATCH 41/53] sh: sh7785lcr: add GPIO lookup table for i2c controller reset Define the GPIO connected to the PCA9564 using a GPIO lookup table. This will allow the i2c-pca-platform driver to use the device managed APIs to lookup the gpio instead of using platform_data. Signed-off-by: Chris Packham Signed-off-by: Wolfram Sang --- arch/sh/boards/board-sh7785lcr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c index 2c4771ee84cd..caec1ebffb09 100644 --- a/arch/sh/boards/board-sh7785lcr.c +++ b/arch/sh/boards/board-sh7785lcr.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -243,6 +244,14 @@ static struct resource i2c_resources[] = { }, }; +static struct gpiod_lookup_table i2c_gpio_table = { + .dev_id = "i2c.0", + .table = { + GPIO_LOOKUP("pfc-sh7757", 0, "reset-gpios", GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct i2c_pca9564_pf_platform_data i2c_platform_data = { .gpio = 0, .i2c_clock_speed = I2C_PCA_CON_330kHz, @@ -283,6 +292,7 @@ static int __init sh7785lcr_devices_setup(void) i2c_device.num_resources = ARRAY_SIZE(i2c_proto_resources); } + gpiod_add_lookup_table(&i2c_gpio_table); return platform_add_devices(sh7785lcr_devices, ARRAY_SIZE(sh7785lcr_devices)); } From 06783261751a44c63680e94005a4763151bc1134 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 5 Jul 2017 22:13:56 +1200 Subject: [PATCH 42/53] i2c: pca-platform: unconditionally use devm_gpiod_get_optional Allow for the reset-gpios property to be defined in the device tree or via a GPIO lookup table. Signed-off-by: Chris Packham Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pca-platform.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 853a2abedb05..b90193d09d4b 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -173,33 +173,20 @@ static int i2c_pca_pf_probe(struct platform_device *pdev) i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = np; + i2c->gpio = devm_gpiod_get_optional(&pdev->dev, "reset-gpios", GPIOD_OUT_LOW); + if (IS_ERR(i2c->gpio)) + return PTR_ERR(i2c->gpio); + if (platform_data) { i2c->adap.timeout = platform_data->timeout; i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed; - if (gpio_is_valid(platform_data->gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - platform_data->gpio, - GPIOF_ACTIVE_LOW, - i2c->adap.name); - if (ret == 0) { - i2c->gpio = gpio_to_desc(platform_data->gpio); - gpiod_direction_output(i2c->gpio, 0); - } else { - dev_warn(&pdev->dev, "Registering gpio failed!\n"); - i2c->gpio = NULL; - } - } } else if (np) { i2c->adap.timeout = HZ; - i2c->gpio = devm_gpiod_get_optional(&pdev->dev, "reset-gpios", GPIOD_OUT_LOW); - if (IS_ERR(i2c->gpio)) - return PTR_ERR(i2c->gpio); of_property_read_u32_index(np, "clock-frequency", 0, &i2c->algo_data.i2c_clock); } else { i2c->adap.timeout = HZ; i2c->algo_data.i2c_clock = 59000; - i2c->gpio = NULL; } i2c->algo_data.data = i2c; From 7562dee282244aade6fa183487bf2fcecaa42a20 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 5 Jul 2017 22:13:57 +1200 Subject: [PATCH 43/53] i2c: pca-platform: use device_property_read_u32 Use device_property_read_u32 instead of of_property_read_u32_index to lookup the "clock-frequency" property. Signed-off-by: Chris Packham Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pca-platform.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index b90193d09d4b..bc2707ffd409 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -177,16 +177,15 @@ static int i2c_pca_pf_probe(struct platform_device *pdev) if (IS_ERR(i2c->gpio)) return PTR_ERR(i2c->gpio); + i2c->adap.timeout = HZ; + ret = device_property_read_u32(&pdev->dev, "clock-frequency", + &i2c->algo_data.i2c_clock); + if (ret) + i2c->algo_data.i2c_clock = 59000; + if (platform_data) { i2c->adap.timeout = platform_data->timeout; i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed; - } else if (np) { - i2c->adap.timeout = HZ; - of_property_read_u32_index(np, "clock-frequency", 0, - &i2c->algo_data.i2c_clock); - } else { - i2c->adap.timeout = HZ; - i2c->algo_data.i2c_clock = 59000; } i2c->algo_data.data = i2c; From eb49778c8c6cbe075cf90d741ccf16f674a8db4e Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 5 Jul 2017 22:13:58 +1200 Subject: [PATCH 44/53] i2c: pca-platform: drop gpio from platform data Now that the i2c-pca-plaform driver is using the device managed API for gpios there is no need for the reset gpio to be specified via i2c_pca9564_pf_platform_data. Signed-off-by: Chris Packham Signed-off-by: Wolfram Sang --- arch/blackfin/mach-bf561/boards/acvilon.c | 1 - arch/sh/boards/board-sh7785lcr.c | 1 - include/linux/i2c-pca-platform.h | 3 --- 3 files changed, 5 deletions(-) diff --git a/arch/blackfin/mach-bf561/boards/acvilon.c b/arch/blackfin/mach-bf561/boards/acvilon.c index 696cc9d7820a..9dd612220211 100644 --- a/arch/blackfin/mach-bf561/boards/acvilon.c +++ b/arch/blackfin/mach-bf561/boards/acvilon.c @@ -112,7 +112,6 @@ static struct resource bfin_i2c_pca_resources[] = { }; struct i2c_pca9564_pf_platform_data pca9564_platform_data = { - .gpio = -1, .i2c_clock_speed = 330000, .timeout = HZ, }; diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c index caec1ebffb09..d7d232dea33e 100644 --- a/arch/sh/boards/board-sh7785lcr.c +++ b/arch/sh/boards/board-sh7785lcr.c @@ -253,7 +253,6 @@ static struct gpiod_lookup_table i2c_gpio_table = { }; static struct i2c_pca9564_pf_platform_data i2c_platform_data = { - .gpio = 0, .i2c_clock_speed = I2C_PCA_CON_330kHz, .timeout = HZ, }; diff --git a/include/linux/i2c-pca-platform.h b/include/linux/i2c-pca-platform.h index 0e5f7c77d1d8..c37329432a8e 100644 --- a/include/linux/i2c-pca-platform.h +++ b/include/linux/i2c-pca-platform.h @@ -3,9 +3,6 @@ #define I2C_PCA9564_PLATFORM_H struct i2c_pca9564_pf_platform_data { - int gpio; /* pin to reset chip. driver will work when - * not supplied (negative value), but it - * cannot exit some error conditions then */ int i2c_clock_speed; /* values are defined in linux/i2c-algo-pca.h */ int timeout; /* timeout in jiffies */ }; From 9d952aa2c8a46ba577b77619cc53e3df95507095 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 20 Mar 2018 22:53:20 +0100 Subject: [PATCH 45/53] dt-bindings: i2c: document R8A77965 bindings R-Car M3-N (R8A77965) SoC has a R-Car Gen3-compatible I2C controller. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-rcar.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index e91dbafe71e5..4a7811ecd954 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -13,6 +13,7 @@ Required properties: "renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC. "renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC. "renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC. + "renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC. "renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC. "renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC. "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device. From a1de3253a8840bf373e7c6330f21b7807c6c0536 Mon Sep 17 00:00:00 2001 From: Hiromitsu Yamasaki Date: Tue, 20 Mar 2018 22:04:14 +0100 Subject: [PATCH 46/53] i2c: rcar: fix mask value of prohibited bit According to documentation, Bit 7 of ICMSR is unused and 0 should be written to it. Fix the mask accordingly. Signed-off-by: Hiromitsu Yamasaki [wsa: edited commit message] Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 4159ebcec2bb..c6915b835396 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -102,8 +102,8 @@ #define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR) #define RCAR_IRQ_STOP (MST) -#define RCAR_IRQ_ACK_SEND (~(MAT | MDE) & 0xFF) -#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0xFF) +#define RCAR_IRQ_ACK_SEND (~(MAT | MDE) & 0x7F) +#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0x7F) #define ID_LAST_MSG (1 << 0) #define ID_FIRST_MSG (1 << 1) From 398432eddea4197880a067718e2711d3f5f11d18 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 20 Mar 2018 21:54:38 +0100 Subject: [PATCH 47/53] i2c: make i2c_check_addr_validity() static After previous refactoring, there is only one user in the same file left. Make the function static now. [wsa: added 'int' to bare 'unsigned'] Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 2 +- drivers/i2c/i2c-core.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 16a3b73375a6..c8bfe008f208 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -517,7 +517,7 @@ static unsigned short i2c_encode_flags_to_addr(struct i2c_client *client) /* This is a permissive address validity check, I2C address map constraints * are purposely not enforced, except for the general call address. */ -int i2c_check_addr_validity(unsigned addr, unsigned short flags) +static int i2c_check_addr_validity(unsigned int addr, unsigned short flags) { if (flags & I2C_CLIENT_TEN) { /* 10-bit address, all values are valid */ diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 3d3d9bf02101..37576f50fe20 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -27,7 +27,6 @@ extern struct rw_semaphore __i2c_board_lock; extern struct list_head __i2c_board_list; extern int __i2c_first_dynamic_bus_num; -int i2c_check_addr_validity(unsigned addr, unsigned short flags); int i2c_check_7bit_addr_validity_strict(unsigned short addr); #ifdef CONFIG_ACPI From 90ad2cbe88c22d0215225ab9594eeead0eb24fde Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 8 Mar 2018 14:25:17 +0100 Subject: [PATCH 48/53] i2c: imx: use clk notifier for rate changes Instead of repeatedly calling clk_get_rate for each transfer, register a clock notifier to update the cached divider value each time the clock rate actually changes. Signed-off-by: Lucas Stach Reviewed-by: Philipp Zabel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 999557729ad2..c9632b2f0eaa 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -194,6 +194,7 @@ struct imx_i2c_dma { struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; + struct notifier_block clk_change_nb; void __iomem *base; wait_queue_head_t queue; unsigned long i2csr; @@ -467,15 +468,14 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) return 0; } -static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) +static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, + unsigned int i2c_clk_rate) { struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; - unsigned int i2c_clk_rate; unsigned int div; int i; /* Divider value calculation */ - i2c_clk_rate = clk_get_rate(i2c_imx->clk); if (i2c_imx->cur_clk == i2c_clk_rate) return; @@ -510,6 +510,20 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) #endif } +static int i2c_imx_clk_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct clk_notifier_data *ndata = data; + struct imx_i2c_struct *i2c_imx = container_of(&ndata->clk, + struct imx_i2c_struct, + clk); + + if (action & POST_RATE_CHANGE) + i2c_imx_set_clk(i2c_imx, ndata->new_rate); + + return NOTIFY_OK; +} + static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) { unsigned int temp = 0; @@ -517,8 +531,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); - i2c_imx_set_clk(i2c_imx); - imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); /* Enable I2C controller */ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); @@ -1131,6 +1143,9 @@ static int i2c_imx_probe(struct platform_device *pdev) "clock-frequency", &i2c_imx->bitrate); if (ret < 0 && pdata && pdata->bitrate) i2c_imx->bitrate = pdata->bitrate; + i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call; + clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb); + i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); /* Set up chip registers to defaults */ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, @@ -1141,12 +1156,12 @@ static int i2c_imx_probe(struct platform_device *pdev) ret = i2c_imx_init_recovery_info(i2c_imx, pdev); /* Give it another chance if pinctrl used is not ready yet */ if (ret == -EPROBE_DEFER) - goto rpm_disable; + goto clk_notifier_unregister; /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_imx->adapter); if (ret < 0) - goto rpm_disable; + goto clk_notifier_unregister; pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); @@ -1162,6 +1177,8 @@ static int i2c_imx_probe(struct platform_device *pdev) return 0; /* Return OK */ +clk_notifier_unregister: + clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); rpm_disable: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1195,6 +1212,7 @@ static int i2c_imx_remove(struct platform_device *pdev) imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); + clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); clk_disable_unprepare(i2c_imx->clk); pm_runtime_put_noidle(&pdev->dev); From d9a22d713acb484f9d60861598a71e28129c0afa Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 8 Mar 2018 14:25:18 +0100 Subject: [PATCH 49/53] i2c: imx: avoid taking clk_prepare mutex in PM callbacks This is unsafe, as the runtime PM callbacks are called from the PM workqueue, so this may deadlock when handling an i2c attached clock, which may already hold the clk_prepare mutex from another context. Signed-off-by: Lucas Stach Reviewed-by: Philipp Zabel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index c9632b2f0eaa..d7267dd9c7bf 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1226,7 +1226,7 @@ static int i2c_imx_runtime_suspend(struct device *dev) { struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); - clk_disable_unprepare(i2c_imx->clk); + clk_disable(i2c_imx->clk); return 0; } @@ -1236,7 +1236,7 @@ static int i2c_imx_runtime_resume(struct device *dev) struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(i2c_imx->clk); + ret = clk_enable(i2c_imx->clk); if (ret) dev_err(dev, "can't enable I2C clock, ret=%d\n", ret); From 4a3f7691e2f722421b231d3f3fa05b0a6670a20a Mon Sep 17 00:00:00 2001 From: Ahbong Chang Date: Sat, 31 Mar 2018 16:17:34 +0800 Subject: [PATCH 50/53] i2c: fix parameter of trace_i2c_result According to the event i2c_result defined in include/trace/events/i2c.h, the second parameter should be the number of messages instead of the ended loop index. The value of ended loop index is the same as ret. Signed-off-by: Ahbong Chang Reviewed-by: Todd Poynor Reviewed-by: David Howells Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index c8bfe008f208..a7909d196f4c 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1876,7 +1876,7 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) for (i = 0; i < ret; i++) if (msgs[i].flags & I2C_M_RD) trace_i2c_reply(adap, &msgs[i], i); - trace_i2c_result(adap, i, ret); + trace_i2c_result(adap, num, ret); } return ret; From 50888b015d1318a5d76c961f80bab79249cb1000 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Mon, 26 Mar 2018 14:09:24 -0700 Subject: [PATCH 51/53] i2c: Update i2c_trace_msg static key to modern api No changes in refcount semantics -- key init is false; replace static_key_slow_inc|dec with static_branch_inc|dec static_key_false with static_branch_unlikely Added a '_key' suffix to i2c_trace_msg, for better self documentation. Signed-off-by: Davidlohr Bueso Reviewed-by: David Howells Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index a7909d196f4c..1adeebaa81b0 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -69,18 +69,18 @@ static DEFINE_IDR(i2c_adapter_idr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); -static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; +static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key); static bool is_registered; int i2c_transfer_trace_reg(void) { - static_key_slow_inc(&i2c_trace_msg); + static_branch_inc(&i2c_trace_msg_key); return 0; } void i2c_transfer_trace_unreg(void) { - static_key_slow_dec(&i2c_trace_msg); + static_branch_dec(&i2c_trace_msg_key); } const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, @@ -1848,11 +1848,12 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) return -EOPNOTSUPP; - /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets + /* + * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed. */ - if (static_key_false(&i2c_trace_msg)) { + if (static_branch_unlikely(&i2c_trace_msg_key)) { int i; for (i = 0; i < num; i++) if (msgs[i].flags & I2C_M_RD) @@ -1871,7 +1872,7 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) break; } - if (static_key_false(&i2c_trace_msg)) { + if (static_branch_unlikely(&i2c_trace_msg_key)) { int i; for (i = 0; i < ret; i++) if (msgs[i].flags & I2C_M_RD) From 730b35e08c5721dece9e624a33481d78cde221df Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 3 Apr 2018 21:11:48 +0200 Subject: [PATCH 52/53] dt-bindings: i2c: add binding for Socionext SynQuacer I2C Add a binding for the I2C controller that can be found in the Socionext SynQuacer SoC. Signed-off-by: Ard Biesheuvel Reviewed-by: Rob Herring Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-synquacer.txt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-synquacer.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-synquacer.txt b/Documentation/devicetree/bindings/i2c/i2c-synquacer.txt new file mode 100644 index 000000000000..72f4a2f0fedc --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-synquacer.txt @@ -0,0 +1,29 @@ +Socionext SynQuacer I2C + +Required properties: +- compatible : Must be "socionext,synquacer-i2c" +- reg : Offset and length of the register set for the device +- interrupts : A single interrupt specifier +- #address-cells : Must be <1>; +- #size-cells : Must be <0>; +- clock-names : Must contain "pclk". +- clocks : Must contain an entry for each name in clock-names. + (See the common clock bindings.) + +Optional properties: +- clock-frequency : Desired I2C bus clock frequency in Hz. As only Normal and + Fast modes are supported, possible values are 100000 and + 400000. + +Example : + + i2c@51210000 { + compatible = "socionext,synquacer-i2c"; + reg = <0x51210000 0x1000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "pclk"; + clocks = <&clk_i2c>; + clock-frequency = <400000>; + }; From 0d676a6c439028b046610f7593f4ddb62680f1fb Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 3 Apr 2018 21:11:49 +0200 Subject: [PATCH 53/53] i2c: add support for Socionext SynQuacer I2C controller This is a cleaned up version of the I2C controller driver for the Fujitsu F_I2C IP, which was never supported upstream, and has now been incorporated into the Socionext SynQuacer SoC. Signed-off-by: Ard Biesheuvel Reviewed-by: Andy Shevchenko [wsa: updated MAINTAINERS entry and removed two empty lines] Signed-off-by: Wolfram Sang --- MAINTAINERS | 7 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-synquacer.c | 667 +++++++++++++++++++++++++++++ 4 files changed, 685 insertions(+) create mode 100644 drivers/i2c/busses/i2c-synquacer.c diff --git a/MAINTAINERS b/MAINTAINERS index 2d3f847cdc8d..284867be62c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12816,6 +12816,13 @@ F: include/media/soc* F: drivers/media/i2c/soc_camera/ F: drivers/media/platform/soc_camera/ +SOCIONEXT SYNQUACER I2C DRIVER +M: Ard Biesheuvel +L: linux-i2c@vger.kernel.org +S: Maintained +F: drivers/i2c/busses/i2c-synquacer.c +F: Documentation/devicetree/bindings/i2c/i2c-synquacer.txt + SOCIONEXT UNIPHIER SOUND DRIVER M: Katsuhiro Suzuki L: alsa-devel@alsa-project.org (moderated for non-subscribers) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e2954fb86d65..56903952d364 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -997,6 +997,16 @@ config I2C_SUN6I_P2WI This interface is used to connect to specific PMIC devices (like the AXP221). +config I2C_SYNQUACER + tristate "Socionext SynQuacer I2C controller" + depends on ARCH_SYNQUACER || COMPILE_TEST + help + Say Y here to include support for the I2C controller used in some + Fujitsu and Socionext SoCs. + + This driver can also be built as a module. If so, the module + will be called i2c-synquacer. + config I2C_TEGRA tristate "NVIDIA Tegra internal I2C controller" depends on ARCH_TEGRA diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 2ce8576540a2..40ab7bfc3458 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o +obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c new file mode 100644 index 000000000000..a021f866d8c2 --- /dev/null +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -0,0 +1,667 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2012 FUJITSU SEMICONDUCTOR LIMITED + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WAIT_PCLK(n, rate) \ + ndelay(DIV_ROUND_UP(DIV_ROUND_UP(1000000000, rate), n) + 10) + +/* I2C register address definitions */ +#define SYNQUACER_I2C_REG_BSR (0x00 << 2) // Bus Status +#define SYNQUACER_I2C_REG_BCR (0x01 << 2) // Bus Control +#define SYNQUACER_I2C_REG_CCR (0x02 << 2) // Clock Control +#define SYNQUACER_I2C_REG_ADR (0x03 << 2) // Address +#define SYNQUACER_I2C_REG_DAR (0x04 << 2) // Data +#define SYNQUACER_I2C_REG_CSR (0x05 << 2) // Expansion CS +#define SYNQUACER_I2C_REG_FSR (0x06 << 2) // Bus Clock Freq +#define SYNQUACER_I2C_REG_BC2R (0x07 << 2) // Bus Control 2 + +/* I2C register bit definitions */ +#define SYNQUACER_I2C_BSR_FBT BIT(0) // First Byte Transfer +#define SYNQUACER_I2C_BSR_GCA BIT(1) // General Call Address +#define SYNQUACER_I2C_BSR_AAS BIT(2) // Address as Slave +#define SYNQUACER_I2C_BSR_TRX BIT(3) // Transfer/Receive +#define SYNQUACER_I2C_BSR_LRB BIT(4) // Last Received Bit +#define SYNQUACER_I2C_BSR_AL BIT(5) // Arbitration Lost +#define SYNQUACER_I2C_BSR_RSC BIT(6) // Repeated Start Cond. +#define SYNQUACER_I2C_BSR_BB BIT(7) // Bus Busy + +#define SYNQUACER_I2C_BCR_INT BIT(0) // Interrupt +#define SYNQUACER_I2C_BCR_INTE BIT(1) // Interrupt Enable +#define SYNQUACER_I2C_BCR_GCAA BIT(2) // Gen. Call Access Ack. +#define SYNQUACER_I2C_BCR_ACK BIT(3) // Acknowledge +#define SYNQUACER_I2C_BCR_MSS BIT(4) // Master Slave Select +#define SYNQUACER_I2C_BCR_SCC BIT(5) // Start Condition Cont. +#define SYNQUACER_I2C_BCR_BEIE BIT(6) // Bus Error Int Enable +#define SYNQUACER_I2C_BCR_BER BIT(7) // Bus Error + +#define SYNQUACER_I2C_CCR_CS_MASK (0x1f) // CCR Clock Period Sel. +#define SYNQUACER_I2C_CCR_EN BIT(5) // Enable +#define SYNQUACER_I2C_CCR_FM BIT(6) // Speed Mode Select + +#define SYNQUACER_I2C_CSR_CS_MASK (0x3f) // CSR Clock Period Sel. + +#define SYNQUACER_I2C_BC2R_SCLL BIT(0) // SCL Low Drive +#define SYNQUACER_I2C_BC2R_SDAL BIT(1) // SDA Low Drive +#define SYNQUACER_I2C_BC2R_SCLS BIT(4) // SCL Status +#define SYNQUACER_I2C_BC2R_SDAS BIT(5) // SDA Status + +/* PCLK frequency */ +#define SYNQUACER_I2C_BUS_CLK_FR(rate) (((rate) / 20000000) + 1) + +/* STANDARD MODE frequency */ +#define SYNQUACER_I2C_CLK_MASTER_STD(rate) \ + DIV_ROUND_UP(DIV_ROUND_UP((rate), 100000) - 2, 2) +/* FAST MODE frequency */ +#define SYNQUACER_I2C_CLK_MASTER_FAST(rate) \ + DIV_ROUND_UP((DIV_ROUND_UP((rate), 400000) - 2) * 2, 3) + +/* (clkrate <= 18000000) */ +/* calculate the value of CS bits in CCR register on standard mode */ +#define SYNQUACER_I2C_CCR_CS_STD_MAX_18M(rate) \ + ((SYNQUACER_I2C_CLK_MASTER_STD(rate) - 65) \ + & SYNQUACER_I2C_CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on standard mode */ +#define SYNQUACER_I2C_CSR_CS_STD_MAX_18M(rate) 0x00 + +/* calculate the value of CS bits in CCR register on fast mode */ +#define SYNQUACER_I2C_CCR_CS_FAST_MAX_18M(rate) \ + ((SYNQUACER_I2C_CLK_MASTER_FAST(rate) - 1) \ + & SYNQUACER_I2C_CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on fast mode */ +#define SYNQUACER_I2C_CSR_CS_FAST_MAX_18M(rate) 0x00 + +/* (clkrate > 18000000) */ +/* calculate the value of CS bits in CCR register on standard mode */ +#define SYNQUACER_I2C_CCR_CS_STD_MIN_18M(rate) \ + ((SYNQUACER_I2C_CLK_MASTER_STD(rate) - 1) \ + & SYNQUACER_I2C_CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on standard mode */ +#define SYNQUACER_I2C_CSR_CS_STD_MIN_18M(rate) \ + (((SYNQUACER_I2C_CLK_MASTER_STD(rate) - 1) >> 5) \ + & SYNQUACER_I2C_CSR_CS_MASK) + +/* calculate the value of CS bits in CCR register on fast mode */ +#define SYNQUACER_I2C_CCR_CS_FAST_MIN_18M(rate) \ + ((SYNQUACER_I2C_CLK_MASTER_FAST(rate) - 1) \ + & SYNQUACER_I2C_CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on fast mode */ +#define SYNQUACER_I2C_CSR_CS_FAST_MIN_18M(rate) \ + (((SYNQUACER_I2C_CLK_MASTER_FAST(rate) - 1) >> 5) \ + & SYNQUACER_I2C_CSR_CS_MASK) + +/* min I2C clock frequency 14M */ +#define SYNQUACER_I2C_MIN_CLK_RATE (14 * 1000000) +/* max I2C clock frequency 200M */ +#define SYNQUACER_I2C_MAX_CLK_RATE (200 * 1000000) +/* I2C clock frequency 18M */ +#define SYNQUACER_I2C_CLK_RATE_18M (18 * 1000000) + +#define SYNQUACER_I2C_SPEED_FM 400 // Fast Mode +#define SYNQUACER_I2C_SPEED_SM 100 // Standard Mode + +enum i2c_state { + STATE_IDLE, + STATE_START, + STATE_READ, + STATE_WRITE +}; + +struct synquacer_i2c { + struct completion completion; + + struct i2c_msg *msg; + u32 msg_num; + u32 msg_idx; + u32 msg_ptr; + + int irq; + struct device *dev; + void __iomem *base; + struct clk *pclk; + u32 pclkrate; + u32 speed_khz; + u32 timeout_ms; + enum i2c_state state; + struct i2c_adapter adapter; + + bool is_suspended; +}; + +static inline int is_lastmsg(struct synquacer_i2c *i2c) +{ + return i2c->msg_idx >= (i2c->msg_num - 1); +} + +static inline int is_msglast(struct synquacer_i2c *i2c) +{ + return i2c->msg_ptr == (i2c->msg->len - 1); +} + +static inline int is_msgend(struct synquacer_i2c *i2c) +{ + return i2c->msg_ptr >= i2c->msg->len; +} + +static inline unsigned long calc_timeout_ms(struct synquacer_i2c *i2c, + struct i2c_msg *msgs, + int num) +{ + unsigned long bit_count = 0; + int i; + + for (i = 0; i < num; i++, msgs++) + bit_count += msgs->len; + + return DIV_ROUND_UP((bit_count * 9 + num * 10) * 3, 200) + 10; +} + +static void synquacer_i2c_stop(struct synquacer_i2c *i2c, int ret) +{ + /* + * clear IRQ (INT=0, BER=0) + * set Stop Condition (MSS=0) + * Interrupt Disable + */ + writeb(0, i2c->base + SYNQUACER_I2C_REG_BCR); + + i2c->state = STATE_IDLE; + + i2c->msg_ptr = 0; + i2c->msg = NULL; + i2c->msg_idx++; + i2c->msg_num = 0; + if (ret) + i2c->msg_idx = ret; + + complete(&i2c->completion); +} + +static void synquacer_i2c_hw_init(struct synquacer_i2c *i2c) +{ + unsigned char ccr_cs, csr_cs; + u32 rt = i2c->pclkrate; + + /* Set own Address */ + writeb(0, i2c->base + SYNQUACER_I2C_REG_ADR); + + /* Set PCLK frequency */ + writeb(SYNQUACER_I2C_BUS_CLK_FR(i2c->pclkrate), + i2c->base + SYNQUACER_I2C_REG_FSR); + + switch (i2c->speed_khz) { + case SYNQUACER_I2C_SPEED_FM: + if (i2c->pclkrate <= SYNQUACER_I2C_CLK_RATE_18M) { + ccr_cs = SYNQUACER_I2C_CCR_CS_FAST_MAX_18M(rt); + csr_cs = SYNQUACER_I2C_CSR_CS_FAST_MAX_18M(rt); + } else { + ccr_cs = SYNQUACER_I2C_CCR_CS_FAST_MIN_18M(rt); + csr_cs = SYNQUACER_I2C_CSR_CS_FAST_MIN_18M(rt); + } + + /* Set Clock and enable, Set fast mode */ + writeb(ccr_cs | SYNQUACER_I2C_CCR_FM | + SYNQUACER_I2C_CCR_EN, + i2c->base + SYNQUACER_I2C_REG_CCR); + writeb(csr_cs, i2c->base + SYNQUACER_I2C_REG_CSR); + break; + case SYNQUACER_I2C_SPEED_SM: + if (i2c->pclkrate <= SYNQUACER_I2C_CLK_RATE_18M) { + ccr_cs = SYNQUACER_I2C_CCR_CS_STD_MAX_18M(rt); + csr_cs = SYNQUACER_I2C_CSR_CS_STD_MAX_18M(rt); + } else { + ccr_cs = SYNQUACER_I2C_CCR_CS_STD_MIN_18M(rt); + csr_cs = SYNQUACER_I2C_CSR_CS_STD_MIN_18M(rt); + } + + /* Set Clock and enable, Set standard mode */ + writeb(ccr_cs | SYNQUACER_I2C_CCR_EN, + i2c->base + SYNQUACER_I2C_REG_CCR); + writeb(csr_cs, i2c->base + SYNQUACER_I2C_REG_CSR); + break; + default: + WARN_ON(1); + } + + /* clear IRQ (INT=0, BER=0), Interrupt Disable */ + writeb(0, i2c->base + SYNQUACER_I2C_REG_BCR); + writeb(0, i2c->base + SYNQUACER_I2C_REG_BC2R); +} + +static void synquacer_i2c_hw_reset(struct synquacer_i2c *i2c) +{ + /* Disable clock */ + writeb(0, i2c->base + SYNQUACER_I2C_REG_CCR); + writeb(0, i2c->base + SYNQUACER_I2C_REG_CSR); + + WAIT_PCLK(100, i2c->pclkrate); +} + +static int synquacer_i2c_master_start(struct synquacer_i2c *i2c, + struct i2c_msg *pmsg) +{ + unsigned char bsr, bcr; + + writeb(i2c_8bit_addr_from_msg(pmsg), i2c->base + SYNQUACER_I2C_REG_DAR); + + dev_dbg(i2c->dev, "slave:0x%02x\n", pmsg->addr); + + /* Generate Start Condition */ + bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR); + bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR); + dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr); + + if ((bsr & SYNQUACER_I2C_BSR_BB) && + !(bcr & SYNQUACER_I2C_BCR_MSS)) { + dev_dbg(i2c->dev, "bus is busy"); + return -EBUSY; + } + + if (bsr & SYNQUACER_I2C_BSR_BB) { /* Bus is busy */ + dev_dbg(i2c->dev, "Continuous Start"); + writeb(bcr | SYNQUACER_I2C_BCR_SCC, + i2c->base + SYNQUACER_I2C_REG_BCR); + } else { + if (bcr & SYNQUACER_I2C_BCR_MSS) { + dev_dbg(i2c->dev, "not in master mode"); + return -EAGAIN; + } + dev_dbg(i2c->dev, "Start Condition"); + /* Start Condition + Enable Interrupts */ + writeb(bcr | SYNQUACER_I2C_BCR_MSS | + SYNQUACER_I2C_BCR_INTE | SYNQUACER_I2C_BCR_BEIE, + i2c->base + SYNQUACER_I2C_REG_BCR); + } + + WAIT_PCLK(10, i2c->pclkrate); + + /* get BSR & BCR registers */ + bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR); + bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR); + dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr); + + if ((bsr & SYNQUACER_I2C_BSR_AL) || + !(bcr & SYNQUACER_I2C_BCR_MSS)) { + dev_dbg(i2c->dev, "arbitration lost\n"); + return -EAGAIN; + } + + return 0; +} + +static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c, + struct i2c_msg *msgs, int num) +{ + unsigned char bsr; + unsigned long timeout; + int ret; + + if (i2c->is_suspended) + return -EBUSY; + + synquacer_i2c_hw_init(i2c); + bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR); + if (bsr & SYNQUACER_I2C_BSR_BB) { + dev_err(i2c->dev, "cannot get bus (bus busy)\n"); + return -EBUSY; + } + + reinit_completion(&i2c->completion); + + i2c->msg = msgs; + i2c->msg_num = num; + i2c->msg_ptr = 0; + i2c->msg_idx = 0; + i2c->state = STATE_START; + + ret = synquacer_i2c_master_start(i2c, i2c->msg); + if (ret < 0) { + dev_dbg(i2c->dev, "Address failed: (%d)\n", ret); + return ret; + } + + timeout = wait_for_completion_timeout(&i2c->completion, + msecs_to_jiffies(i2c->timeout_ms)); + if (timeout == 0) { + dev_dbg(i2c->dev, "timeout\n"); + return -EAGAIN; + } + + ret = i2c->msg_idx; + if (ret != num) { + dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + return -EAGAIN; + } + + /* wait 2 clock periods to ensure the stop has been through the bus */ + udelay(DIV_ROUND_UP(2 * 1000, i2c->speed_khz)); + + return 0; +} + +static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id) +{ + struct synquacer_i2c *i2c = dev_id; + + unsigned char byte; + unsigned char bsr, bcr; + int ret; + + bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR); + bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR); + dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr); + + if (bcr & SYNQUACER_I2C_BCR_BER) { + dev_err(i2c->dev, "bus error\n"); + synquacer_i2c_stop(i2c, -EAGAIN); + goto out; + } + if ((bsr & SYNQUACER_I2C_BSR_AL) || + !(bcr & SYNQUACER_I2C_BCR_MSS)) { + dev_dbg(i2c->dev, "arbitration lost\n"); + synquacer_i2c_stop(i2c, -EAGAIN); + goto out; + } + + switch (i2c->state) { + case STATE_START: + if (bsr & SYNQUACER_I2C_BSR_LRB) { + dev_dbg(i2c->dev, "ack was not received\n"); + synquacer_i2c_stop(i2c, -EAGAIN); + goto out; + } + + if (i2c->msg->flags & I2C_M_RD) + i2c->state = STATE_READ; + else + i2c->state = STATE_WRITE; + + if (is_lastmsg(i2c) && i2c->msg->len == 0) { + synquacer_i2c_stop(i2c, 0); + goto out; + } + + if (i2c->state == STATE_READ) + goto prepare_read; + + /* fallthru */ + + case STATE_WRITE: + if (bsr & SYNQUACER_I2C_BSR_LRB) { + dev_dbg(i2c->dev, "WRITE: No Ack\n"); + synquacer_i2c_stop(i2c, -EAGAIN); + goto out; + } + + if (!is_msgend(i2c)) { + writeb(i2c->msg->buf[i2c->msg_ptr++], + i2c->base + SYNQUACER_I2C_REG_DAR); + + /* clear IRQ, and continue */ + writeb(SYNQUACER_I2C_BCR_BEIE | + SYNQUACER_I2C_BCR_MSS | + SYNQUACER_I2C_BCR_INTE, + i2c->base + SYNQUACER_I2C_REG_BCR); + break; + } + if (is_lastmsg(i2c)) { + synquacer_i2c_stop(i2c, 0); + break; + } + dev_dbg(i2c->dev, "WRITE: Next Message\n"); + + i2c->msg_ptr = 0; + i2c->msg_idx++; + i2c->msg++; + + /* send the new start */ + ret = synquacer_i2c_master_start(i2c, i2c->msg); + if (ret < 0) { + dev_dbg(i2c->dev, "restart error (%d)\n", ret); + synquacer_i2c_stop(i2c, -EAGAIN); + break; + } + i2c->state = STATE_START; + break; + + case STATE_READ: + byte = readb(i2c->base + SYNQUACER_I2C_REG_DAR); + if (!(bsr & SYNQUACER_I2C_BSR_FBT)) /* data */ + i2c->msg->buf[i2c->msg_ptr++] = byte; + else /* address */ + dev_dbg(i2c->dev, "address:0x%02x. ignore it.\n", byte); + +prepare_read: + if (is_msglast(i2c)) { + writeb(SYNQUACER_I2C_BCR_MSS | + SYNQUACER_I2C_BCR_BEIE | + SYNQUACER_I2C_BCR_INTE, + i2c->base + SYNQUACER_I2C_REG_BCR); + break; + } + if (!is_msgend(i2c)) { + writeb(SYNQUACER_I2C_BCR_MSS | + SYNQUACER_I2C_BCR_BEIE | + SYNQUACER_I2C_BCR_INTE | + SYNQUACER_I2C_BCR_ACK, + i2c->base + SYNQUACER_I2C_REG_BCR); + break; + } + if (is_lastmsg(i2c)) { + /* last message, send stop and complete */ + dev_dbg(i2c->dev, "READ: Send Stop\n"); + synquacer_i2c_stop(i2c, 0); + break; + } + dev_dbg(i2c->dev, "READ: Next Transfer\n"); + + i2c->msg_ptr = 0; + i2c->msg_idx++; + i2c->msg++; + + ret = synquacer_i2c_master_start(i2c, i2c->msg); + if (ret < 0) { + dev_dbg(i2c->dev, "restart error (%d)\n", ret); + synquacer_i2c_stop(i2c, -EAGAIN); + } else { + i2c->state = STATE_START; + } + break; + default: + dev_err(i2c->dev, "called in err STATE (%d)\n", i2c->state); + break; + } + +out: + WAIT_PCLK(10, i2c->pclkrate); + return IRQ_HANDLED; +} + +static int synquacer_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct synquacer_i2c *i2c; + int retry; + int ret; + + i2c = i2c_get_adapdata(adap); + i2c->timeout_ms = calc_timeout_ms(i2c, msgs, num); + + dev_dbg(i2c->dev, "calculated timeout %d ms\n", i2c->timeout_ms); + + for (retry = 0; retry < adap->retries; retry++) { + ret = synquacer_i2c_doxfer(i2c, msgs, num); + if (ret != -EAGAIN) + return ret; + + dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); + + synquacer_i2c_hw_reset(i2c); + } + return -EIO; +} + +static u32 synquacer_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm synquacer_i2c_algo = { + .master_xfer = synquacer_i2c_xfer, + .functionality = synquacer_i2c_functionality, +}; + +static struct i2c_adapter synquacer_i2c_ops = { + .owner = THIS_MODULE, + .name = "synquacer_i2c-adapter", + .algo = &synquacer_i2c_algo, + .retries = 5, +}; + +static int synquacer_i2c_probe(struct platform_device *pdev) +{ + struct synquacer_i2c *i2c; + struct resource *r; + u32 bus_speed; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + bus_speed = i2c_acpi_find_bus_speed(&pdev->dev); + if (!bus_speed) + device_property_read_u32(&pdev->dev, "clock-frequency", + &bus_speed); + + device_property_read_u32(&pdev->dev, "socionext,pclk-rate", + &i2c->pclkrate); + + i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(i2c->pclk) && PTR_ERR(i2c->pclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!IS_ERR_OR_NULL(i2c->pclk)) { + dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); + + ret = clk_prepare_enable(i2c->pclk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock (%d)\n", + ret); + return ret; + } + i2c->pclkrate = clk_get_rate(i2c->pclk); + } + + if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE || + i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) { + dev_err(&pdev->dev, "PCLK missing or out of range (%d)\n", + i2c->pclkrate); + return -EINVAL; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + return -ENODEV; + } + + ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr, + 0, dev_name(&pdev->dev), i2c); + if (ret < 0) { + dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); + return ret; + } + + i2c->state = STATE_IDLE; + i2c->dev = &pdev->dev; + i2c->adapter = synquacer_i2c_ops; + i2c_set_adapdata(&i2c->adapter, i2c); + i2c->adapter.dev.parent = &pdev->dev; + i2c->adapter.nr = pdev->id; + init_completion(&i2c->completion); + + if (bus_speed < 400000) + i2c->speed_khz = SYNQUACER_I2C_SPEED_SM; + else + i2c->speed_khz = SYNQUACER_I2C_SPEED_FM; + + synquacer_i2c_hw_init(i2c); + + ret = i2c_add_numbered_adapter(&i2c->adapter); + if (ret) { + dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + return ret; + } + + platform_set_drvdata(pdev, i2c); + + dev_info(&pdev->dev, "%s: synquacer_i2c adapter\n", + dev_name(&i2c->adapter.dev)); + + return 0; +} + +static int synquacer_i2c_remove(struct platform_device *pdev) +{ + struct synquacer_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adapter); + if (!IS_ERR(i2c->pclk)) + clk_disable_unprepare(i2c->pclk); + + return 0; +}; + +static const struct of_device_id synquacer_i2c_dt_ids[] = { + { .compatible = "socionext,synquacer-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, synquacer_i2c_dt_ids); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id synquacer_i2c_acpi_ids[] = { + { "SCX0003" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, synquacer_i2c_acpi_ids); +#endif + +static struct platform_driver synquacer_i2c_driver = { + .probe = synquacer_i2c_probe, + .remove = synquacer_i2c_remove, + .driver = { + .name = "synquacer_i2c", + .of_match_table = of_match_ptr(synquacer_i2c_dt_ids), + .acpi_match_table = ACPI_PTR(synquacer_i2c_acpi_ids), + }, +}; +module_platform_driver(synquacer_i2c_driver); + +MODULE_AUTHOR("Fujitsu Semiconductor Ltd"); +MODULE_DESCRIPTION("Socionext SynQuacer I2C Driver"); +MODULE_LICENSE("GPL v2");