Merge tag 'i2c-for-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Aug 2022 02:23:51 +0000 (19:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Aug 2022 02:23:51 +0000 (19:23 -0700)
Pull i2c updates from Wolfram Sang:

 - new drivers: Microchip CoreI2C, Renesas RZV2M

 - quite some DT schema conversions and extensions

 - and a bunch of driver updates and improvements

* tag 'i2c-for-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (37 commits)
  i2c: extend documentation about retvals of master_xfer functions
  i2c: mux-gpmux: Add of_node_put() when breaking out of loop
  dt-bindings: i2c: i2c-rk3x: Document Rockchip RV1126
  i2c: qcom-geni: Use the correct return value
  i2c: cadence: Support PEC for SMBus block read
  i2c: qcom-geni: Propagate GENI_ABORT_DONE to geni_i2c_abort_xfer()
  i2c: brcmstb: Use dev_name() for adapter name
  i2c: Add Renesas RZ/V2M controller
  dt-bindings: i2c: Document RZ/V2M I2C controller
  i2c: mlxcpld: Add callback to notify probing completion
  i2c: scmi: Replace open coded device_get_match_data()
  i2c: stm32: add support for the STM32MP13 soc
  dt-bindings: i2c: st,stm32-i2c: add entry for stm32mp13
  dt-bindings: i2c: i2c-rk3x: add rk3588 compatible
  i2c: add support for microchip fpga i2c controllers
  i2c: i801: Add support for Intel Meteor Lake-P
  dt-bindings: i2c: nomadik: Add power domain to binding
  dt-bindings: i2c: nomadik: Drop unused voltage supply from example
  i2c: Fix a potential use after free
  i2c: hisi: use HZ_PER_KHZ macro in units.h
  ...

33 files changed:
Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-nomadik.txt [deleted file]
Documentation/devicetree/bindings/i2c/i2c-ocores.txt [deleted file]
Documentation/devicetree/bindings/i2c/i2c-qcom-cci.txt
Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
Documentation/devicetree/bindings/i2c/i2c-versatile.txt [deleted file]
Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.yaml
Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml
Documentation/i2c/busses/i2c-i801.rst
MAINTAINERS
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-brcmstb.c
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-hisi.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-microchip-corei2c.c [new file with mode: 0644]
drivers/i2c/busses/i2c-mlxcpld.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-npcm7xx.c
drivers/i2c/busses/i2c-qcom-cci.c
drivers/i2c/busses/i2c-qcom-geni.c
drivers/i2c/busses/i2c-rzv2m.c [new file with mode: 0644]
drivers/i2c/busses/i2c-scmi.c
drivers/i2c/busses/i2c-stm32f7.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/i2c-core-base.c
drivers/i2c/muxes/i2c-mux-gpmux.c
include/linux/i2c.h

diff --git a/Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml b/Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml
new file mode 100644 (file)
index 0000000..e58465d
--- /dev/null
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/arm,i2c-versatile.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: I2C Controller on ARM Ltd development platforms
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+  compatible:
+    const: arm,versatile-i2c
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+...
+
diff --git a/Documentation/devicetree/bindings/i2c/i2c-nomadik.txt b/Documentation/devicetree/bindings/i2c/i2c-nomadik.txt
deleted file mode 100644 (file)
index 72065b0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-I2C for Nomadik based systems
-
-Required (non-standard) properties:
- - Nil
-
-Recommended (non-standard) properties:
- - clock-frequency : Maximum bus clock frequency for the device
-
-Optional (non-standard) properties:
- - Nil
-
-Example :
-
-i2c@80004000 {
-        compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
-        reg = <0x80004000 0x1000>;
-        interrupts = <0 21 0x4>;
-        #address-cells = <1>;
-        #size-cells = <0>;
-        v-i2c-supply = <&db8500_vape_reg>;
-
-        clock-frequency = <400000>;
-};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
deleted file mode 100644 (file)
index a37c945..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-Device tree configuration for i2c-ocores
-
-Required properties:
-- compatible      : "opencores,i2c-ocores"
-                    "aeroflexgaisler,i2cmst"
-                    "sifive,fu540-c000-i2c", "sifive,i2c0"
-                    For Opencore based I2C IP block reimplemented in
-                    FU540-C000 SoC.
-                    "sifive,fu740-c000-i2c", "sifive,i2c0"
-                    For Opencore based I2C IP block reimplemented in
-                    FU740-C000 SoC.
-                    Please refer to sifive-blocks-ip-versioning.txt for
-                    additional details.
-- reg             : bus address start and address range size of device
-- clocks          : handle to the controller clock; see the note below.
-                    Mutually exclusive with opencores,ip-clock-frequency
-- opencores,ip-clock-frequency: frequency of the controller clock in Hz;
-                    see the note below. Mutually exclusive with clocks
-- #address-cells  : should be <1>
-- #size-cells     : should be <0>
-
-Optional properties:
-- interrupts      : interrupt number.
-- clock-frequency : frequency of bus clock in Hz; see the note below.
-                    Defaults to 100 KHz when the property is not specified
-- reg-shift       : device register offsets are shifted by this value
-- reg-io-width    : io register width in bytes (1, 2 or 4)
-- regstep         : deprecated, use reg-shift above
-
-Note
-clock-frequency property is meant to control the bus frequency for i2c bus
-drivers, but it was incorrectly used to specify i2c controller input clock
-frequency. So the following rules are set to fix this situation:
-- if clock-frequency is present and neither opencores,ip-clock-frequency nor
-  clocks are, then clock-frequency specifies i2c controller clock frequency.
-  This is to keep backwards compatibility with setups using old DTB. i2c bus
-  frequency is fixed at 100 KHz.
-- if clocks is present it specifies i2c controller clock. clock-frequency
-  property specifies i2c bus frequency.
-- if opencores,ip-clock-frequency is present it specifies i2c controller
-  clock frequency. clock-frequency property specifies i2c bus frequency.
-
-Examples:
-
-       i2c0: ocores@a0000000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "opencores,i2c-ocores";
-               reg = <0xa0000000 0x8>;
-               interrupts = <10>;
-               opencores,ip-clock-frequency = <20000000>;
-
-               reg-shift = <0>;        /* 8 bit registers */
-               reg-io-width = <1>;     /* 8 bit read/write */
-
-               dummy@60 {
-                       compatible = "dummy";
-                       reg = <0x60>;
-               };
-       };
-or
-       i2c0: ocores@a0000000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "opencores,i2c-ocores";
-               reg = <0xa0000000 0x8>;
-               interrupts = <10>;
-               clocks = <&osc>;
-               clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
-
-               reg-shift = <0>;        /* 8 bit registers */
-               reg-io-width = <1>;     /* 8 bit read/write */
-
-               dummy@60 {
-                       compatible = "dummy";
-                       reg = <0x60>;
-               };
-       };
index 924ad8c..166865e 100644 (file)
@@ -7,6 +7,7 @@ PROPERTIES:
        Value type: <string>
        Definition: must be one of:
                "qcom,msm8916-cci"
+               "qcom,msm8974-cci"
                "qcom,msm8996-cci"
                "qcom,sdm845-cci"
                "qcom,sm8250-cci"
@@ -43,9 +44,9 @@ PROPERTIES:
 
 SUBNODES:
 
-The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8996,
-sdm845, sm8250 and sm8450), described as subdevices named "i2c-bus@0" and
-"i2c-bus@1".
+The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8974,
+msm8996, sdm845, sm8250 and sm8450), described as subdevices named "i2c-bus@0"
+and "i2c-bus@1".
 
 PROPERTIES:
 
index 5339dd4..ee9f8b9 100644 (file)
@@ -37,6 +37,8 @@ properties:
               - rockchip,rk3308-i2c
               - rockchip,rk3328-i2c
               - rockchip,rk3568-i2c
+              - rockchip,rk3588-i2c
+              - rockchip,rv1126-i2c
           - const: rockchip,rk3399-i2c
 
   reg:
diff --git a/Documentation/devicetree/bindings/i2c/i2c-versatile.txt b/Documentation/devicetree/bindings/i2c/i2c-versatile.txt
deleted file mode 100644 (file)
index 361d31c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-i2c Controller on ARM Versatile platform:
-
-Required properties:
-- compatible : Must be "arm,versatile-i2c";
-- reg
-- #address-cells = <1>;
-- #size-cells = <0>;
-
-Optional properties:
-- Child nodes conforming to i2c bus binding
index 1284449..09d2591 100644 (file)
@@ -7,17 +7,18 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: nuvoton NPCM7XX I2C Controller Device Tree Bindings
 
 description: |
-  The NPCM750x includes sixteen I2C bus controllers. All Controllers support
-  both master and slave mode. Each controller can switch between master and slave
-  at run time (i.e. IPMB mode). Each controller has two 16 byte HW FIFO for TX and
-  RX.
+  I2C bus controllers of the NPCM series support both master and
+  slave mode. Each controller can switch between master and slave at run time
+  (i.e. IPMB mode). HW FIFO for TX and RX are supported.
 
 maintainers:
   - Tali Perry <tali.perry1@gmail.com>
 
 properties:
   compatible:
-    const: nuvoton,npcm750-i2c
+    enum:
+      - nuvoton,npcm750-i2c
+      - nuvoton,npcm845-i2c
 
   reg:
     maxItems: 1
@@ -36,6 +37,10 @@ properties:
     default: 100000
     enum: [100000, 400000, 1000000]
 
+  nuvoton,sys-mgr:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of system manager register node.
+
 required:
   - compatible
   - reg
@@ -44,6 +49,15 @@ required:
 
 allOf:
   - $ref: /schemas/i2c/i2c-controller.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nuvoton,npcm845-i2c
+
+    then:
+      required:
+        - nuvoton,sys-mgr
 
 unevaluatedProperties: false
 
@@ -57,6 +71,7 @@ examples:
         clock-frequency = <100000>;
         interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
         compatible = "nuvoton,npcm750-i2c";
+        nuvoton,sys-mgr = <&gcr>;
     };
 
 ...
