Merge branch 'i2c/for-current' into i2c/for-5.11
authorWolfram Sang <wsa@kernel.org>
Mon, 7 Dec 2020 06:57:42 +0000 (07:57 +0100)
committerWolfram Sang <wsa@kernel.org>
Mon, 7 Dec 2020 06:57:42 +0000 (07:57 +0100)
16 files changed:
Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt [deleted file]
Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml [new file with mode: 0644]
MAINTAINERS
drivers/i2c/busses/i2c-at91-master.c
drivers/i2c/busses/i2c-at91.h
drivers/i2c/busses/i2c-exynos5.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nvidia-gpu.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-owl.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-qcom-geni.c
drivers/soc/qcom/qcom-geni-se.c

diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt
deleted file mode 100644 (file)
index 566ea86..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Device tree configuration for the Mellanox I2C SMBus on BlueField SoCs
-
-Required Properties:
-
-- compatible : should be "mellanox,i2c-mlxbf1" or "mellanox,i2c-mlxbf2".
-
-- reg : address offset and length of the device registers. The
-       registers consist of the following set of resources:
-               1) Smbus block registers.
-               2) Cause master registers.
-               3) Cause slave registers.
-               4) Cause coalesce registers (if compatible isn't set
-                  to "mellanox,i2c-mlxbf1").
-
-- interrupts : interrupt number.
-
-Optional Properties:
-
-- clock-frequency : bus frequency used to configure timing registers;
-                       allowed values are 100000, 400000 and 1000000;
-                       those are expressed in Hz. Default is 100000.
-
-Example:
-
-i2c@2804000 {
-       compatible = "mellanox,i2c-mlxbf1";
-       reg =   <0x02804000 0x800>,
-               <0x02801200 0x020>,
-               <0x02801260 0x020>;
-       interrupts = <57>;
-       clock-frequency = <100000>;
-};
-
-i2c@2808800 {
-       compatible = "mellanox,i2c-mlxbf2";
-       reg =   <0x02808800 0x600>,
-               <0x02808e00 0x020>,
-               <0x02808e20 0x020>,
-               <0x02808e40 0x010>;
-       interrupts = <57>;
-       clock-frequency = <400000>;
-};
diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml
new file mode 100644 (file)
index 0000000..d2b401d
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/mellanox,i2c-mlxbf.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mellanox I2C SMBus on BlueField SoCs
+
+maintainers:
+  - Khalil Blaiech <kblaiech@nvidia.com>
+
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+  compatible:
+    enum:
+      - mellanox,i2c-mlxbf1
+      - mellanox,i2c-mlxbf2
+
+  reg:
+    minItems: 3
+    maxItems: 4
+    items:
+      - description: Smbus block registers
+      - description: Cause master registers
+      - description: Cause slave registers
+      - description: Cause coalesce registers
+
+  interrupts:
+    maxItems: 1
+
+  clock-frequency:
+    enum: [ 100000, 400000, 1000000 ]
+    description:
+      bus frequency used to configure timing registers;
+      The frequency is expressed in Hz. Default is 100000.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - mellanox,i2c-mlxbf1
+
+then:
+  properties:
+    reg:
+      maxItems: 3
+
+examples:
+  - |
+    i2c@2804000 {
+        compatible = "mellanox,i2c-mlxbf1";
+        reg = <0x02804000 0x800>,
+              <0x02801200 0x020>,
+              <0x02801260 0x020>;
+        interrupts = <57>;
+        clock-frequency = <100000>;
+    };
+
+  - |
+    i2c@2808800 {
+        compatible = "mellanox,i2c-mlxbf2";
+        reg = <0x02808800 0x600>,
+              <0x02808e00 0x020>,
+              <0x02808e20 0x020>,
+              <0x02808e40 0x010>;
+        interrupts = <57>;
+        clock-frequency = <400000>;
+    };
index 6f47415..1d097b9 100644 (file)
@@ -11160,6 +11160,7 @@ MELLANOX BLUEFIELD I2C DRIVER
 M:     Khalil Blaiech <kblaiech@nvidia.com>
 L:     linux-i2c@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml
 F:     drivers/i2c/busses/i2c-mlxbf.c
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
index 66864f9..1cceb68 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/dma-atmel.h>
 #include <linux/pm_runtime.h>
 
 #include "i2c-at91.h"