diff --git a/Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml b/Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml
new file mode 100644 (file)
index 0000000..85d9efb
--- /dev/null
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/opencores,i2c-ocores.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OpenCores I2C controller
+
+maintainers:
+  - Peter Korsgaard <peter@korsgaard.com>
+  - Andrew Lunn <andrew@lunn.ch>
+
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - sifive,fu740-c000-i2c # Opencore based IP block FU740-C000 SoC
+              - sifive,fu540-c000-i2c # Opencore based IP block FU540-C000 SoC
+          - const: sifive,i2c0
+      - enum:
+          - opencores,i2c-ocores
+          - aeroflexgaisler,i2cmst
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-frequency:
+    description: |
+      clock-frequency property is meant to control the bus frequency for i2c bus
+      drivers, but it was incorrectly used to specify i2c controller input clock
+      frequency. So the following rules are set to fix this situation:
+      - if clock-frequency is present and neither opencores,ip-clock-frequency nor
+        clocks are, then clock-frequency specifies i2c controller clock frequency.
+        This is to keep backwards compatibility with setups using old DTB. i2c bus
+        frequency is fixed at 100 KHz.
+      - if clocks is present it specifies i2c controller clock. clock-frequency
+        property specifies i2c bus frequency.
+      - if opencores,ip-clock-frequency is present it specifies i2c controller
+        clock frequency. clock-frequency property specifies i2c bus frequency.
+    default: 100000
+
+  reg-io-width:
+    description: |
+      io register width in bytes
+    enum: [1, 2, 4]
+
+  reg-shift:
+    description: |
+      device register offsets are shifted by this value
+    default: 0
+
+  regstep:
+    description: |
+      deprecated, use reg-shift above
+    deprecated: true
+
+  opencores,ip-clock-frequency:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Frequency of the controller clock in Hz. Mutually exclusive with clocks.
+      See the note above.
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+oneOf:
+  - required:
+      - opencores,ip-clock-frequency
+  - required:
+      - clocks
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c@a0000000 {
+      compatible = "opencores,i2c-ocores";
+      reg = <0xa0000000 0x8>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      interrupts = <10>;
+      opencores,ip-clock-frequency = <20000000>;
+
+      reg-shift = <0>; /* 8 bit registers */
+      reg-io-width = <1>;      /* 8 bit read/write */
+    };
+
+    i2c@b0000000 {
+      compatible = "opencores,i2c-ocores";
+      reg = <0xa0000000 0x8>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      interrupts = <10>;
+      clocks = <&osc>;
+      clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
+
+      reg-shift = <0>; /* 8 bit registers */
+      reg-io-width = <1>;      /* 8 bit read/write */
+    };
+...
diff --git a/Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml b/Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
new file mode 100644 (file)
index 0000000..c46378e
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/renesas,rzv2m.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/V2M I2C Bus Interface
+
+maintainers:
+  - Phil Edworthy <phil.edworthy@renesas.com>
+
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,i2c-r9a09g011  # RZ/V2M
+      - const: renesas,rzv2m-i2c
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: Data transmission/reception interrupt
+      - description: Status interrupt
+
+  interrupt-names:
+    items:
+      - const: tia
+      - const: tis
+
+  clock-frequency:
+    default: 100000
+    enum: [ 100000, 400000 ]
+    description:
+      Desired I2C bus clock frequency in Hz.
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - power-domains
+  - resets
+  - '#address-cells'
+  - '#size-cells'
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r9a09g011-cpg.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    i2c0: i2c@a4030000 {
+        compatible = "renesas,i2c-r9a09g011", "renesas,rzv2m-i2c";
+        reg = <0xa4030000 0x80>;
+        interrupts = <GIC_SPI 232 IRQ_TYPE_EDGE_RISING>,
+                     <GIC_SPI 236 IRQ_TYPE_EDGE_RISING>;
+        interrupt-names = "tia", "tis";
+        clocks = <&cpg CPG_MOD R9A09G011_IIC_PCLK0>;
+        resets = <&cpg R9A09G011_IIC_GPA_PRESETN>;
+        power-domains = <&cpg>;
+        clock-frequency = <100000>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
new file mode 100644 (file)
index 0000000..42c5974
--- /dev/null
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/st,nomadik-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ST Microelectronics Nomadik I2C Bindings
+
+description: The Nomadik I2C host controller began its life in the ST
+  Microelectronics STn8800 SoC, and was then inherited into STn8810 and
+  STn8815. It was part of the prototype STn8500 which then became ST-Ericsson
+  DB8500 after the merge of these two companies wireless divisions.
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+
+# Need a custom select here or 'arm,primecell' will match on lots of nodes
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - st,nomadik-i2c
+  required:
+    - compatible
+
+properties:
+  compatible:
+    oneOf:
+      # The variant found in STn8815
+      - items:
+          - const: st,nomadik-i2c
+          - const: arm,primecell
+      # The variant found in DB8500
+      - items:
+          - const: stericsson,db8500-i2c
+          - const: st,nomadik-i2c
+          - const: arm,primecell
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    oneOf:
+      # Clock name in STn8815
+      - items:
+          - const: mclk
+          - const: apb_pclk
+      # Clock name in DB8500
+      - items:
+          - const: i2cclk
+          - const: apb_pclk
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  clock-frequency:
+    minimum: 1
+    maximum: 400000
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/reset/stericsson,db8500-prcc-reset.h>
+    #include <dt-bindings/arm/ux500_pm_domains.h>
+    i2c@80004000 {
+      compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
+      reg = <0x80004000 0x1000>;
+      interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      clock-frequency = <400000>;
+      clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>;
+      clock-names = "i2cclk", "apb_pclk";
+      power-domains = <&pm_domains DOMAIN_VAPE>;
+      resets = <&prcc_reset DB8500_PRCC_3 DB8500_PRCC_3_RESET_I2C0>;
+    };
+
+    i2c@101f8000 {
+      compatible = "st,nomadik-i2c", "arm,primecell";
+      reg = <0x101f8000 0x1000>;
+      interrupt-parent = <&vica>;
+      interrupts = <20>;
+      clock-frequency = <100000>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      clocks = <&i2c0clk>, <&pclki2c0>;
+      clock-names = "mclk", "apb_pclk";
+    };
+
+...
index dccbb18..a415887 100644 (file)
@@ -17,6 +17,7 @@ allOf:
           contains:
             enum:
               - st,stm32f7-i2c
+              - st,stm32mp13-i2c
               - st,stm32mp15-i2c
     then:
       properties:
@@ -45,6 +46,7 @@ properties:
     enum:
       - st,stm32f4-i2c
       - st,stm32f7-i2c
+      - st,stm32mp13-i2c
       - st,stm32mp15-i2c
 
   reg:
index cad5917..ab9e850 100644 (file)
@@ -46,6 +46,7 @@ Supported adapters:
   * Intel Emmitsburg (PCH)
   * Intel Alder Lake (PCH)
   * Intel Raptor Lake (PCH)
+  * Intel Meteor Lake (SOC)
 
    Datasheets: Publicly available at the Intel website
 
index 56ab4aa..17273f0 100644 (file)
@@ -1525,7 +1525,7 @@ F:        Documentation/devicetree/bindings/arm/arm,versatile.yaml
 F:     Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
 F:     Documentation/devicetree/bindings/auxdisplay/arm,versatile-lcd.yaml
 F:     Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml
-F:     Documentation/devicetree/bindings/i2c/i2c-versatile.txt
+F:     Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml
 F:     Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt
 F:     Documentation/devicetree/bindings/mtd/mtd-physmap.yaml
 F:     arch/arm/boot/dts/arm-realview-*
@@ -2424,7 +2424,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
 F:     Documentation/devicetree/bindings/arm/ste-*
 F:     Documentation/devicetree/bindings/arm/ux500.yaml
 F:     Documentation/devicetree/bindings/arm/ux500/
-F:     Documentation/devicetree/bindings/i2c/i2c-nomadik.txt
+F:     Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
 F:     arch/arm/boot/dts/ste-*
 F:     arch/arm/mach-nomadik/
 F:     arch/arm/mach-ux500/
@@ -15075,7 +15075,7 @@ M:      Peter Korsgaard <peter@korsgaard.com>
 M:     Andrew Lunn <andrew@lunn.ch>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+F:     Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml
 F:     Documentation/i2c/busses/i2c-ocores.rst
 F:     drivers/i2c/busses/i2c-ocores.c
 F:     include/linux/platform_data/i2c-ocores.h
index 708a67c..e95d6bc 100644 (file)
@@ -156,6 +156,7 @@ config I2C_I801
            Emmitsburg (PCH)
            Alder Lake (PCH)
            Raptor Lake (PCH)
+           Meteor Lake (SOC)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -781,6 +782,17 @@ config I2C_MESON
          If you say yes to this option, support will be included for the
          I2C interface on the Amlogic Meson family of SoCs.
 
+config I2C_MICROCHIP_CORE
+       tristate "Microchip FPGA I2C controller"
+       depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST
+       depends on OF
+       help
+         If you say yes to this option, support will be included for the
+         I2C interface on Microchip FPGAs.
+
+         This driver can also be built as a module. If so, the module will be
+         called i2c-microchip-core.
+
 config I2C_MPC
        tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
        depends on PPC
@@ -838,13 +850,13 @@ config I2C_NOMADIK
          I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
          as well as the STA2X11 PCIe I/O HUB.
 
-config I2C_NPCM7XX
+config I2C_NPCM
        tristate "Nuvoton I2C Controller"
-       depends on ARCH_NPCM7XX || COMPILE_TEST
+       depends on ARCH_NPCM || COMPILE_TEST
        help
          If you say yes to this option, support will be included for the
-         Nuvoton I2C controller, which is available on the NPCM7xx BMC
-         controller.
+         Nuvoton I2C controller, which is available on the NPCM BMC
+         controllers.
          Driver can also support slave mode (select I2C_SLAVE).
 
 config I2C_OCORES
@@ -984,6 +996,16 @@ config I2C_RK3X
          This driver can also be built as a module. If so, the module will
          be called i2c-rk3x.
 
+config I2C_RZV2M
+       tristate "Renesas RZ/V2M adapter"
+       depends on ARCH_RENESAS || COMPILE_TEST
+       help
+         If you say yes to this option, support will be included for the
+         Renesas RZ/V2M  I2C interface.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-rzv2m.
+
 config I2C_S3C2410
        tristate "S3C/Exynos I2C Driver"
        depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || \
index 479f60e..c5cac15 100644 (file)
@@ -78,13 +78,14 @@ obj-$(CONFIG_I2C_JZ4780)    += i2c-jz4780.o
 obj-$(CONFIG_I2C_KEMPLD)       += i2c-kempld.o
 obj-$(CONFIG_I2C_LPC2K)                += i2c-lpc2k.o
 obj-$(CONFIG_I2C_MESON)                += i2c-meson.o
+obj-$(CONFIG_I2C_MICROCHIP_CORE)       += i2c-microchip-corei2c.o
 obj-$(CONFIG_I2C_MPC)          += i2c-mpc.o
 obj-$(CONFIG_I2C_MT65XX)       += i2c-mt65xx.o
 obj-$(CONFIG_I2C_MT7621)       += i2c-mt7621.o
 obj-$(CONFIG_I2C_MV64XXX)      += i2c-mv64xxx.o
 obj-$(CONFIG_I2C_MXS)          += i2c-mxs.o
 obj-$(CONFIG_I2C_NOMADIK)      += i2c-nomadik.o
-obj-$(CONFIG_I2C_NPCM7XX)      += i2c-npcm7xx.o
+obj-$(CONFIG_I2C_NPCM)         += i2c-npcm7xx.o
 obj-$(CONFIG_I2C_OCORES)       += i2c-ocores.o
 obj-$(CONFIG_I2C_OMAP)         += i2c-omap.o
 obj-$(CONFIG_I2C_OWL)          += i2c-owl.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
 obj-$(CONFIG_I2C_QUP)          += i2c-qup.o
 obj-$(CONFIG_I2C_RIIC)         += i2c-riic.o
 obj-$(CONFIG_I2C_RK3X)         += i2c-rk3x.o
+obj-$(CONFIG_I2C_RZV2M)                += i2c-rzv2m.o
 obj-$(CONFIG_I2C_S3C2410)      += i2c-s3c2410.o
 obj-$(CONFIG_I2C_SH7760)       += i2c-sh7760.o
 obj-$(CONFIG_I2C_SH_MOBILE)    += i2c-sh_mobile.o
index b00f35c..3ba6cbb 100644 (file)
@@ -684,9 +684,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
-       strlcpy(adap->name, "Broadcom STB : ", sizeof(adap->name));
-       if (int_name)
-               strlcat(adap->name, int_name, sizeof(adap->name));
+       strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
        adap->algo = &brcmstb_i2c_algo;
        adap->dev.parent = &pdev->dev;
        adap->dev.of_node = pdev->dev.of_node;
index 630cfa4..33f5588 100644 (file)
@@ -573,8 +573,13 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
        ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
        ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
 
+       /*
+        * Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length
+        * byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if
+        * PEC is enabled, otherwise 1.
+        */
        if (id->p_msg->flags & I2C_M_RECV_LEN)
-               id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+               id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len;
 
        id->curr_recv_count = id->recv_count;
 
@@ -789,6 +794,9 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
        if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
                return -EAGAIN;
 
+       if (msg->flags & I2C_M_RECV_LEN)
+               msg->len += min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX);
+
        return 0;
 }
 
index acf3948..76c3d8f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
+#include <linux/units.h>
 
 #define HISI_I2C_FRAME_CTRL            0x0000
 #define   HISI_I2C_FRAME_CTRL_SPEED_MODE       GENMASK(1, 0)
@@ -80,8 +81,6 @@
 #define HISI_I2C_TX_F_AE_THRESH                1
 #define HISI_I2C_RX_F_AF_THRESH                60
 
-#define HZ_PER_KHZ     1000
-
 #define NSEC_TO_CYCLES(ns, clk_rate_khz) \
        DIV_ROUND_UP_ULL((clk_rate_khz) * (ns), NSEC_PER_MSEC)
 
index ff70634..9e5b87e 100644 (file)
@@ -76,6 +76,7 @@
  * Alder Lake-P (PCH)          0x51a3  32      hard    yes     yes     yes
  * Alder Lake-M (PCH)          0x54a3  32      hard    yes     yes     yes
  * Raptor Lake-S (PCH)         0x7a23  32      hard    yes     yes     yes
+ * Meteor Lake-P (SOC)         0x7e22  32      hard    yes     yes     yes
  *
  * Features supported by this driver:
  * Software PEC                                no
 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS              0x5ad4
 #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS                0x7a23
 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS         0x7aa3
+#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_P_SMBUS                0x7e22
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS            0x8c22
 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS         0x8ca2
 #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS            0x8d22
@@ -1049,6 +1051,7 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_P_SMBUS,    FEATURES_ICH5 | FEATURE_TCO_CNL) },
        { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_M_SMBUS,    FEATURES_ICH5 | FEATURE_TCO_CNL) },
        { PCI_DEVICE_DATA(INTEL, RAPTOR_LAKE_S_SMBUS,   FEATURES_ICH5 | FEATURE_TCO_CNL) },
+       { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS,   FEATURES_ICH5 | FEATURE_TCO_CNL) },
        { 0, }
 };
 
diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c
new file mode 100644 (file)
index 0000000..6df0f1c
--- /dev/null
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip CoreI2C I2C controller driver
+ *
+ * Copyright (c) 2018-2022 Microchip Corporation. All rights reserved.
+ *
+ * Author: Daire McNamara <daire.mcnamara@microchip.com>
+ * Author: Conor Dooley <conor.dooley@microchip.com>
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define CORE_I2C_CTRL  (0x00)
+#define  CTRL_CR0      BIT(0)
+#define  CTRL_CR1      BIT(1)
+#define  CTRL_AA       BIT(2)
+#define  CTRL_SI       BIT(3)
+#define  CTRL_STO      BIT(4)
+#define  CTRL_STA      BIT(5)
+#define  CTRL_ENS1     BIT(6)
+#define  CTRL_CR2      BIT(7)
+
+#define STATUS_BUS_ERROR                       (0x00)
+#define STATUS_M_START_SENT                    (0x08)
+#define STATUS_M_REPEATED_START_SENT           (0x10)
+#define STATUS_M_SLAW_ACK                      (0x18)
+#define STATUS_M_SLAW_NACK                     (0x20)
+#define STATUS_M_TX_DATA_ACK                   (0x28)
+#define STATUS_M_TX_DATA_NACK                  (0x30)
+#define STATUS_M_ARB_LOST                      (0x38)
+#define STATUS_M_SLAR_ACK                      (0x40)
+#define STATUS_M_SLAR_NACK                     (0x48)
+#define STATUS_M_RX_DATA_ACKED                 (0x50)
+#define STATUS_M_RX_DATA_NACKED                        (0x58)
+#define STATUS_S_SLAW_ACKED                    (0x60)
+#define STATUS_S_ARB_LOST_SLAW_ACKED           (0x68)
+#define STATUS_S_GENERAL_CALL_ACKED            (0x70)
+#define STATUS_S_ARB_LOST_GENERAL_CALL_ACKED   (0x78)
+#define STATUS_S_RX_DATA_ACKED                 (0x80)
+#define STATUS_S_RX_DATA_NACKED                        (0x88)
+#define STATUS_S_GENERAL_CALL_RX_DATA_ACKED    (0x90)
+#define STATUS_S_GENERAL_CALL_RX_DATA_NACKED   (0x98)
+#define STATUS_S_RX_STOP                       (0xA0)
+#define STATUS_S_SLAR_ACKED                    (0xA8)
+#define STATUS_S_ARB_LOST_SLAR_ACKED           (0xB0)
+#define STATUS_S_TX_DATA_ACK                   (0xB8)
+#define STATUS_S_TX_DATA_NACK                  (0xC0)
+#define STATUS_LAST_DATA_ACK                   (0xC8)
+#define STATUS_M_SMB_MASTER_RESET              (0xD0)
+#define STATUS_S_SCL_LOW_TIMEOUT               (0xD8) /* 25 ms */
+#define STATUS_NO_STATE_INFO                   (0xF8)
+
+#define CORE_I2C_STATUS                (0x04)
+#define CORE_I2C_DATA          (0x08)
+#define WRITE_BIT              (0x0)
+#define READ_BIT               (0x1)
+#define SLAVE_ADDR_SHIFT       (1)
+#define CORE_I2C_SLAVE0_ADDR   (0x0c)
+#define GENERAL_CALL_BIT       (0x0)
+#define CORE_I2C_SMBUS         (0x10)
+#define SMBALERT_INT_ENB       (0x0)
+#define SMBSUS_INT_ENB         (0x1)
+#define SMBUS_ENB              (0x2)
+#define SMBALERT_NI_STATUS     (0x3)
+#define SMBALERT_NO_CTRL       (0x4)
+#define SMBSUS_NI_STATUS       (0x5)
+#define SMBSUS_NO_CTRL         (0x6)
+#define SMBUS_RESET            (0x7)
+#define CORE_I2C_FREQ          (0x14)
+#define CORE_I2C_GLITCHREG     (0x18)
+#define CORE_I2C_SLAVE1_ADDR   (0x1c)
+
+#define PCLK_DIV_960   (CTRL_CR2)
+#define PCLK_DIV_256   (0)
+#define PCLK_DIV_224   (CTRL_CR0)
+#define PCLK_DIV_192   (CTRL_CR1)
+#define PCLK_DIV_160   (CTRL_CR0 | CTRL_CR1)
+#define PCLK_DIV_120   (CTRL_CR0 | CTRL_CR2)
+#define PCLK_DIV_60    (CTRL_CR1 | CTRL_CR2)
+#define BCLK_DIV_8     (CTRL_CR0 | CTRL_CR1 | CTRL_CR2)
+#define CLK_MASK       (CTRL_CR0 | CTRL_CR1 | CTRL_CR2)
+
+/**
+ * struct mchp_corei2c_dev - Microchip CoreI2C device private data
+ *
+ * @base:              pointer to register struct
+ * @dev:               device reference
+ * @i2c_clk:           clock reference for i2c input clock
+ * @buf:               pointer to msg buffer for easier use
+ * @msg_complete:      xfer completion object
+ * @adapter:           core i2c abstraction
+ * @msg_err:           error code for completed message
+ * @bus_clk_rate:      current i2c bus clock rate
+ * @isr_status:                cached copy of local ISR status
+ * @msg_len:           number of bytes transferred in msg
+ * @addr:              address of the current slave
+ */
+struct mchp_corei2c_dev {
+       void __iomem *base;
+       struct device *dev;
+       struct clk *i2c_clk;
+       u8 *buf;
+       struct completion msg_complete;
+       struct i2c_adapter adapter;
+       int msg_err;
+       u32 bus_clk_rate;
+       u32 isr_status;
+       u16 msg_len;
+       u8 addr;
+};
+
+static void mchp_corei2c_core_disable(struct mchp_corei2c_dev *idev)
+{
+       u8 ctrl = readb(idev->base + CORE_I2C_CTRL);
+
+       ctrl &= ~CTRL_ENS1;
+       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+}
+
+static void mchp_corei2c_core_enable(struct mchp_corei2c_dev *idev)
+{
+       u8 ctrl = readb(idev->base + CORE_I2C_CTRL);
+
+       ctrl |= CTRL_ENS1;
+       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+}
+
+static void mchp_corei2c_reset(struct mchp_corei2c_dev *idev)
+{
+       mchp_corei2c_core_disable(idev);
+       mchp_corei2c_core_enable(idev);
+}
+
+static inline void mchp_corei2c_stop(struct mchp_corei2c_dev *idev)
+{
+       u8 ctrl = readb(idev->base + CORE_I2C_CTRL);
+
+       ctrl |= CTRL_STO;
+       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+}
+
+static inline int mchp_corei2c_set_divisor(u32 rate,
+                                          struct mchp_corei2c_dev *idev)
+{
+       u8 clkval, ctrl;
+
+       if (rate >= 960)
+               clkval = PCLK_DIV_960;
+       else if (rate >= 256)
+               clkval = PCLK_DIV_256;
+       else if (rate >= 224)
+               clkval = PCLK_DIV_224;
+       else if (rate >= 192)
+               clkval = PCLK_DIV_192;
+       else if (rate >= 160)
+               clkval = PCLK_DIV_160;
+       else if (rate >= 120)
+               clkval = PCLK_DIV_120;
+       else if (rate >= 60)
+               clkval = PCLK_DIV_60;
+       else if (rate >= 8)
+               clkval = BCLK_DIV_8;
+       else
+               return -EINVAL;
+
+       ctrl = readb(idev->base + CORE_I2C_CTRL);
+       ctrl &= ~CLK_MASK;
+       ctrl |= clkval;
+       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+
+       ctrl = readb(idev->base + CORE_I2C_CTRL);
+       if ((ctrl & CLK_MASK) != clkval)
+               return -EIO;
+
+       return 0;
+}
+
+static int mchp_corei2c_init(struct mchp_corei2c_dev *idev)
+{
+       u32 clk_rate = clk_get_rate(idev->i2c_clk);
+       u32 divisor = clk_rate / idev->bus_clk_rate;
+       int ret;
+
+       ret = mchp_corei2c_set_divisor(divisor, idev);
+       if (ret)
+               return ret;
+
+       mchp_corei2c_reset(idev);
+
+       return 0;
+}
+
+static void mchp_corei2c_empty_rx(struct mchp_corei2c_dev *idev)
+{
+       u8 ctrl;
+
+       if (idev->msg_len > 0) {
+               *idev->buf++ = readb(idev->base + CORE_I2C_DATA);
+               idev->msg_len--;
+       }
+
+       if (idev->msg_len == 0) {
+               ctrl = readb(idev->base + CORE_I2C_CTRL);
+               ctrl &= ~CTRL_AA;
+               writeb(ctrl, idev->base + CORE_I2C_CTRL);
+       }
+}
+
+static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev)
+{
+       if (idev->msg_len > 0)
+               writeb(*idev->buf++, idev->base + CORE_I2C_DATA);
+       idev->msg_len--;
+
+       return 0;
+}
+
+static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
+{
+       u32 status = idev->isr_status;
+       u8 ctrl;
+       bool last_byte = false, finished = false;
+
+       if (!idev->buf)
+               return IRQ_NONE;
+
+       switch (status) {
+       case STATUS_M_START_SENT:
+       case STATUS_M_REPEATED_START_SENT:
+               ctrl = readb(idev->base + CORE_I2C_CTRL);
+               ctrl &= ~CTRL_STA;
+               writeb(idev->addr, idev->base + CORE_I2C_DATA);
+               writeb(ctrl, idev->base + CORE_I2C_CTRL);
+               if (idev->msg_len == 0)
+                       finished = true;
+               break;
+       case STATUS_M_ARB_LOST:
+               idev->msg_err = -EAGAIN;
+               finished = true;
+               break;
+       case STATUS_M_SLAW_ACK:
+       case STATUS_M_TX_DATA_ACK:
+               if (idev->msg_len > 0)
+                       mchp_corei2c_fill_tx(idev);
+               else
+                       last_byte = true;
+               break;
+       case STATUS_M_TX_DATA_NACK:
+       case STATUS_M_SLAR_NACK:
+       case STATUS_M_SLAW_NACK:
+               idev->msg_err = -ENXIO;
+               last_byte = true;
+               break;
+       case STATUS_M_SLAR_ACK:
+               ctrl = readb(idev->base + CORE_I2C_CTRL);
+               if (idev->msg_len == 1u) {
+                       ctrl &= ~CTRL_AA;
+                       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+               } else {
+                       ctrl |= CTRL_AA;
+                       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+               }
+               if (idev->msg_len < 1u)
+                       last_byte = true;
+               break;
+       case STATUS_M_RX_DATA_ACKED:
+               mchp_corei2c_empty_rx(idev);
+               break;
+       case STATUS_M_RX_DATA_NACKED:
+               mchp_corei2c_empty_rx(idev);
+               if (idev->msg_len == 0)
+                       last_byte = true;
+               break;
+       default:
+               break;
+       }
+
+       /* On the last byte to be transmitted, send STOP */
+       if (last_byte)
+               mchp_corei2c_stop(idev);
+
+       if (last_byte || finished)
+               complete(&idev->msg_complete);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mchp_corei2c_isr(int irq, void *_dev)
+{
+       struct mchp_corei2c_dev *idev = _dev;
+       irqreturn_t ret = IRQ_NONE;
+       u8 ctrl;
+
+       ctrl = readb(idev->base + CORE_I2C_CTRL);
+       if (ctrl & CTRL_SI) {
+               idev->isr_status = readb(idev->base + CORE_I2C_STATUS);
+               ret = mchp_corei2c_handle_isr(idev);
+       }
+
+       ctrl = readb(idev->base + CORE_I2C_CTRL);
+       ctrl &= ~CTRL_SI;
+       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+
+       return ret;
+}
+
+static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev,
+                                struct i2c_msg *msg)
+{
+       u8 ctrl;
+       unsigned long time_left;
+
+       idev->addr = i2c_8bit_addr_from_msg(msg);
+       idev->msg_len = msg->len;
+       idev->buf = msg->buf;
+       idev->msg_err = 0;
+
+       reinit_completion(&idev->msg_complete);
+
+       mchp_corei2c_core_enable(idev);
+
+       ctrl = readb(idev->base + CORE_I2C_CTRL);
+       ctrl |= CTRL_STA;
+       writeb(ctrl, idev->base + CORE_I2C_CTRL);
+
+       time_left = wait_for_completion_timeout(&idev->msg_complete,
+                                               idev->adapter.timeout);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       return idev->msg_err;
+}
+
+static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                            int num)
+{
+       struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap);
+       int i, ret;
+
+       for (i = 0; i < num; i++) {
+               ret = mchp_corei2c_xfer_msg(idev, msgs++);
+               if (ret)
+                       return ret;
+       }
+
+       return num;
+}
+
+static u32 mchp_corei2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mchp_corei2c_algo = {
+       .master_xfer = mchp_corei2c_xfer,
+       .functionality = mchp_corei2c_func,
+};
+
+static int mchp_corei2c_probe(struct platform_device *pdev)
+{
+       struct mchp_corei2c_dev *idev;
+       struct resource *res;
+       int irq, ret;
+
+       idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
+       if (!idev)
+               return -ENOMEM;
+
+       idev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(idev->base))
+               return PTR_ERR(idev->base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return dev_err_probe(&pdev->dev, -ENXIO,
+                                    "invalid IRQ %d for I2C controller\n", irq);
+
+       idev->i2c_clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(idev->i2c_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(idev->i2c_clk),
+                                    "missing clock\n");
+
+       idev->dev = &pdev->dev;
+       init_completion(&idev->msg_complete);
+
+       ret = device_property_read_u32(idev->dev, "clock-frequency",
+                                      &idev->bus_clk_rate);
+       if (ret || !idev->bus_clk_rate) {
+               dev_info(&pdev->dev, "default to 100kHz\n");
+               idev->bus_clk_rate = 100000;
+       }
+
+       if (idev->bus_clk_rate > 400000)
+               return dev_err_probe(&pdev->dev, -EINVAL,
+                                    "clock-frequency too high: %d\n",
+                                    idev->bus_clk_rate);
+
+       /*
+        * This driver supports both the hard peripherals & soft FPGA cores.
+        * The hard peripherals do not have shared IRQs, but we don't have
+        * control over what way the interrupts are wired for the soft cores.
+        */
+       ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED,
+                              pdev->name, idev);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to claim irq %d\n", irq);
+
+       ret = clk_prepare_enable(idev->i2c_clk);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to enable clock\n");
+
+       ret = mchp_corei2c_init(idev);
+       if (ret) {
+               clk_disable_unprepare(idev->i2c_clk);
+               return dev_err_probe(&pdev->dev, ret, "failed to program clock divider\n");
+       }
+
+       i2c_set_adapdata(&idev->adapter, idev);
+       snprintf(idev->adapter.name, sizeof(idev->adapter.name),
+                "Microchip I2C hw bus at %08lx", (unsigned long)res->start);
+       idev->adapter.owner = THIS_MODULE;
+       idev->adapter.algo = &mchp_corei2c_algo;
+       idev->adapter.dev.parent = &pdev->dev;
+       idev->adapter.dev.of_node = pdev->dev.of_node;
+       idev->adapter.timeout = HZ;
+
+       platform_set_drvdata(pdev, idev);
+
+       ret = i2c_add_adapter(&idev->adapter);
+       if (ret) {
+               clk_disable_unprepare(idev->i2c_clk);
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "registered CoreI2C bus driver\n");
+
+       return 0;
+}
+
+static int mchp_corei2c_remove(struct platform_device *pdev)
+{
+       struct mchp_corei2c_dev *idev = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(idev->i2c_clk);
+       i2c_del_adapter(&idev->adapter);
+
+       return 0;
+}
+
+static const struct of_device_id mchp_corei2c_of_match[] = {
+       { .compatible = "microchip,mpfs-i2c" },
+       { .compatible = "microchip,corei2c-rtl-v7" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match);
+
+static struct platform_driver mchp_corei2c_driver = {
+       .probe = mchp_corei2c_probe,
+       .remove = mchp_corei2c_remove,
+       .driver = {
+               .name = "microchip-corei2c",
+               .of_match_table = mchp_corei2c_of_match,
+       },
+};
+
+module_platform_driver(mchp_corei2c_driver);
+
+MODULE_DESCRIPTION("Microchip CoreI2C bus driver");
+MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_LICENSE("GPL");
index 815cc56..72fcfb1 100644 (file)
@@ -560,6 +560,10 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
        if (err)
                goto mlxcpld_i2_probe_failed;
 
+       /* Notify caller when adapter is added. */
+       if (pdata && pdata->completion_notify)
+               pdata->completion_notify(pdata->handle, mlxcpld_i2c_adapter.nr);
+
        return 0;
 
 mlxcpld_i2_probe_failed:
index 5c8e94b..103a05e 100644 (file)
@@ -150,6 +150,7 @@ struct mv64xxx_i2c_data {
        /* 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;
+       bool                    atomic;
 };
 
 static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -179,7 +180,10 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
        u32     dir = 0;
 
        drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
-               MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
+                             MV64XXX_I2C_REG_CONTROL_TWSIEN;
+
+       if (!drv_data->atomic)
+               drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN;
 
        if (msg->flags & I2C_M_RD)
                dir = 1;
@@ -409,7 +413,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
        case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
                drv_data->msg->buf[drv_data->byte_posn++] =
                        readl(drv_data->reg_base + drv_data->reg_offsets.data);
-               drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+               if (!drv_data->atomic)
+                       drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
                writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
                        drv_data->reg_base + drv_data->reg_offsets.control);
                drv_data->block = 0;
@@ -427,7 +432,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
                drv_data->rc = -EIO;
                fallthrough;
        case MV64XXX_I2C_ACTION_SEND_STOP:
-               drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+               if (!drv_data->atomic)
+                       drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
                writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
                        drv_data->reg_base + drv_data->reg_offsets.control);
                drv_data->block = 0;
@@ -575,6 +581,17 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
                spin_unlock_irqrestore(&drv_data->lock, flags);
 }
 
+static void mv64xxx_i2c_wait_polling(struct mv64xxx_i2c_data *drv_data)
+{
+       ktime_t timeout = ktime_add_ms(ktime_get(), drv_data->adapter.timeout);
+
+       while (READ_ONCE(drv_data->block) &&
+              ktime_compare(ktime_get(), timeout) < 0) {
+               udelay(5);
+               mv64xxx_i2c_intr(0, drv_data);
+       }
+}
+
 static int
 mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
                                int is_last)
@@ -590,7 +607,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
        mv64xxx_i2c_send_start(drv_data);
        spin_unlock_irqrestore(&drv_data->lock, flags);
 
-       mv64xxx_i2c_wait_for_completion(drv_data);
+       if (!drv_data->atomic)
+               mv64xxx_i2c_wait_for_completion(drv_data);
+       else
+               mv64xxx_i2c_wait_polling(drv_data);
+
        return drv_data->rc;
 }
 
@@ -717,7 +738,7 @@ mv64xxx_i2c_functionality(struct i2c_adapter *adap)
 }
 
 static int
-mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
        struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
        int rc, ret = num;
@@ -730,7 +751,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        drv_data->msgs = msgs;
        drv_data->num_msgs = num;
 
-       if (mv64xxx_i2c_can_offload(drv_data))
+       if (mv64xxx_i2c_can_offload(drv_data) && !drv_data->atomic)
                rc = mv64xxx_i2c_offload_xfer(drv_data);
        else
                rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
@@ -747,8 +768,27 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        return ret;
 }
 
+static int
+mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+       struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
+
+       drv_data->atomic = 0;
+       return mv64xxx_i2c_xfer_core(adap, msgs, num);
+}
+
+static int mv64xxx_i2c_xfer_atomic(struct i2c_adapter *adap,
+                                  struct i2c_msg msgs[], int num)
+{
+       struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
+
+       drv_data->atomic = 1;
+       return mv64xxx_i2c_xfer_core(adap, msgs, num);
+}
+
 static const struct i2c_algorithm mv64xxx_i2c_algo = {
        .master_xfer = mv64xxx_i2c_xfer,
+       .master_xfer_atomic = mv64xxx_i2c_xfer_atomic,
        .functionality = mv64xxx_i2c_functionality,
 };
 
@@ -1047,14 +1087,6 @@ mv64xxx_i2c_remove(struct platform_device *pd)
        return 0;
 }
 
-static void
-mv64xxx_i2c_shutdown(struct platform_device *pd)
-{
-       pm_runtime_disable(&pd->dev);
-       if (!pm_runtime_status_suspended(&pd->dev))
-               mv64xxx_i2c_runtime_suspend(&pd->dev);
-}
-
 static const struct dev_pm_ops mv64xxx_i2c_pm_ops = {
        SET_RUNTIME_PM_OPS(mv64xxx_i2c_runtime_suspend,
                           mv64xxx_i2c_runtime_resume, NULL)
@@ -1065,7 +1097,6 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = {
 static struct platform_driver mv64xxx_i2c_driver = {
        .probe  = mv64xxx_i2c_probe,
        .remove = mv64xxx_i2c_remove,
-       .shutdown = mv64xxx_i2c_shutdown,
        .driver = {
                .name   = MV64XXX_I2C_CTLR_NAME,
                .pm     = &mv64xxx_i2c_pm_ops,
index 864a3f1..68f67d0 100644 (file)
@@ -799,7 +799,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
        if (!i2c)
                return -ENOMEM;
 
-       i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
+       i2c->dev_type = (uintptr_t)of_device_get_match_data(&pdev->dev);
 
        i2c->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(i2c->regs))
index aede9d5..0c365b5 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
@@ -91,7 +92,6 @@ enum i2c_addr {
 
 /* init register and default value required to enable module */
 #define NPCM_I2CSEGCTL                 0xE4
-#define NPCM_I2CSEGCTL_INIT_VAL                0x0333F000
 
 /* Common regs */
 #define NPCM_I2CSDA                    0x00
@@ -123,11 +123,11 @@ enum i2c_addr {
  * Since the addr regs are sprinkled all over the address space,
  * use this array to get the address or each register.
  */
-#define I2C_NUM_OWN_ADDR 10
+#define I2C_NUM_OWN_ADDR 2
+#define I2C_NUM_OWN_ADDR_SUPPORTED 2
+
 static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
-       NPCM_I2CADDR1, NPCM_I2CADDR2, NPCM_I2CADDR3, NPCM_I2CADDR4,
-       NPCM_I2CADDR5, NPCM_I2CADDR6, NPCM_I2CADDR7, NPCM_I2CADDR8,
-       NPCM_I2CADDR9, NPCM_I2CADDR10,
+       NPCM_I2CADDR1, NPCM_I2CADDR2,
 };
 #endif
 
@@ -226,8 +226,7 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
 #define NPCM_I2CFIF_CTS_CLR_FIFO       BIT(6)
 #define NPCM_I2CFIF_CTS_SLVRSTR                BIT(7)
 
-/* NPCM_I2CTXF_CTL reg fields */
-#define NPCM_I2CTXF_CTL_TX_THR         GENMASK(4, 0)
+/* NPCM_I2CTXF_CTL reg field */
 #define NPCM_I2CTXF_CTL_THR_TXIE       BIT(6)
 
 /* NPCM_I2CT_OUT reg fields */
@@ -236,22 +235,18 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
 #define NPCM_I2CT_OUT_T_OUTST          BIT(7)
 
 /* NPCM_I2CTXF_STS reg fields */
-#define NPCM_I2CTXF_STS_TX_BYTES       GENMASK(4, 0)
 #define NPCM_I2CTXF_STS_TX_THST                BIT(6)
 
 /* NPCM_I2CRXF_STS reg fields */
-#define NPCM_I2CRXF_STS_RX_BYTES       GENMASK(4, 0)
 #define NPCM_I2CRXF_STS_RX_THST                BIT(6)
 
 /* NPCM_I2CFIF_CTL reg fields */
 #define NPCM_I2CFIF_CTL_FIFO_EN                BIT(4)
 
 /* NPCM_I2CRXF_CTL reg fields */
-#define NPCM_I2CRXF_CTL_RX_THR         GENMASK(4, 0)
-#define NPCM_I2CRXF_CTL_LAST_PEC       BIT(5)
 #define NPCM_I2CRXF_CTL_THR_RXIE       BIT(6)
 
-#define I2C_HW_FIFO_SIZE               16
+#define MAX_I2C_HW_FIFO_SIZE           32
 
 /* I2C_VER reg fields */
 #define I2C_VER_VERSION                        GENMASK(6, 0)
@@ -268,11 +263,36 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
 #define I2C_FREQ_MIN_HZ                        10000
 #define I2C_FREQ_MAX_HZ                        I2C_MAX_FAST_MODE_PLUS_FREQ
 
+struct npcm_i2c_data {
+       u8 fifo_size;
+       u32 segctl_init_val;
+       u8 txf_sts_tx_bytes;
+       u8 rxf_sts_rx_bytes;
+       u8 rxf_ctl_last_pec;
+};
+
+static const struct npcm_i2c_data npxm7xx_i2c_data = {
+       .fifo_size = 16,
+       .segctl_init_val = 0x0333F000,
+       .txf_sts_tx_bytes = GENMASK(4, 0),
+       .rxf_sts_rx_bytes = GENMASK(4, 0),
+       .rxf_ctl_last_pec = BIT(5),
+};
+
+static const struct npcm_i2c_data npxm8xx_i2c_data = {
+       .fifo_size = 32,
+       .segctl_init_val = 0x9333F000,
+       .txf_sts_tx_bytes = GENMASK(5, 0),
+       .rxf_sts_rx_bytes = GENMASK(5, 0),
+       .rxf_ctl_last_pec = BIT(7),
+};
+
 /* Status of one I2C module */
 struct npcm_i2c {
        struct i2c_adapter adap;
        struct device *dev;
        unsigned char __iomem *reg;
+       const struct npcm_i2c_data *data;
        spinlock_t lock;   /* IRQ synchronization */
        struct completion cmd_complete;
        int cmd_err;
@@ -305,8 +325,8 @@ struct npcm_i2c {
        int slv_rd_ind;
        int slv_wr_size;
        int slv_wr_ind;
-       u8 slv_rd_buf[I2C_HW_FIFO_SIZE];
-       u8 slv_wr_buf[I2C_HW_FIFO_SIZE];
+       u8 slv_rd_buf[MAX_I2C_HW_FIFO_SIZE];
+       u8 slv_wr_buf[MAX_I2C_HW_FIFO_SIZE];
 #endif
        struct dentry *debugfs; /* debugfs device directory */
        u64 ber_cnt;
@@ -392,14 +412,10 @@ static void npcm_i2c_disable(struct npcm_i2c *bus)
 #if IS_ENABLED(CONFIG_I2C_SLAVE)
        int i;
 
-       /* select bank 0 for I2C addresses */
-       npcm_i2c_select_bank(bus, I2C_BANK_0);
-
        /* Slave addresses removal */
-       for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR; i++)
+       for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++)
                iowrite8(0, bus->reg + npcm_i2caddr[i]);
 
-       npcm_i2c_select_bank(bus, I2C_BANK_1);
 #endif
        /* Disable module */
        i2cctl2 = ioread8(bus->reg + NPCM_I2CCTL2);
@@ -443,7 +459,7 @@ static inline bool npcm_i2c_tx_fifo_empty(struct npcm_i2c *bus)
 
        tx_fifo_sts = ioread8(bus->reg + NPCM_I2CTXF_STS);
        /* check if TX FIFO is not empty */
-       if ((tx_fifo_sts & NPCM_I2CTXF_STS_TX_BYTES) == 0)
+       if ((tx_fifo_sts & bus->data->txf_sts_tx_bytes) == 0)
                return false;
 
        /* check if TX FIFO status bit is set: */
@@ -456,7 +472,7 @@ static inline bool npcm_i2c_rx_fifo_full(struct npcm_i2c *bus)
 
        rx_fifo_sts = ioread8(bus->reg + NPCM_I2CRXF_STS);
        /* check if RX FIFO is not empty: */
-       if ((rx_fifo_sts & NPCM_I2CRXF_STS_RX_BYTES) == 0)
+       if ((rx_fifo_sts & bus->data->rxf_sts_rx_bytes) == 0)
                return false;
 
        /* check if rx fifo full status is set: */
@@ -604,8 +620,7 @@ static int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type,
                        i2cctl1 &= ~NPCM_I2CCTL1_GCMEN;
                iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1);
                return 0;
-       }
-       if (addr_type == I2C_ARP_ADDR) {
+       } else if (addr_type == I2C_ARP_ADDR) {
                i2cctl3 = ioread8(bus->reg + NPCM_I2CCTL3);
                if (enable)
                        i2cctl3 |= I2CCTL3_ARPMEN;
@@ -614,16 +629,16 @@ static int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type,
                iowrite8(i2cctl3, bus->reg + NPCM_I2CCTL3);
                return 0;
        }