index eae673a..942e9c3 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/i2c.h>
-#include <linux/platform_data/dma-atmel.h>
 #include <linux/platform_device.h>
 
 #define AT91_I2C_TIMEOUT       msecs_to_jiffies(100)   /* transfer timeout */
@@ -123,7 +122,6 @@ struct at91_twi_pdata {
        bool has_adv_dig_filtr;
        bool has_ana_filtr;
        bool has_clear_cmd;
-       struct at_dma_slave dma_slave;
 };
 
 struct at91_twi_dma {
index 6ce3ec0..20a9881 100644 (file)
@@ -778,11 +778,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
        init_completion(&i2c->msg_complete);
 
        i2c->irq = ret = platform_get_irq(pdev, 0);
-       if (ret <= 0) {
-               dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
-               ret = -EINVAL;
+       if (ret < 0)
                goto err_clk;
-       }
 
        ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq,
                               IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c);
index e6f8d6e..a04d17c 100644 (file)
@@ -233,19 +233,6 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
 
 };
 
-static const struct platform_device_id imx_i2c_devtype[] = {
-       {
-               .name = "imx1-i2c",
-               .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
-       }, {
-               .name = "imx21-i2c",
-               .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
-
 static const struct of_device_id i2c_imx_dt_ids[] = {
        { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
        { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
@@ -1169,11 +1156,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        match = device_get_match_data(&pdev->dev);
-       if (match)
-               i2c_imx->hwdata = match;
-       else
-               i2c_imx->hwdata = (struct imx_i2c_hwdata *)
-                               platform_get_device_id(pdev)->driver_data;
+       i2c_imx->hwdata = match;
 
        /* Setup i2c_imx driver structure */
        strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
@@ -1344,7 +1327,6 @@ static struct platform_driver i2c_imx_driver = {
                .of_match_table = i2c_imx_dt_ids,
                .acpi_match_table = i2c_imx_acpi_ids,
        },
-       .id_table = imx_i2c_devtype,
 };
 
 static int __init i2c_adap_imx_init(void)
index a35a27c..a6187cb 100644 (file)
@@ -53,7 +53,7 @@
  *  Features supported by this driver:
  *  Hardware PEC                     yes
  *  Block buffer                     yes
- *  Block process call transaction   no
+ *  Block process call transaction   yes
  *  Slave mode                       no
  */
 
@@ -332,7 +332,8 @@ static int ismt_process_desc(const struct ismt_desc *desc,
 
        if (desc->status & ISMT_DESC_SCS) {
                if (read_write == I2C_SMBUS_WRITE &&
-                   size != I2C_SMBUS_PROC_CALL)
+                   size != I2C_SMBUS_PROC_CALL &&
+                   size != I2C_SMBUS_BLOCK_PROC_CALL)
                        return 0;
 
                switch (size) {
@@ -345,6 +346,7 @@ static int ismt_process_desc(const struct ismt_desc *desc,
                        data->word = dma_buffer[0] | (dma_buffer[1] << 8);
                        break;
                case I2C_SMBUS_BLOCK_DATA:
+               case I2C_SMBUS_BLOCK_PROC_CALL:
                        if (desc->rxbytes != dma_buffer[0] + 1)
                                return -EMSGSIZE;
 
@@ -518,6 +520,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
                }
                break;
 
+       case I2C_SMBUS_BLOCK_PROC_CALL:
+               dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n");
+               dma_size = I2C_SMBUS_BLOCK_MAX;
+               desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1);
+               desc->wr_len_cmd = data->block[0] + 1;
+               desc->rd_len = dma_size;
+               desc->control |= ISMT_DESC_BLK;
+               dma_direction = DMA_BIDIRECTIONAL;
+               dma_buffer[0] = command;
+               memcpy(&dma_buffer[1], &data->block[1], data->block[0]);
+               break;
+
        case I2C_SMBUS_I2C_BLOCK_DATA:
                /* Make sure the length is valid */
                if (data->block[0] < 1)
@@ -624,6 +638,7 @@ static u32 ismt_func(struct i2c_adapter *adap)
               I2C_FUNC_SMBUS_BYTE_DATA         |
               I2C_FUNC_SMBUS_WORD_DATA         |
               I2C_FUNC_SMBUS_PROC_CALL         |
+              I2C_FUNC_SMBUS_BLOCK_PROC_CALL   |
               I2C_FUNC_SMBUS_BLOCK_DATA        |
               I2C_FUNC_SMBUS_I2C_BLOCK         |
               I2C_FUNC_SMBUS_PEC;
index e0e45fc..5cfe70a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/mv643xx_i2c.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/reset.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -147,6 +148,7 @@ struct mv64xxx_i2c_data {
        bool                    irq_clear_inverted;
        /* Clk div is 2 to the power n, not 2 to the power n + 1 */
        bool                    clk_n_base_0;
+       struct i2c_bus_recovery_info    rinfo;
 };
 
 static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -325,7 +327,8 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
                         drv_data->msg->flags);
                drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
                mv64xxx_i2c_hw_init(drv_data);
-               drv_data->rc = -EIO;
+               i2c_recover_bus(&drv_data->adapter);
+               drv_data->rc = -EAGAIN;
        }
 }
 
@@ -561,6 +564,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
                                "time_left: %d\n", drv_data->block,
                                (int)time_left);
                        mv64xxx_i2c_hw_init(drv_data);
+                       i2c_recover_bus(&drv_data->adapter);
                }
        } else
                spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -870,6 +874,25 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
 }
 #endif /* CONFIG_OF */
 