+       if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10)
+               dev_err(bus->dev, "try to enable more than 2 SA not supported\n");
+
        if (addr_type >= I2C_ARP_ADDR)
                return -EFAULT;
-       /* select bank 0 for address 3 to 10 */
-       if (addr_type > I2C_SLAVE_ADDR2)
-               npcm_i2c_select_bank(bus, I2C_BANK_0);
+
        /* Set and enable the address */
        iowrite8(sa_reg, bus->reg + npcm_i2caddr[addr_type]);
        npcm_i2c_slave_int_enable(bus, enable);
-       if (addr_type > I2C_SLAVE_ADDR2)
-               npcm_i2c_select_bank(bus, I2C_BANK_1);
+
        return 0;
 }
 #endif
@@ -665,7 +680,7 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)
        }
 #endif
 
-       /* clear status bits for spurious interrupts */
+       /* Clear status bits for spurious interrupts */
        npcm_i2c_clear_master_status(bus);
 
        bus->state = I2C_IDLE;
@@ -744,11 +759,11 @@ static void npcm_i2c_callback(struct npcm_i2c *bus,
 static u8 npcm_i2c_fifo_usage(struct npcm_i2c *bus)
 {
        if (bus->operation == I2C_WRITE_OPER)
-               return FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES,
-                                ioread8(bus->reg + NPCM_I2CTXF_STS));
+               return (bus->data->txf_sts_tx_bytes &
+                       ioread8(bus->reg + NPCM_I2CTXF_STS));
        if (bus->operation == I2C_READ_OPER)
-               return FIELD_GET(NPCM_I2CRXF_STS_RX_BYTES,
-                                ioread8(bus->reg + NPCM_I2CRXF_STS));
+               return (bus->data->rxf_sts_rx_bytes &
+                       ioread8(bus->reg + NPCM_I2CRXF_STS));
        return 0;
 }
 
@@ -760,13 +775,13 @@ static void npcm_i2c_write_to_fifo_master(struct npcm_i2c *bus, u16 max_bytes)
         * Fill the FIFO, while the FIFO is not full and there are more bytes
         * to write
         */
-       size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus);
+       size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus);
        while (max_bytes-- && size_free_fifo) {
                if (bus->wr_ind < bus->wr_size)
                        npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]);
                else
                        npcm_i2c_wr_byte(bus, 0xFF);
-               size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus);
+               size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus);
        }
 }
 
@@ -787,11 +802,11 @@ static void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite)
 
        /* configure RX FIFO */
        if (nread > 0) {
-               rxf_ctl = min_t(int, nread, I2C_HW_FIFO_SIZE);
+               rxf_ctl = min_t(int, nread, bus->data->fifo_size);
 
                /* set LAST bit. if LAST is set next FIFO packet is nacked */
-               if (nread <= I2C_HW_FIFO_SIZE)
-                       rxf_ctl |= NPCM_I2CRXF_CTL_LAST_PEC;
+               if (nread <= bus->data->fifo_size)
+                       rxf_ctl |= bus->data->rxf_ctl_last_pec;
 
                /*
                 * if we are about to read the first byte in blk rd mode,
@@ -809,9 +824,9 @@ static void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite)
 
        /* configure TX FIFO */
        if (nwrite > 0) {
-               if (nwrite > I2C_HW_FIFO_SIZE)
+               if (nwrite > bus->data->fifo_size)
                        /* data to send is more then FIFO size. */
-                       iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CTXF_CTL);
+                       iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CTXF_CTL);
                else
                        iowrite8(nwrite, bus->reg + NPCM_I2CTXF_CTL);
 
@@ -846,15 +861,11 @@ static u8 npcm_i2c_get_slave_addr(struct npcm_i2c *bus, enum i2c_addr addr_type)
 {
        u8 slave_add;
 
-       /* select bank 0 for address 3 to 10 */
-       if (addr_type > I2C_SLAVE_ADDR2)
-               npcm_i2c_select_bank(bus, I2C_BANK_0);
+       if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10)
+               dev_err(bus->dev, "get slave: try to use more than 2 SA not supported\n");
 
        slave_add = ioread8(bus->reg + npcm_i2caddr[(int)addr_type]);
 