+static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data,
+                                         struct device *dev)
+{
+       struct i2c_bus_recovery_info *rinfo = &drv_data->rinfo;
+
+       rinfo->pinctrl = devm_pinctrl_get(dev);
+       if (IS_ERR(rinfo->pinctrl)) {
+               if (PTR_ERR(rinfo->pinctrl) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               dev_info(dev, "can't get pinctrl, bus recovery not supported\n");
+               return PTR_ERR(rinfo->pinctrl);
+       } else if (!rinfo->pinctrl) {
+               return -ENODEV;
+       }
+
+       drv_data->adapter.bus_recovery_info = rinfo;
+       return 0;
+}
+
 static int
 mv64xxx_i2c_probe(struct platform_device *pd)
 {
@@ -926,6 +949,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
                goto exit_reset;
        }
 
+       rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev);
+       if (rc == -EPROBE_DEFER)
+               goto exit_reset;
+
        drv_data->adapter.dev.parent = &pd->dev;
        drv_data->adapter.algo = &mv64xxx_i2c_algo;
        drv_data->adapter.owner = THIS_MODULE;
index c4b08a9..f97243f 100644 (file)
@@ -781,28 +781,15 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
        return 0;
 }
 
-static const struct platform_device_id mxs_i2c_devtype[] = {
-       {
-               .name = "imx23-i2c",
-               .driver_data = MXS_I2C_V1,
-       }, {
-               .name = "imx28-i2c",
-               .driver_data = MXS_I2C_V2,
-       }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype);
-
 static const struct of_device_id mxs_i2c_dt_ids[] = {
-       { .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], },
-       { .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], },
+       { .compatible = "fsl,imx23-i2c", .data = (void *)MXS_I2C_V1, },
+       { .compatible = "fsl,imx28-i2c", .data = (void *)MXS_I2C_V2, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
 
 static int mxs_i2c_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *of_id =
-                               of_match_device(mxs_i2c_dt_ids, &pdev->dev);
        struct device *dev = &pdev->dev;
        struct mxs_i2c_dev *i2c;
        struct i2c_adapter *adap;
@@ -812,10 +799,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
        if (!i2c)
                return -ENOMEM;
 
-       if (of_id) {
-               const struct platform_device_id *device_id = of_id->data;
-               i2c->dev_type = device_id->driver_data;
-       }
+       i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
 
        i2c->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(i2c->regs))
index f9a69b1..6b20601 100644 (file)
@@ -353,15 +353,7 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
        pci_free_irq_vectors(pdev);
 }
 
-/*
- * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
- * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
- * Documentation/power/pci.rst also insists for driver to provide this.
- */
-static __maybe_unused int gpu_i2c_suspend(struct device *dev)
-{
-       return 0;
-}
+#define gpu_i2c_suspend NULL
 
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
index f5fc75b..273222e 100644 (file)
@@ -83,7 +83,6 @@ struct ocores_i2c {
 
 #define TYPE_OCORES            0
 #define TYPE_GRLIB             1
-#define TYPE_SIFIVE_REV0       2
 
 #define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
 
@@ -476,11 +475,9 @@ static const struct of_device_id ocores_i2c_match[] = {
        },
        {
                .compatible = "sifive,fu540-c000-i2c",
-               .data = (void *)TYPE_SIFIVE_REV0,
        },
        {
                .compatible = "sifive,i2c0",
-               .data = (void *)TYPE_SIFIVE_REV0,
        },
        {},
 };
@@ -606,7 +603,6 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
        struct ocores_i2c *i2c;
        struct ocores_i2c_platform_data *pdata;
-       const struct of_device_id *match;
        struct resource *res;
        int irq;
        int ret;
@@ -686,17 +682,20 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
        init_waitqueue_head(&i2c->wait);
 
-       irq = platform_get_irq(pdev, 0);
+       irq = platform_get_irq_optional(pdev, 0);
+       /*
+        * Since the SoC does have an interrupt, its DT has an interrupt
+        * property - But this should be bypassed as the IRQ logic in this
+        * SoC is broken.
+        */
+       if (of_device_is_compatible(pdev->dev.of_node,
+                                   "sifive,fu540-c000-i2c")) {
+               i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+               irq = -ENXIO;
+       }
+
        if (irq == -ENXIO) {
                ocores_algorithm.master_xfer = ocores_xfer_polling;
-
-               /*
-                * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
-                * FU540-C000 SoC in polling mode.
-                */
-               match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
-               if (match && (long)match->data == TYPE_SIFIVE_REV0)
-                       i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
        } else {
                if (irq < 0)
                        return irq;
index 9918b2a..5cf5a11 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 
@@ -76,6 +77,7 @@
 #define OWL_I2C_FIFOCTL_TFR    BIT(2)
 
 /* I2Cc_FIFOSTAT Bit Mask */
+#define OWL_I2C_FIFOSTAT_CECB  BIT(0)
 #define OWL_I2C_FIFOSTAT_RNB   BIT(1)
 #define OWL_I2C_FIFOSTAT_RFE   BIT(2)
 #define OWL_I2C_FIFOSTAT_TFF   BIT(5)
@@ -83,7 +85,8 @@
 #define OWL_I2C_FIFOSTAT_RFD   GENMASK(15, 8)
 
 /* I2C bus timeout */
-#define OWL_I2C_TIMEOUT                msecs_to_jiffies(4 * 1000)
+#define OWL_I2C_TIMEOUT_MS     (4 * 1000)
+#define OWL_I2C_TIMEOUT                msecs_to_jiffies(OWL_I2C_TIMEOUT_MS)
 
 #define OWL_I2C_MAX_RETRIES    50
 
@@ -161,14 +164,11 @@ static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev)
        writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
 }
 
-static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev)
 {
-       struct owl_i2c_dev *i2c_dev = _dev;
        struct i2c_msg *msg = i2c_dev->msg;
        unsigned int stat, fifostat;
 
-       spin_lock(&i2c_dev->lock);
-
        i2c_dev->err = 0;
 
        /* Handle NACK from slave */
@@ -178,7 +178,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
                /* Clear NACK error bit by writing "1" */
                owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
                                   OWL_I2C_FIFOSTAT_RNB, true);
-               goto stop;
+               return;
        }
 
        /* Handle bus error */
@@ -188,7 +188,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
                /* Clear BUS error bit by writing "1" */
                owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
                                   OWL_I2C_STAT_BEB, true);
-               goto stop;
+               return;
        }
 
        /* Handle FIFO read */
@@ -206,8 +206,16 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
                               i2c_dev->base + OWL_I2C_REG_TXDAT);
                }
        }