-       if (addr_type > I2C_SLAVE_ADDR2)
-               npcm_i2c_select_bank(bus, I2C_BANK_1);
-
        return slave_add;
 }
 
@@ -864,12 +875,12 @@ static int npcm_i2c_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add)
 
        /* Set the enable bit */
        slave_add |= 0x80;
-       npcm_i2c_select_bank(bus, I2C_BANK_0);
-       for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR; i++) {
+
+       for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) {
                if (ioread8(bus->reg + npcm_i2caddr[i]) == slave_add)
                        iowrite8(0, bus->reg + npcm_i2caddr[i]);
        }
-       npcm_i2c_select_bank(bus, I2C_BANK_1);
+
        return 0;
 }
 
@@ -882,13 +893,13 @@ static void npcm_i2c_write_fifo_slave(struct npcm_i2c *bus, u16 max_bytes)
        npcm_i2c_clear_fifo_int(bus);
        npcm_i2c_clear_tx_fifo(bus);
        iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
-       while (max_bytes-- && I2C_HW_FIFO_SIZE != npcm_i2c_fifo_usage(bus)) {
+       while (max_bytes-- && bus->data->fifo_size != npcm_i2c_fifo_usage(bus)) {
                if (bus->slv_wr_size <= 0)
                        break;
-               bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE;
+               bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1);
                npcm_i2c_wr_byte(bus, bus->slv_wr_buf[bus->slv_wr_ind]);
                bus->slv_wr_ind++;
-               bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE;
+               bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1);
                bus->slv_wr_size--;
        }
 }
@@ -903,7 +914,7 @@ static void npcm_i2c_read_fifo_slave(struct npcm_i2c *bus, u8 bytes_in_fifo)
        while (bytes_in_fifo--) {
                data = npcm_i2c_rd_byte(bus);
 
-               bus->slv_rd_ind = bus->slv_rd_ind % I2C_HW_FIFO_SIZE;
+               bus->slv_rd_ind = bus->slv_rd_ind & (bus->data->fifo_size - 1);
                bus->slv_rd_buf[bus->slv_rd_ind] = data;
                bus->slv_rd_ind++;
 
@@ -921,16 +932,20 @@ static int npcm_i2c_slave_get_wr_buf(struct npcm_i2c *bus)
        int ret = bus->slv_wr_ind;
 
        /* fill a cyclic buffer */
-       for (i = 0; i < I2C_HW_FIFO_SIZE; i++) {
-               if (bus->slv_wr_size >= I2C_HW_FIFO_SIZE)
+       for (i = 0; i < bus->data->fifo_size; i++) {
+               if (bus->slv_wr_size >= bus->data->fifo_size)
                        break;
-               i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value);
-               ind = (bus->slv_wr_ind + bus->slv_wr_size) % I2C_HW_FIFO_SIZE;
+               if (bus->state == I2C_SLAVE_MATCH) {
+                       i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value);
+                       bus->state = I2C_OPER_STARTED;
+               } else {
+                       i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value);
+               }
+               ind = (bus->slv_wr_ind + bus->slv_wr_size) & (bus->data->fifo_size - 1);
                bus->slv_wr_buf[ind] = value;
                bus->slv_wr_size++;
-               i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value);
        }
-       return I2C_HW_FIFO_SIZE - ret;
+       return bus->data->fifo_size - ret;
 }
 
 static void npcm_i2c_slave_send_rd_buf(struct npcm_i2c *bus)
@@ -965,7 +980,7 @@ static void npcm_i2c_slave_receive(struct npcm_i2c *bus, u16 nread,
        bus->slv_rd_ind = 0;
 
        iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
-       iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL);
+       iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CRXF_CTL);
        npcm_i2c_clear_tx_fifo(bus);
        npcm_i2c_clear_rx_fifo(bus);
 }
@@ -976,7 +991,6 @@ static void npcm_i2c_slave_xmit(struct npcm_i2c *bus, u16 nwrite,
        if (nwrite == 0)
                return;
 
-       bus->state = I2C_OPER_STARTED;
        bus->operation = I2C_WRITE_OPER;
 
        /* get the next buffer */
@@ -999,12 +1013,12 @@ static void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus)
 {
        int left_in_fifo;
 
-       left_in_fifo = FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES,
-                                ioread8(bus->reg + NPCM_I2CTXF_STS));
+       left_in_fifo = bus->data->txf_sts_tx_bytes &
+                       ioread8(bus->reg + NPCM_I2CTXF_STS);
 
        /* fifo already full: */
-       if (left_in_fifo >= I2C_HW_FIFO_SIZE ||
-           bus->slv_wr_size >= I2C_HW_FIFO_SIZE)
+       if (left_in_fifo >= bus->data->fifo_size ||
+           bus->slv_wr_size >= bus->data->fifo_size)
                return;
 
        /* update the wr fifo index back to the untransmitted bytes: */
@@ -1012,7 +1026,7 @@ static void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus)
        bus->slv_wr_size = bus->slv_wr_size + left_in_fifo;
 
        if (bus->slv_wr_ind < 0)
-               bus->slv_wr_ind += I2C_HW_FIFO_SIZE;
+               bus->slv_wr_ind += bus->data->fifo_size;
 }
 
 static void npcm_i2c_slave_rd_wr(struct npcm_i2c *bus)
@@ -1158,7 +1172,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
                npcm_i2c_clear_rx_fifo(bus);
                npcm_i2c_clear_tx_fifo(bus);
                iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
-               iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL);
+               iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CRXF_CTL);
                if (NPCM_I2CST_XMIT & i2cst) {
                        bus->operation = I2C_WRITE_OPER;
                } else {
@@ -1238,7 +1252,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
        } /* SDAST */
 
        /*
-        * if irq is not one of the above, make sure EOB is disabled and all
+        * If irq is not one of the above, make sure EOB is disabled and all
         * status bits are cleared.
         */
        if (ret == IRQ_NONE) {
@@ -1319,8 +1333,8 @@ static void npcm_i2c_master_fifo_read(struct npcm_i2c *bus)
         * read == FIFO Size + C (where C < FIFO Size)then first read C bytes
         * and in the next int we read rest of the data.
         */
-       if (rcount < (2 * I2C_HW_FIFO_SIZE) && rcount > I2C_HW_FIFO_SIZE)
-               fifo_bytes = rcount - I2C_HW_FIFO_SIZE;
+       if (rcount < (2 * bus->data->fifo_size) && rcount > bus->data->fifo_size)
+               fifo_bytes = rcount - bus->data->fifo_size;
 
        if (rcount <= fifo_bytes) {
                /* last bytes are about to be read - end of tx */
@@ -1492,7 +1506,7 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)
                npcm_i2c_clear_master_status(bus);
                readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val,
                                          !(val & NPCM_I2CCST_BUSY), 10, 200);
-               /* verify no status bits are still set after bus is released */
+               /* Verify no status bits are still set after bus is released */
                npcm_i2c_clear_master_status(bus);
        }
        bus->state = I2C_IDLE;
@@ -1960,7 +1974,7 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode,
 
        npcm_i2c_reset(bus);
 
-       /* check HW is OK: SDA and SCL should be high at this point. */
+       /* Check HW is OK: SDA and SCL should be high at this point. */
        if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) {
                dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num);
                dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap),
@@ -2020,7 +2034,7 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id)
                        return IRQ_HANDLED;
        }
 #endif
-       /* clear status bits for spurious interrupts */
+       /* Clear status bits for spurious interrupts */
        npcm_i2c_clear_master_status(bus);
 
        return IRQ_HANDLED;
@@ -2199,10 +2213,10 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
         * It cannot be cleared without resetting the module.
         */
        else if (bus->cmd_err &&
-                (NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
+                (bus->data->rxf_ctl_last_pec & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
                npcm_i2c_reset(bus);
 
-       /* after any xfer, successful or not, stall and EOB must be disabled */
+       /* After any xfer, successful or not, stall and EOB must be disabled */
        npcm_i2c_stall_after_start(bus, false);
        npcm_i2c_eob_int(bus, false);
 
@@ -2268,6 +2282,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        static struct regmap *gcr_regmap;
+       struct device *dev = &pdev->dev;
        struct i2c_adapter *adap;
        struct npcm_i2c *bus;
        struct clk *i2c_clk;
@@ -2280,6 +2295,12 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
 
        bus->dev = &pdev->dev;
 
+       bus->data = of_device_get_match_data(dev);
+       if (!bus->data) {
+               dev_err(dev, "OF data missing\n");
+               return -EINVAL;
+       }
+
        bus->num = of_alias_get_id(pdev->dev.of_node, "i2c");
        /* core clk must be acquired to calculate module timing settings */
        i2c_clk = devm_clk_get(&pdev->dev, NULL);
@@ -2293,7 +2314,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
 
        if (IS_ERR(gcr_regmap))
                return PTR_ERR(gcr_regmap);
-       regmap_write(gcr_regmap, NPCM_I2CSEGCTL, NPCM_I2CSEGCTL_INIT_VAL);
+       regmap_write(gcr_regmap, NPCM_I2CSEGCTL, bus->data->segctl_init_val);
 
        bus->reg = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(bus->reg))
@@ -2355,7 +2376,8 @@ static int npcm_i2c_remove_bus(struct platform_device *pdev)
 }
 
 static const struct of_device_id npcm_i2c_bus_of_table[] = {
-       { .compatible = "nuvoton,npcm750-i2c", },
+       { .compatible = "nuvoton,npcm750-i2c", .data = &npxm7xx_i2c_data },
+       { .compatible = "nuvoton,npcm845-i2c", .data = &npxm8xx_i2c_data },
        {}
 };
 MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table);
index 5c7cc86..ea48e6a 100644 (file)
@@ -541,6 +541,7 @@ static int cci_probe(struct platform_device *pdev)
                return -ENOENT;
 
        for_each_available_child_of_node(dev->of_node, child) {
+               struct cci_master *master;
                u32 idx;
 
                ret = of_property_read_u32(child, "reg", &idx);
@@ -555,27 +556,27 @@ static int cci_probe(struct platform_device *pdev)
                        continue;
                }
 
-               cci->master[idx].adap.quirks = &cci->data->quirks;
-               cci->master[idx].adap.algo = &cci_algo;
-               cci->master[idx].adap.dev.parent = dev;
-               cci->master[idx].adap.dev.of_node = of_node_get(child);
-               cci->master[idx].master = idx;
-               cci->master[idx].cci = cci;
+               master = &cci->master[idx];
+               master->adap.quirks = &cci->data->quirks;
+               master->adap.algo = &cci_algo;
+               master->adap.dev.parent = dev;
+               master->adap.dev.of_node = of_node_get(child);
+               master->master = idx;
+               master->cci = cci;
 
-               i2c_set_adapdata(&cci->master[idx].adap, &cci->master[idx]);
-               snprintf(cci->master[idx].adap.name,
-                        sizeof(cci->master[idx].adap.name), "Qualcomm-CCI");
+               i2c_set_adapdata(&master->adap, master);
+               snprintf(master->adap.name, sizeof(master->adap.name), "Qualcomm-CCI");
 
-               cci->master[idx].mode = I2C_MODE_STANDARD;
+               master->mode = I2C_MODE_STANDARD;
                ret = of_property_read_u32(child, "clock-frequency", &val);
                if (!ret) {
                        if (val == I2C_MAX_FAST_MODE_FREQ)
-                               cci->master[idx].mode = I2C_MODE_FAST;
+                               master->mode = I2C_MODE_FAST;
                        else if (val == I2C_MAX_FAST_MODE_PLUS_FREQ)
-                               cci->master[idx].mode = I2C_MODE_FAST_PLUS;
+                               master->mode = I2C_MODE_FAST_PLUS;
                }
 