+}
+
+static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+{
+       struct owl_i2c_dev *i2c_dev = _dev;
+
+       spin_lock(&i2c_dev->lock);
+
+       owl_i2c_xfer_data(i2c_dev);
 
-stop:
        /* Clear pending interrupts */
        owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
                           OWL_I2C_STAT_IRQP, true);
@@ -240,8 +248,8 @@ static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
        return 0;
 }
 
-static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
-                              int num)
+static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                              int num, bool atomic)
 {
        struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
        struct i2c_msg *msg;
@@ -285,11 +293,12 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                goto err_exit;
        }
 
-       reinit_completion(&i2c_dev->msg_complete);
+       if (!atomic)
+               reinit_completion(&i2c_dev->msg_complete);
 
-       /* Enable I2C controller interrupt */
+       /* Enable/disable I2C controller interrupt */
        owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
-                          OWL_I2C_CTL_IRQE, true);
+                          OWL_I2C_CTL_IRQE, !atomic);
 
        /*
         * Select: FIFO enable, Master mode, Stop enable, Data count enable,
@@ -357,20 +366,33 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 
        spin_unlock_irqrestore(&i2c_dev->lock, flags);
 
-       time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
-                                               adap->timeout);
+       if (atomic) {
+               /* Wait for Command Execute Completed or NACK Error bits */
+               ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
+                                               val, val & (OWL_I2C_FIFOSTAT_CECB |
+                                                           OWL_I2C_FIFOSTAT_RNB),
+                                               10, OWL_I2C_TIMEOUT_MS * 1000);
+       } else {
+               time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+                                                       adap->timeout);
+               if (!time_left)
+                       ret = -ETIMEDOUT;
+       }
 
        spin_lock_irqsave(&i2c_dev->lock, flags);
-       if (time_left == 0) {
+
+       if (ret) {
                dev_err(&adap->dev, "Transaction timed out\n");
                /* Send stop condition and release the bus */
                owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
                                   OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
                                   true);
-               ret = -ETIMEDOUT;
                goto err_exit;
        }
 
+       if (atomic)
+               owl_i2c_xfer_data(i2c_dev);
+
        ret = i2c_dev->err < 0 ? i2c_dev->err : num;
 
 err_exit:
@@ -384,9 +406,22 @@ unlocked_err_exit:
        return ret;
 }
 
+static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                       int num)
+{
+       return owl_i2c_xfer_common(adap, msgs, num, false);
+}
+
+static int owl_i2c_xfer_atomic(struct i2c_adapter *adap,
+                              struct i2c_msg *msgs, int num)
+{
+       return owl_i2c_xfer_common(adap, msgs, num, true);
+}
+
 static const struct i2c_algorithm owl_i2c_algorithm = {
-       .master_xfer    = owl_i2c_master_xfer,
-       .functionality  = owl_i2c_func,
+       .master_xfer         = owl_i2c_xfer,
+       .master_xfer_atomic  = owl_i2c_xfer_atomic,
+       .functionality       = owl_i2c_func,
 };
 
 static const struct i2c_adapter_quirks owl_i2c_quirks = {
@@ -484,6 +519,7 @@ static struct platform_driver owl_i2c_driver = {
        .driver         = {
                .name   = "owl-i2c",
                .of_match_table = of_match_ptr(owl_i2c_of_match),
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
 };
 module_platform_driver(owl_i2c_driver);
index 546426a..86d4f75 100644 (file)
@@ -33,8 +33,6 @@ struct i2c_pca_pf_data {
        wait_queue_head_t               wait;
        struct i2c_adapter              adap;
        struct i2c_algo_pca_data        algo_data;
-       unsigned long                   io_base;
-       unsigned long                   io_size;
 };
 
 /* Read/Write functions for different register alignments */
@@ -156,8 +154,6 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
 
        init_waitqueue_head(&i2c->wait);
 
-       i2c->io_base = res->start;
-       i2c->io_size = resource_size(res);
        i2c->irq = irq;
 
        i2c->adap.nr = pdev->id;
index 8b4c35f..046d241 100644 (file)
@@ -353,19 +353,18 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 {
        dma_addr_t rx_dma;
        unsigned long time_left;
-       void *dma_buf = NULL;
+       void *dma_buf;
        struct geni_se *se = &gi2c->se;
        size_t len = msg->len;
 
-       if (!of_machine_is_compatible("lenovo,yoga-c630"))
-               dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
-
+       dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
        if (dma_buf)
                geni_se_select_mode(se, GENI_SE_DMA);
        else
                geni_se_select_mode(se, GENI_SE_FIFO);
 
        writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
+       geni_se_setup_m_cmd(se, I2C_READ, m_param);
 
        if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
                geni_se_select_mode(se, GENI_SE_FIFO);
@@ -373,8 +372,6 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
                dma_buf = NULL;
        }
 
-       geni_se_setup_m_cmd(se, I2C_READ, m_param);
-
        time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
        if (!time_left)
                geni_i2c_abort_xfer(gi2c);
@@ -395,19 +392,18 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 {
        dma_addr_t tx_dma;
        unsigned long time_left;
-       void *dma_buf = NULL;
+       void *dma_buf;
        struct geni_se *se = &gi2c->se;
        size_t len = msg->len;
 
-       if (!of_machine_is_compatible("lenovo,yoga-c630"))
-               dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
-
+       dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
        if (dma_buf)
                geni_se_select_mode(se, GENI_SE_DMA);
        else
                geni_se_select_mode(se, GENI_SE_FIFO);
 
        writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
+       geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
 
        if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
                geni_se_select_mode(se, GENI_SE_FIFO);
@@ -415,8 +411,6 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
                dma_buf = NULL;
        }
 
-       geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
-
        if (!dma_buf) /* Get FIFO IRQ */
                writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
 
index d0e4f52..7649b20 100644 (file)
@@ -266,36 +266,63 @@ EXPORT_SYMBOL(geni_se_init);
 static void geni_se_select_fifo_mode(struct geni_se *se)
 {
        u32 proto = geni_se_read_proto(se);
-       u32 val;
+       u32 val, val_old;
 
        geni_se_irq_clear(se);
 
-       val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
+       /*
+        * The RX path for the UART is asynchronous and so needs more
+        * complex logic for enabling / disabling its interrupts.
+        *
+        * Specific notes:
+        * - The done and TX-related interrupts are managed manually.
+        * - We don't RX from the main sequencer (we use the secondary) so
+        *   we don't need the RX-related interrupts enabled in the main
+        *   sequencer for UART.
+        */
        if (proto != GENI_SE_UART) {
+               val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
                val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
                val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
-       }
-       writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
+               if (val != val_old)
+                       writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
 
-       val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
-       if (proto != GENI_SE_UART)
+               val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
                val |= S_CMD_DONE_EN;
-       writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
+               if (val != val_old)
+                       writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
+       }
 
-       val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
+       val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
        val &= ~GENI_DMA_MODE_EN;
-       writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
+       if (val != val_old)
+               writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
 }
 
 static void geni_se_select_dma_mode(struct geni_se *se)
 {
-       u32 val;
+       u32 proto = geni_se_read_proto(se);
+       u32 val, val_old;
 
        geni_se_irq_clear(se);
 
-       val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
+       if (proto != GENI_SE_UART) {
+               val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
+               val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
+               val &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+               if (val != val_old)
+                       writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
+
+               val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
+               val &= ~S_CMD_DONE_EN;
+               if (val != val_old)
+                       writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
+       }
+
+       val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
        val |= GENI_DMA_MODE_EN;
-       writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
+       if (val != val_old)
+               writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
 }
 
 /**
@@ -651,7 +678,7 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
        writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
        writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
        writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
-       writel_relaxed(len, se->base + SE_DMA_TX_LEN);
+       writel(len, se->base + SE_DMA_TX_LEN);
        return 0;
 }
 EXPORT_SYMBOL(geni_se_tx_dma_prep);
@@ -688,7 +715,7 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
        writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
        /* RX does not have EOT buffer type bit. So just reset RX_ATTR */
        writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
-       writel_relaxed(len, se->base + SE_DMA_RX_LEN);
+       writel(len, se->base + SE_DMA_RX_LEN);
        return 0;
 }
 EXPORT_SYMBOL(geni_se_rx_dma_prep);