-               init_completion(&cci->master[idx].irq_complete);
+               init_completion(&master->irq_complete);
        }
 
        /* Memory */
@@ -725,6 +726,40 @@ static const struct cci_data cci_v1_data = {
        },
 };
 
+static const struct cci_data cci_v1_5_data = {
+       .num_masters = 2,
+       .queue_size = { 64, 16 },
+       .quirks = {
+               .max_write_len = 10,
+               .max_read_len = 12,
+       },
+       .cci_clk_rate =  19200000,
+       .params[I2C_MODE_STANDARD] = {
+               .thigh = 78,
+               .tlow = 114,
+               .tsu_sto = 28,
+               .tsu_sta = 28,
+               .thd_dat = 10,
+               .thd_sta = 77,
+               .tbuf = 118,
+               .scl_stretch_en = 0,
+               .trdhld = 6,
+               .tsp = 1
+       },
+       .params[I2C_MODE_FAST] = {
+               .thigh = 20,
+               .tlow = 28,
+               .tsu_sto = 21,
+               .tsu_sta = 21,
+               .thd_dat = 13,
+               .thd_sta = 18,
+               .tbuf = 32,
+               .scl_stretch_en = 0,
+               .trdhld = 6,
+               .tsp = 3
+       },
+};
+
 static const struct cci_data cci_v2_data = {
        .num_masters = 2,
        .queue_size = { 64, 16 },
@@ -773,6 +808,7 @@ static const struct cci_data cci_v2_data = {
 
 static const struct of_device_id cci_dt_match[] = {
        { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
+       { .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data},
        { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
        { .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
        { .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},
index 6ac402e..6ac179a 100644 (file)
@@ -97,6 +97,7 @@ struct geni_i2c_dev {
        struct dma_chan *tx_c;
        struct dma_chan *rx_c;
        bool gpi_mode;
+       bool abort_done;
 };
 
 struct geni_i2c_err_log {
@@ -203,9 +204,18 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
                dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
                        gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
 
-       if (err != NACK && err != GENI_ABORT_DONE) {
+       switch (err) {
+       case GENI_ABORT_DONE:
+               gi2c->abort_done = true;
+               break;
+       case NACK:
+       case GENI_TIMEOUT:
+               dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
+               break;
+       default:
                dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
                geni_i2c_err_misc(gi2c);
+               break;
        }
 }
 
@@ -311,21 +321,21 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
 
 static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
 {
-       u32 val;
        unsigned long time_left = ABORT_TIMEOUT;
        unsigned long flags;
 
        spin_lock_irqsave(&gi2c->lock, flags);
        geni_i2c_err(gi2c, GENI_TIMEOUT);
        gi2c->cur = NULL;
+       gi2c->abort_done = false;
        geni_se_abort_m_cmd(&gi2c->se);
        spin_unlock_irqrestore(&gi2c->lock, flags);
+
        do {
                time_left = wait_for_completion_timeout(&gi2c->done, time_left);
-               val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
-       } while (!(val & M_CMD_ABORT_EN) && time_left);
+       } while (!gi2c->abort_done && time_left);
 
-       if (!(val & M_CMD_ABORT_EN))
+       if (!time_left)
                dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
 }
 
@@ -688,7 +698,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
        pm_runtime_put_autosuspend(gi2c->se.dev);
        gi2c->cur = NULL;
        gi2c->err = 0;
-       return num;
+       return ret;
 }
 
 static u32 geni_i2c_func(struct i2c_adapter *adap)
diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c
new file mode 100644 (file)
index 0000000..56d0fae
--- /dev/null
@@ -0,0 +1,532 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the Renesas RZ/V2M I2C unit
+ *
+ * Copyright (C) 2016-2022 Renesas Electronics Corporation
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/i2c.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+/* Register offsets */
+#define IICB0DAT       0x00            /* Data Register */
+#define IICB0CTL0      0x08            /* Control Register 0 */
+#define IICB0TRG       0x0C            /* Trigger Register */
+#define IICB0STR0      0x10            /* Status Register 0 */
+#define IICB0CTL1      0x20            /* Control Register 1 */
+#define IICB0WL                0x24            /* Low Level Width Setting Reg */
+#define IICB0WH                0x28            /* How Level Width Setting Reg */
+
+/* IICB0CTL0 */
+#define IICB0IICE      BIT(7)          /* I2C Enable */
+#define IICB0SLWT      BIT(1)          /* Interrupt Request Timing */
+#define IICB0SLAC      BIT(0)          /* Acknowledge */
+
+/* IICB0TRG */
+#define IICB0WRET      BIT(2)          /* Quit Wait Trigger */
+#define IICB0STT       BIT(1)          /* Create Start Condition Trigger */
+#define IICB0SPT       BIT(0)          /* Create Stop Condition Trigger */
+
+/* IICB0STR0 */
+#define IICB0SSAC      BIT(8)          /* Ack Flag */
+#define IICB0SSBS      BIT(6)          /* Bus Flag */
+#define IICB0SSSP      BIT(4)          /* Stop Condition Flag */
+
+/* IICB0CTL1 */
+#define IICB0MDSC      BIT(7)          /* Bus Mode */
+#define IICB0SLSE      BIT(1)          /* Start condition output */
+
+#define bit_setl(addr, val)            writel(readl(addr) | (val), (addr))
+#define bit_clrl(addr, val)            writel(readl(addr) & ~(val), (addr))
+
+struct rzv2m_i2c_priv {
+       void __iomem *base;
+       struct i2c_adapter adap;
+       struct clk *clk;
+       int bus_mode;
+       struct completion msg_tia_done;
+       u32 iicb0wl;
+       u32 iicb0wh;
+};
+
+enum bcr_index {
+       RZV2M_I2C_100K = 0,
+       RZV2M_I2C_400K,
+};
+
+struct bitrate_config {
+       unsigned int percent_low;
+       unsigned int min_hold_time_ns;
+};
+
+static const struct bitrate_config bitrate_configs[] = {
+       [RZV2M_I2C_100K] = { 47, 3450 },
+       [RZV2M_I2C_400K] = { 52, 900 },
+};
+
+static irqreturn_t rzv2m_i2c_tia_irq_handler(int this_irq, void *dev_id)
+{
+       struct rzv2m_i2c_priv *priv = dev_id;
+
+       complete(&priv->msg_tia_done);
+
+       return IRQ_HANDLED;
+}
+
+/* Calculate IICB0WL and IICB0WH */
+static int rzv2m_i2c_clock_calculate(struct device *dev,
+                                    struct rzv2m_i2c_priv *priv)
+{
+       const struct bitrate_config *config;
+       unsigned int hold_time_ns;
+       unsigned int total_pclks;
+       unsigned int trf_pclks;
+       unsigned long pclk_hz;
+       struct i2c_timings t;
+       u32 trf_ns;
+
+       i2c_parse_fw_timings(dev, &t, true);
+
+       pclk_hz = clk_get_rate(priv->clk);
+       total_pclks = pclk_hz / t.bus_freq_hz;
+
+       trf_ns = t.scl_rise_ns + t.scl_fall_ns;
+       trf_pclks = mul_u64_u32_div(pclk_hz, trf_ns, NSEC_PER_SEC);
+
+       /* Config setting */
+       switch (t.bus_freq_hz) {
+       case I2C_MAX_FAST_MODE_FREQ:
+               priv->bus_mode = RZV2M_I2C_400K;
+               break;
+       case I2C_MAX_STANDARD_MODE_FREQ:
+               priv->bus_mode = RZV2M_I2C_100K;
+               break;
+       default:
+               dev_err(dev, "transfer speed is invalid\n");
+               return -EINVAL;
+       }
+       config = &bitrate_configs[priv->bus_mode];
+
+       /* IICB0WL = (percent_low / Transfer clock) x PCLK */
+       priv->iicb0wl = total_pclks * config->percent_low / 100;
+       if (priv->iicb0wl > (BIT(10) - 1))
+               return -EINVAL;
+
+       /* IICB0WH = ((percent_high / Transfer clock) x PCLK) - (tR + tF) */
+       priv->iicb0wh = total_pclks - priv->iicb0wl - trf_pclks;
+       if (priv->iicb0wh > (BIT(10) - 1))
+               return -EINVAL;
+
+       /*
+        * Data hold time must be less than 0.9us in fast mode and
+        * 3.45us in standard mode.
+        * Data hold time = IICB0WL[9:2] / PCLK
+        */
+       hold_time_ns = div64_ul((u64)(priv->iicb0wl >> 2) * NSEC_PER_SEC, pclk_hz);
+       if (hold_time_ns > config->min_hold_time_ns) {
+               dev_err(dev, "data hold time %dns is over %dns\n",
+                       hold_time_ns, config->min_hold_time_ns);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void rzv2m_i2c_init(struct rzv2m_i2c_priv *priv)
+{
+       u32 i2c_ctl0;
+       u32 i2c_ctl1;
+
+       /* i2c disable */
+       writel(0, priv->base + IICB0CTL0);
+
+       /* IICB0CTL1 setting */
+       i2c_ctl1 = IICB0SLSE;
+       if (priv->bus_mode == RZV2M_I2C_400K)
+               i2c_ctl1 |= IICB0MDSC;
+       writel(i2c_ctl1, priv->base + IICB0CTL1);
+
+       /* IICB0WL IICB0WH setting */
+       writel(priv->iicb0wl, priv->base + IICB0WL);
+       writel(priv->iicb0wh, priv->base + IICB0WH);
+
+       /* i2c enable after setting */
+       i2c_ctl0 = IICB0SLWT | IICB0SLAC | IICB0IICE;
+       writel(i2c_ctl0, priv->base + IICB0CTL0);
+}
+
+static int rzv2m_i2c_write_with_ack(struct rzv2m_i2c_priv *priv, u32 data)
+{
+       unsigned long time_left;
+
+       reinit_completion(&priv->msg_tia_done);
+
+       writel(data, priv->base + IICB0DAT);
+
+       time_left = wait_for_completion_timeout(&priv->msg_tia_done,
+                                               priv->adap.timeout);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       /* Confirm ACK */
+       if ((readl(priv->base + IICB0STR0) & IICB0SSAC) != IICB0SSAC)
+               return -ENXIO;
+
+       return 0;
+}
+
+static int rzv2m_i2c_read_with_ack(struct rzv2m_i2c_priv *priv, u8 *data,
+                                  bool last)
+{
+       unsigned long time_left;
+       u32 data_tmp;
+
+       reinit_completion(&priv->msg_tia_done);
+
+       /* Interrupt request timing : 8th clock */
+       bit_clrl(priv->base + IICB0CTL0, IICB0SLWT);
+
+       /* Exit the wait state */
+       writel(IICB0WRET, priv->base + IICB0TRG);
+
+       /* Wait for transaction */
+       time_left = wait_for_completion_timeout(&priv->msg_tia_done,
+                                               priv->adap.timeout);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       if (last) {
+               /* Disable ACK */
+               bit_clrl(priv->base + IICB0CTL0, IICB0SLAC);
+
+               /* Read data*/
+               data_tmp = readl(priv->base + IICB0DAT);
+
+               /* Interrupt request timing : 9th clock */
+               bit_setl(priv->base + IICB0CTL0, IICB0SLWT);
+
+               /* Exit the wait state */
+               writel(IICB0WRET, priv->base + IICB0TRG);
+
+               /* Wait for transaction */
+               time_left = wait_for_completion_timeout(&priv->msg_tia_done,
+                                                       priv->adap.timeout);
+               if (!time_left)
+                       return -ETIMEDOUT;
+
+               /* Enable ACK */
+               bit_setl(priv->base + IICB0CTL0, IICB0SLAC);
+       } else {
+               /* Read data */
+               data_tmp = readl(priv->base + IICB0DAT);
+       }
+
+       *data = data_tmp;
+
+       return 0;
+}
+
+static int rzv2m_i2c_send(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg,
+                         unsigned int *count)
+{
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < msg->len; i++) {
+               ret = rzv2m_i2c_write_with_ack(priv, msg->buf[i]);
+               if (ret < 0)
+                       return ret;
+       }
+       *count = i;
+
+       return 0;
+}
+
+static int rzv2m_i2c_receive(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg,
+                            unsigned int *count)
+{
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < msg->len; i++) {
+               ret = rzv2m_i2c_read_with_ack(priv, &msg->buf[i],
+                                             (msg->len - 1) == i);
+               if (ret < 0)
+                       return ret;
+       }
+       *count = i;
+
+       return 0;
+}
+
+static int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv,
+                                 struct i2c_msg *msg)
+{
+       u32 addr;
+       int ret;
+
+       if (msg->flags & I2C_M_TEN) {
+               /*
+                * 10-bit address
+                *   addr_1: 5'b11110 | addr[9:8] | (R/nW)
+                *   addr_2: addr[7:0]
+                */
+               addr = 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7);
+               addr |= !!(msg->flags & I2C_M_RD);
+               /* Send 1st address(extend code) */
+               ret = rzv2m_i2c_write_with_ack(priv, addr);
+               if (ret)
+                       return ret;
+
+               /* Send 2nd address */
+               ret = rzv2m_i2c_write_with_ack(priv, msg->addr & 0xff);
+       } else {
+               /* 7-bit address */
+               addr = i2c_8bit_addr_from_msg(msg);
+               ret = rzv2m_i2c_write_with_ack(priv, addr);
+       }
+
+       return ret;
+}
+
+static int rzv2m_i2c_stop_condition(struct rzv2m_i2c_priv *priv)
+{
+       u32 value;
+
+       /* Send stop condition */
+       writel(IICB0SPT, priv->base + IICB0TRG);
+       return readl_poll_timeout(priv->base + IICB0STR0,
+                                 value, value & IICB0SSSP,
+                                 100, jiffies_to_usecs(priv->adap.timeout));
+}
+
+static int rzv2m_i2c_master_xfer_msg(struct rzv2m_i2c_priv *priv,
+                                 struct i2c_msg *msg, int stop)
+{
+       unsigned int count = 0;
+       int ret, read = !!(msg->flags & I2C_M_RD);
+
+       /* Send start condition */
+       writel(IICB0STT, priv->base + IICB0TRG);
+
+       ret = rzv2m_i2c_send_address(priv, msg);
+       if (!ret) {
+               if (read)
+                       ret = rzv2m_i2c_receive(priv, msg, &count);
+               else
+                       ret = rzv2m_i2c_send(priv, msg, &count);
+
+               if (!ret && stop)
+                       ret = rzv2m_i2c_stop_condition(priv);
+       }
+
+       if (ret == -ENXIO)
+               rzv2m_i2c_stop_condition(priv);
+       else if (ret < 0)
+               rzv2m_i2c_init(priv);
+       else
+               ret = count;
+
+       return ret;
+}
+
+static int rzv2m_i2c_master_xfer(struct i2c_adapter *adap,
+                                struct i2c_msg *msgs, int num)
+{
+       struct rzv2m_i2c_priv *priv = i2c_get_adapdata(adap);
+       struct device *dev = priv->adap.dev.parent;
+       unsigned int i;
+       int ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
+               return ret;
+
+       if (readl(priv->base + IICB0STR0) & IICB0SSBS) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       /* I2C main transfer */
+       for (i = 0; i < num; i++) {
+               ret = rzv2m_i2c_master_xfer_msg(priv, &msgs[i], i == (num - 1));
+               if (ret < 0)
+                       goto out;
+       }
+       ret = num;
+
+out:
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
+}
+
+static u32 rzv2m_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+              I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_adapter_quirks rzv2m_i2c_quirks = {
+       .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static struct i2c_algorithm rzv2m_i2c_algo = {
+       .master_xfer = rzv2m_i2c_master_xfer,
+       .functionality = rzv2m_i2c_func,
+};
+
+static int rzv2m_i2c_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct rzv2m_i2c_priv *priv;
+       struct reset_control *rstc;
+       struct i2c_adapter *adap;
+       struct resource *res;
+       int irq, ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(dev, PTR_ERR(priv->clk), "Can't get clock\n");
+
+       rstc = devm_reset_control_get_shared(dev, NULL);
+       if (IS_ERR(rstc))
+               return dev_err_probe(dev, PTR_ERR(rstc), "Missing reset ctrl\n");
+       /*
+        * The reset also affects other HW that is not under the control
+        * of Linux. Therefore, all we can do is deassert the reset.
+        */
+       reset_control_deassert(rstc);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0,
+                              dev_name(dev), priv);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+
+       adap = &priv->adap;
+       adap->nr = pdev->id;
+       adap->algo = &rzv2m_i2c_algo;
+       adap->quirks = &rzv2m_i2c_quirks;
+       adap->dev.parent = dev;
+       adap->owner = THIS_MODULE;
+       device_set_node(&adap->dev, dev_fwnode(dev));
+       i2c_set_adapdata(adap, priv);
+       strscpy(adap->name, pdev->name, sizeof(adap->name));
+       init_completion(&priv->msg_tia_done);
+
+       ret = rzv2m_i2c_clock_calculate(dev, priv);
+       if (ret < 0)
+               return ret;
+
+       pm_runtime_enable(dev);
+
+       pm_runtime_get_sync(dev);
+       rzv2m_i2c_init(priv);
+       pm_runtime_put(dev);
+
+       platform_set_drvdata(pdev, priv);
+
+       ret = i2c_add_numbered_adapter(adap);
+       if (ret < 0)
+               pm_runtime_disable(dev);
+
+       return ret;
+}
+
+static int rzv2m_i2c_remove(struct platform_device *pdev)
+{
+       struct rzv2m_i2c_priv *priv = platform_get_drvdata(pdev);
+       struct device *dev = priv->adap.dev.parent;
+
+       i2c_del_adapter(&priv->adap);
+       bit_clrl(priv->base + IICB0CTL0, IICB0IICE);
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+static int rzv2m_i2c_suspend(struct device *dev)
+{
+       struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
+               return ret;
+
+       bit_clrl(priv->base + IICB0CTL0, IICB0IICE);
+       pm_runtime_put(dev);
+
+       return 0;
+}
+
+static int rzv2m_i2c_resume(struct device *dev)
+{
+       struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = rzv2m_i2c_clock_calculate(dev, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
+               return ret;
+
+       rzv2m_i2c_init(priv);
+       pm_runtime_put(dev);
+
+       return 0;
+}
+
+static const struct of_device_id rzv2m_i2c_ids[] = {
+       { .compatible = "renesas,rzv2m-i2c" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rzv2m_i2c_ids);
+
+static const struct dev_pm_ops rzv2m_i2c_pm_ops = {
+       SYSTEM_SLEEP_PM_OPS(rzv2m_i2c_suspend, rzv2m_i2c_resume)
+};
+
+static struct platform_driver rzv2m_i2c_driver = {
+       .driver = {
+               .name = "rzv2m-i2c",
+               .of_match_table = rzv2m_i2c_ids,
+               .pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops),
+       },
+       .probe  = rzv2m_i2c_probe,
+       .remove = rzv2m_i2c_remove,
+};
+module_platform_driver(rzv2m_i2c_driver);
+
+MODULE_DESCRIPTION("RZ/V2M I2C bus driver");
+MODULE_AUTHOR("Renesas Electronics Corporation");
+MODULE_LICENSE("GPL");
index 6746aa4..79798fc 100644 (file)
@@ -30,7 +30,7 @@ struct acpi_smbus_cmi {
        u8 cap_info:1;
        u8 cap_read:1;
        u8 cap_write:1;
-       struct smbus_methods_t *methods;
+       const struct smbus_methods_t *methods;
 };
 
 static const struct smbus_methods_t smbus_methods = {
@@ -361,7 +361,6 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
 static int acpi_smbus_cmi_add(struct acpi_device *device)
 {
        struct acpi_smbus_cmi *smbus_cmi;
-       const struct acpi_device_id *id;
        int ret;
 
        smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
@@ -369,6 +368,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
                return -ENOMEM;
 
        smbus_cmi->handle = device->handle;
+       smbus_cmi->methods = device_get_match_data(&device->dev);
        strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
        device->driver_data = smbus_cmi;
@@ -376,11 +376,6 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
        smbus_cmi->cap_read = 0;
        smbus_cmi->cap_write = 0;
 
-       for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
-               if (!strcmp(id->id, acpi_device_hid(device)))
-                       smbus_cmi->methods =
-                               (struct smbus_methods_t *) id->driver_data;
-
        acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
                            acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
 
index 6d4aa64..d1c59d8 100644 (file)
@@ -410,6 +410,12 @@ static const struct stm32f7_i2c_setup stm32mp15_setup = {
        .fmp_clr_offset = 0x40,
 };
 
+static const struct stm32f7_i2c_setup stm32mp13_setup = {
+       .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
+       .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
+       .fmp_clr_offset = 0x4,
+};
+
 static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask)
 {
        writel_relaxed(readl_relaxed(reg) | mask, reg);
@@ -2468,6 +2474,7 @@ static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
 static const struct of_device_id stm32f7_i2c_match[] = {
        { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
        { .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup},
+       { .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_setup},
        {},
 };
 MODULE_DEVICE_TABLE(of, stm32f7_i2c_match);
index 9a1c3f8..b3fe6b2 100644 (file)
@@ -367,7 +367,7 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
        }
 }
 
-static void xiic_wakeup(struct xiic_i2c *i2c, int code)
+static void xiic_wakeup(struct xiic_i2c *i2c, enum xilinx_i2c_state code)
 {
        i2c->tx_msg = NULL;
        i2c->rx_msg = NULL;
@@ -383,7 +383,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
        u32 clr = 0;
        int xfer_more = 0;
        int wakeup_req = 0;
-       int wakeup_code = 0;
+       enum xilinx_i2c_state wakeup_code = STATE_DONE;
        int ret;
 
        /* Get the interrupt Status from the IPIF. There is no clearing of
index d43db2c..10f35f9 100644 (file)
@@ -1023,15 +1023,9 @@ static int dummy_probe(struct i2c_client *client,
        return 0;
 }
 
-static int dummy_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static struct i2c_driver dummy_driver = {
        .driver.name    = "dummy",
        .probe          = dummy_probe,
-       .remove         = dummy_remove,
        .id_table       = dummy_id,
 };
 
@@ -2467,8 +2461,9 @@ void i2c_put_adapter(struct i2c_adapter *adap)
        if (!adap)
                return;
 
-       put_device(&adap->dev);
        module_put(adap->owner);
+       /* Should be last, otherwise we risk use-after-free with 'adap' */
+       put_device(&adap->dev);
 }
 EXPORT_SYMBOL(i2c_put_adapter);
 
index d3acd8d..33024ac 100644 (file)
@@ -134,6 +134,7 @@ static int i2c_mux_probe(struct platform_device *pdev)
        return 0;
 
 err_children:
+       of_node_put(child);
        i2c_mux_del_adapters(muxc);
 err_parent:
        i2c_put_adapter(parent);
index fbda5ad..8eab501 100644 (file)
@@ -537,7 +537,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
  *
  * The return codes from the ``master_xfer{_atomic}`` fields should indicate the
  * type of error code that occurred during the transfer, as documented in the
- * Kernel Documentation file Documentation/i2c/fault-codes.rst.
+ * Kernel Documentation file Documentation/i2c/fault-codes.rst. Otherwise, the
+ * number of messages executed should be returned.
  */
 struct i2c_algorithm {
        /*