Merge tag 'i2c-for-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 15 Mar 2024 19:09:49 +0000 (12:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 15 Mar 2024 19:09:49 +0000 (12:09 -0700)
Pull i2c updates from Wolfram Sang:
 "Minor changes to the I2C core. Most changes are in drivers:

  The i801 and designware drivers received most of the changes,
  including refactorings and some additions.

  Recovery changes for the iMX and iMX-LPI2C are now utilizing the
  generic i2c support.

  The Cadence driver now supports system suspend and resume.

  The hisi, mpc, sh_mobile, and npcm drivers have undergone some
  cleanups and improvements. Meanwhile, Uwe continues his work on
  converting the "remove" callback to become a void function.

  The pca954x mux driver now supports additional configurations, such as
  isolating faulty channels and flushing stuck buses, among others.

  Support has been added for Renesas r8a779h0, i.MX95 LPI2C, and
  Microchip sam9x7. Meanwhile, Geert lays the groundwork for the
  upcoming R-Car Gen4"

* tag 'i2c-for-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (34 commits)
  i2c: sprd: Convert to platform remove callback returning void
  Documentation: i2c: Document that client auto-detection is a legacy mechanism
  i2c: remove redundant condition
  i2c: rcar: Prepare for the advent of ARCH_RCAR_GEN4
  i2c: imx-lpi2c: add generic GPIO recovery for LPI2C
  i2c: cadence: Add system suspend and resume PM support
  i2c: mpc: remove outdated macro
  i2c: mpc: use proper binding for transfer timeouts
  dt-bindings: i2c: mpc: use proper binding for transfer timeouts
  i2c: smbus: Prepare i2c_register_spd for usage on muxed segments
  i2c: constify the struct device_type usage
  i2c: designware: Implement generic polling mode code for Wangxun 10Gb NIC
  i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC
  i2c: designware: Move interrupt handling functions before i2c_dw_xfer()
  i2c: designware: Use accessors to DW_IC_INTR_MASK register
  i2c: designware: Do not enable interrupts shortly in polling mode
  i2c: designware: Uniform initialization flow for polling mode
  dt-bindings: i2c: at91: Add sam9x7 compatible string
  dt-bindings: i2c: imx-lpi2c: add i.MX95 LPI2C
  i2c: Remove redundant comparison in npcm_i2c_reg_slave
  ...

25 files changed:
Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml
Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.yaml
Documentation/devicetree/bindings/i2c/i2c-mpc.yaml
Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.yaml
Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml
Documentation/i2c/writing-clients.rst
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-master.c
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-hisi.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-imx-lpi2c.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-npcm7xx.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-sprd.c
drivers/i2c/i2c-core-base.c
drivers/i2c/i2c-smbus.c
drivers/i2c/muxes/i2c-mux-pca954x.c
include/linux/i2c.h

index 6adedd3ec399b90310a93e68d82eaa63325a772b..b1c13bab24722ff5ccdbb99e4bf9ecd7dc81f16d 100644 (file)
@@ -25,7 +25,9 @@ properties:
               - atmel,sama5d2-i2c
               - microchip,sam9x60-i2c
       - items:
-          - const: microchip,sama7g5-i2c
+          - enum:
+              - microchip,sama7g5-i2c
+              - microchip,sam9x7-i2c
           - const: microchip,sam9x60-i2c
 
   reg:
index 4656f5112b84e97d7642e8bec4eb2fe26c5ac8da..54d500be6aaac3bc925d5fcaa99d9bdb6b0d04c5 100644 (file)
@@ -24,6 +24,7 @@ properties:
               - fsl,imx8qm-lpi2c
               - fsl,imx8ulp-lpi2c
               - fsl,imx93-lpi2c
+              - fsl,imx95-lpi2c
           - const: fsl,imx7ulp-lpi2c
 
   reg:
index 70fb69b923c46da3441cde4bac2ae57e955496c8..b1d7d14c0be40af317b23b7fcb94342decb7f99e 100644 (file)
@@ -96,6 +96,6 @@ examples:
         interrupts = <43 2>;
         interrupt-parent = <&mpic>;
         clock-frequency = <400000>;
-        i2c-scl-clk-low-timeout-us = <10000>;
+        i2c-transfer-timeout-us = <10000>;
     };
 ...
index 2d7bb998b0e9d2651daf0efae9dd312f2ddf5ae9..9aa0585200c9cd24615d171b299c19ade27d861b 100644 (file)
@@ -71,6 +71,23 @@ properties:
     description: A voltage regulator supplying power to the chip. On PCA9846
       the regulator supplies power to VDD2 (core logic) and optionally to VDD1.
 
+  maxim,isolate-stuck-channel:
+    type: boolean
+    description: Allows to use non faulty channels while a stuck channel is
+      isolated from the upstream bus. If not set all channels are isolated from
+      the upstream bus until the fault is cleared.
+
+  maxim,send-flush-out-sequence:
+    type: boolean
+    description: Send a flush-out sequence to stuck auxiliary buses
+      automatically after a stuck channel is being detected.
+
+  maxim,preconnection-wiggle-test-enable:
+    type: boolean
+    description: Send a STOP condition to the auxiliary buses when the switch
+      register activates a channel to detect a stuck high fault. On fault the
+      channel is isolated from the upstream bus.
+
 required:
   - compatible
   - reg
@@ -95,6 +112,19 @@ allOf:
         "#interrupt-cells": false
         interrupt-controller: false
 
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              enum:
+                - maxim,max7357
+    then:
+      properties:
+        maxim,isolate-stuck-channel: false
+        maxim,send-flush-out-sequence: false
+        maxim,preconnection-wiggle-test-enable: false
+
 unevaluatedProperties: false
 
 examples:
index c4ace5585e1e22d32b17abc5a859f5c3b298b258..51b220da461b068d3af8614c8fc8d14071169de9 100644 (file)
@@ -53,6 +53,7 @@ properties:
               - renesas,i2c-r8a779a0     # R-Car V3U
               - renesas,i2c-r8a779f0     # R-Car S4-8
               - renesas,i2c-r8a779g0     # R-Car V4H
+              - renesas,i2c-r8a779h0     # R-Car V4M
           - const: renesas,rcar-gen4-i2c # R-Car Gen4
 
   reg:
index 41ddc10f1ac7b5dd860a829a4723b25b47ae5c4d..0b8439ea954ccdbd8fbf1f8c6564617298cc540c 100644 (file)
@@ -48,10 +48,6 @@ driver model device node, and its I2C address.
        .id_table       = foo_idtable,
        .probe          = foo_probe,
        .remove         = foo_remove,
-       /* if device autodetection is needed: */
-       .class          = I2C_CLASS_SOMETHING,
-       .detect         = foo_detect,
-       .address_list   = normal_i2c,
 
        .shutdown       = foo_shutdown, /* optional */
        .command        = foo_command,  /* optional, deprecated */
@@ -203,27 +199,8 @@ reference for later use.
 Device Detection
 ----------------
 
-Sometimes you do not know in advance which I2C devices are connected to
-a given I2C bus.  This is for example the case of hardware monitoring
-devices on a PC's SMBus.  In that case, you may want to let your driver
-detect supported devices automatically.  This is how the legacy model
-was working, and is now available as an extension to the standard
-driver model.
-
-You simply have to define a detect callback which will attempt to
-identify supported devices (returning 0 for supported ones and -ENODEV
-for unsupported ones), a list of addresses to probe, and a device type
-(or class) so that only I2C buses which may have that type of device
-connected (and not otherwise enumerated) will be probed.  For example,
-a driver for a hardware monitoring chip for which auto-detection is
-needed would set its class to I2C_CLASS_HWMON, and only I2C adapters
-with a class including I2C_CLASS_HWMON would be probed by this driver.
-Note that the absence of matching classes does not prevent the use of
-a device of that type on the given I2C adapter.  All it prevents is
-auto-detection; explicit instantiation of devices is still possible.
-
-Note that this mechanism is purely optional and not suitable for all
-devices.  You need some reliable way to identify the supported devices
+The device detection mechanism comes with a number of disadvantages.
+You need some reliable way to identify the supported devices
 (typically using device-specific, dedicated identification registers),
 otherwise misdetections are likely to occur and things can get wrong
 quickly.  Keep in mind that the I2C protocol doesn't include any
@@ -231,9 +208,8 @@ standard way to detect the presence of a chip at a given address, let
 alone a standard way to identify devices.  Even worse is the lack of
 semantics associated to bus transfers, which means that the same
 transfer can be seen as a read operation by a chip and as a write
-operation by another chip.  For these reasons, explicit device
-instantiation should always be preferred to auto-detection where
-possible.
+operation by another chip.  For these reasons, device detection is
+considered a legacy mechanism and shouldn't be used in new code.
 
 
 Device Deletion
index 28eb48dd5b3262b0ae05a0e2946b09b294e012a3..97989c914260f2893ee12ba2dca5ac202a1ed475 100644 (file)
@@ -1235,7 +1235,7 @@ config I2C_RCAR
        depends on ARCH_RENESAS || COMPILE_TEST
        select I2C_SLAVE
        select I2C_SMBUS
-       select RESET_CONTROLLER if ARCH_RCAR_GEN3
+       select RESET_CONTROLLER if ARCH_RCAR_GEN3 || ARCH_RCAR_GEN4
        help
          If you say yes to this option, support will be included for the
          R-Car I2C controller.
index de3f58b60dce5d465f75e3bc509ea449f0c927d0..4bb7d6756947cd16a9ab64295dfaa650bd58677f 100644 (file)
@@ -1176,6 +1176,18 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
        return 0;
 }
 
+static int __maybe_unused cdns_i2c_suspend(struct device *dev)
+{
+       struct cdns_i2c *xi2c = dev_get_drvdata(dev);
+
+       i2c_mark_adapter_suspended(&xi2c->adap);
+
+       if (!pm_runtime_status_suspended(dev))
+               return cdns_i2c_runtime_suspend(dev);
+
+       return 0;
+}
+
 /**
  * cdns_i2c_init -  Controller initialisation
  * @id:                Device private data structure
@@ -1219,7 +1231,28 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
        return 0;
 }
 
+static int __maybe_unused cdns_i2c_resume(struct device *dev)
+{
+       struct cdns_i2c *xi2c = dev_get_drvdata(dev);
+       int err;
+
+       err = cdns_i2c_runtime_resume(dev);
+       if (err)
+               return err;
+
+       if (pm_runtime_status_suspended(dev)) {
+               err = cdns_i2c_runtime_suspend(dev);
+               if (err)
+                       return err;
+       }
+
+       i2c_mark_adapter_resumed(&xi2c->adap);
+
+       return 0;
+}
+
 static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_i2c_suspend, cdns_i2c_resume)
        SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
                           cdns_i2c_runtime_resume, NULL)
 };
index 35f762872b8a58c2f7e8fd4867bb0e139aea5cf0..e8a688d04aee0fa9aa01dc4f5d1563526f354437 100644 (file)
@@ -648,7 +648,7 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
        __i2c_dw_disable(dev);
 
        /* Disable all interrupts */
-       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+       __i2c_dw_write_intr_mask(dev, 0);
        regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
 
        i2c_dw_release_lock(dev);
index a7f6f3eafad7dd72241f57a2a356219d36bfaf56..e9606c00b8d103c538034ad3038d53daeeb34563 100644 (file)
@@ -212,6 +212,7 @@ struct reset_control;
  * @msg_err: error status of the current transfer
  * @status: i2c master status, one of STATUS_*
  * @abort_source: copy of the TX_ABRT_SOURCE register
+ * @sw_mask: SW mask of DW_IC_INTR_MASK used in polling mode
  * @irq: interrupt number for the i2c master
  * @flags: platform specific flags like type of IO accessors or model
  * @adapter: i2c subsystem adapter node
@@ -270,6 +271,7 @@ struct dw_i2c_dev {
        int                     msg_err;
        unsigned int            status;
        unsigned int            abort_source;
+       unsigned int            sw_mask;
        int                     irq;
        u32                     flags;
        struct i2c_adapter      adapter;
@@ -303,6 +305,7 @@ struct dw_i2c_dev {
 #define ACCESS_INTR_MASK                       BIT(0)
 #define ACCESS_NO_IRQ_SUSPEND                  BIT(1)
 #define ARBITRATION_SEMAPHORE                  BIT(2)
+#define ACCESS_POLLING                         BIT(3)
 
 #define MODEL_MSCC_OCELOT                      BIT(8)
 #define MODEL_BAIKAL_BT1                       BIT(9)
@@ -318,7 +321,7 @@ struct dw_i2c_dev {
 #define AMD_UCSI_INTR_EN                       0xd
 
 #define TXGBE_TX_FIFO_DEPTH                    4
-#define TXGBE_RX_FIFO_DEPTH                    0
+#define TXGBE_RX_FIFO_DEPTH                    1
 
 struct i2c_dw_semaphore_callbacks {
        int     (*probe)(struct dw_i2c_dev *dev);
@@ -351,6 +354,24 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
        dev->status &= ~STATUS_ACTIVE;
 }
 
+static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev,
+                                           unsigned int intr_mask)
+{
+       unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask;
+
+       regmap_write(dev->map, DW_IC_INTR_MASK, val);
+       dev->sw_mask = intr_mask;
+}
+
+static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev,
+                                          unsigned int *intr_mask)
+{
+       if (!(dev->flags & ACCESS_POLLING))
+               regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask);
+       else
+               *intr_mask = dev->sw_mask;
+}
+
 void __i2c_dw_disable(struct dw_i2c_dev *dev);
 
 extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
index 85dbd0eb5392c53017ffec96bf3fca6646fa70c4..c7e56002809ace54d0307b3c350d0256c3bf41f1 100644 (file)
@@ -240,7 +240,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
                     msgs[dev->msg_write_idx].addr | ic_tar);
 
        /* Enforce disabled interrupts (due to HW issues) */
-       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+       __i2c_dw_write_intr_mask(dev, 0);
 
        /* Enable the adapter */
        __i2c_dw_enable(dev);
@@ -250,7 +250,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 
        /* Clear and enable interrupts */
        regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
-       regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
+       __i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK);
 }
 
 static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev)
@@ -300,7 +300,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
        dev->msgs = msgs;
        dev->msgs_num = num_msgs;
        i2c_dw_xfer_init(dev);
-       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
 
        /* Initiate messages read/write transaction */
        for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) {
@@ -355,68 +354,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
        return 0;
 }
 
-static int i2c_dw_poll_tx_empty(struct dw_i2c_dev *dev)
-{
-       u32 val;
-
-       return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
-                                       val & DW_IC_INTR_TX_EMPTY,
-                                       100, 1000);
-}
-
-static int i2c_dw_poll_rx_full(struct dw_i2c_dev *dev)
-{
-       u32 val;
-
-       return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
-                                       val & DW_IC_INTR_RX_FULL,
-                                       100, 1000);
-}
-
-static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
-                                  int num_msgs)
-{
-       struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
-       int msg_idx, buf_len, data_idx, ret;
-       unsigned int val, stop = 0;
-       u8 *buf;
-
-       dev->msgs = msgs;
-       dev->msgs_num = num_msgs;
-       i2c_dw_xfer_init(dev);
-       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
-
-       for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
-               buf = msgs[msg_idx].buf;
-               buf_len = msgs[msg_idx].len;
-
-               for (data_idx = 0; data_idx < buf_len; data_idx++) {
-                       if (msg_idx == num_msgs - 1 && data_idx == buf_len - 1)
-                               stop |= BIT(9);
-
-                       if (msgs[msg_idx].flags & I2C_M_RD) {
-                               regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | stop);
-
-                               ret = i2c_dw_poll_rx_full(dev);
-                               if (ret)
-                                       return ret;
-
-                               regmap_read(dev->map, DW_IC_DATA_CMD, &val);
-                               buf[data_idx] = val;
-                       } else {
-                               ret = i2c_dw_poll_tx_empty(dev);
-                               if (ret)
-                                       return ret;
-
-                               regmap_write(dev->map, DW_IC_DATA_CMD,
-                                            buf[data_idx] | stop);
-                       }
-               }
-       }
-
-       return num_msgs;
-}
-
 /*
  * Initiate (and continue) low level master read/write transaction.
  * This function is only called from i2c_dw_isr, and pumping i2c_msg
@@ -546,7 +483,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
        if (dev->msg_err)
                intr_mask = 0;
 
-       regmap_write(dev->map,  DW_IC_INTR_MASK, intr_mask);
+       __i2c_dw_write_intr_mask(dev, intr_mask);
 }
 
 static u8
@@ -554,6 +491,7 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
 {
        struct i2c_msg *msgs = dev->msgs;
        u32 flags = msgs[dev->msg_read_idx].flags;
+       unsigned int intr_mask;
 
        /*
         * Adjust the buffer length and mask the flag
@@ -568,8 +506,9 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
         * Received buffer length, re-enable TX_EMPTY interrupt
         * to resume the SMBUS transaction.
         */
-       regmap_update_bits(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY,
-                          DW_IC_INTR_TX_EMPTY);
+       __i2c_dw_read_intr_mask(dev, &intr_mask);
+       intr_mask |= DW_IC_INTR_TX_EMPTY;
+       __i2c_dw_write_intr_mask(dev, intr_mask);
 
        return len;
 }
@@ -633,6 +572,169 @@ i2c_dw_read(struct dw_i2c_dev *dev)
        }
 }
 
+static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+{
+       unsigned int stat, dummy;
+
+       /*
+        * The IC_INTR_STAT register just indicates "enabled" interrupts.
+        * The unmasked raw version of interrupt status bits is available
+        * in the IC_RAW_INTR_STAT register.
+        *
+        * That is,
+        *   stat = readl(IC_INTR_STAT);
+        * equals to,
+        *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
+        *
+        * The raw version might be useful for debugging purposes.
+        */
+       if (!(dev->flags & ACCESS_POLLING)) {
+               regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
+       } else {
+               regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
+               stat &= dev->sw_mask;
+       }
+
+       /*
+        * Do not use the IC_CLR_INTR register to clear interrupts, or
+        * you'll miss some interrupts, triggered during the period from
+        * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
+        *
+        * Instead, use the separately-prepared IC_CLR_* registers.
+        */
+       if (stat & DW_IC_INTR_RX_UNDER)
+               regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &dummy);
+       if (stat & DW_IC_INTR_RX_OVER)
+               regmap_read(dev->map, DW_IC_CLR_RX_OVER, &dummy);
+       if (stat & DW_IC_INTR_TX_OVER)
+               regmap_read(dev->map, DW_IC_CLR_TX_OVER, &dummy);
+       if (stat & DW_IC_INTR_RD_REQ)
+               regmap_read(dev->map, DW_IC_CLR_RD_REQ, &dummy);
+       if (stat & DW_IC_INTR_TX_ABRT) {
+               /*
+                * The IC_TX_ABRT_SOURCE register is cleared whenever
+                * the IC_CLR_TX_ABRT is read.  Preserve it beforehand.
+                */
+               regmap_read(dev->map, DW_IC_TX_ABRT_SOURCE, &dev->abort_source);
+               regmap_read(dev->map, DW_IC_CLR_TX_ABRT, &dummy);
+       }
+       if (stat & DW_IC_INTR_RX_DONE)
+               regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy);
+       if (stat & DW_IC_INTR_ACTIVITY)
+               regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy);
+       if ((stat & DW_IC_INTR_STOP_DET) &&
+           ((dev->rx_outstanding == 0) || (stat & DW_IC_INTR_RX_FULL)))
+               regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy);
+       if (stat & DW_IC_INTR_START_DET)
+               regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy);
+       if (stat & DW_IC_INTR_GEN_CALL)
+               regmap_read(dev->map, DW_IC_CLR_GEN_CALL, &dummy);
+
+       return stat;
+}
+
+static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat)
+{
+       if (stat & DW_IC_INTR_TX_ABRT) {
+               dev->cmd_err |= DW_IC_ERR_TX_ABRT;
+               dev->status &= ~STATUS_MASK;
+               dev->rx_outstanding = 0;
+
+               /*
+                * Anytime TX_ABRT is set, the contents of the tx/rx
+                * buffers are flushed. Make sure to skip them.
+                */
+               __i2c_dw_write_intr_mask(dev, 0);
+               goto tx_aborted;
+       }
+
+       if (stat & DW_IC_INTR_RX_FULL)
+               i2c_dw_read(dev);
+
+       if (stat & DW_IC_INTR_TX_EMPTY)
+               i2c_dw_xfer_msg(dev);
+
+       /*
+        * No need to modify or disable the interrupt mask here.
+        * i2c_dw_xfer_msg() will take care of it according to
+        * the current transmit status.
+        */
+
+tx_aborted:
+       if (((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) &&
+            (dev->rx_outstanding == 0))
+               complete(&dev->cmd_complete);
+       else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
+               /* Workaround to trigger pending interrupt */
+               __i2c_dw_read_intr_mask(dev, &stat);
+               __i2c_dw_write_intr_mask(dev, 0);
+               __i2c_dw_write_intr_mask(dev, stat);
+       }
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C master interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+       struct dw_i2c_dev *dev = dev_id;
+       unsigned int stat, enabled;
+
+       regmap_read(dev->map, DW_IC_ENABLE, &enabled);
+       regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
+       if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+               return IRQ_NONE;
+       if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0))
+               return IRQ_NONE;
+       dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
+
+       stat = i2c_dw_read_clear_intrbits(dev);
+
+       if (!(dev->status & STATUS_ACTIVE)) {
+               /*
+                * Unexpected interrupt in driver point of view. State
+                * variables are either unset or stale so acknowledge and
+                * disable interrupts for suppressing further interrupts if
+                * interrupt really came from this HW (E.g. firmware has left
+                * the HW active).
+                */
+               __i2c_dw_write_intr_mask(dev, 0);
+               return IRQ_HANDLED;
+       }
+
+       i2c_dw_process_transfer(dev, stat);
+
+       return IRQ_HANDLED;
+}
+
+static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev)
+{
+       unsigned long timeout = dev->adapter.timeout;
+       unsigned int stat;
+       int ret;
+
+       if (!(dev->flags & ACCESS_POLLING)) {
+               ret = wait_for_completion_timeout(&dev->cmd_complete, timeout);
+       } else {
+               timeout += jiffies;
+               do {
+                       ret = try_wait_for_completion(&dev->cmd_complete);
+                       if (ret)
+                               break;
+
+                       stat = i2c_dw_read_clear_intrbits(dev);
+                       if (stat)
+                               i2c_dw_process_transfer(dev, stat);
+                       else
+                               /* Try save some power */
+                               usleep_range(3, 25);
+               } while (time_before(jiffies, timeout));
+       }
+
+       return ret ? 0 : -ETIMEDOUT;
+}
+
 /*
  * Prepare controller for a transaction and call i2c_dw_xfer_msg.
  */
@@ -646,18 +748,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
        pm_runtime_get_sync(dev->dev);
 
-       /*
-        * Initiate I2C message transfer when polling mode is enabled,
-        * As it is polling based transfer mechanism, which does not support
-        * interrupt based functionalities of existing DesignWare driver.
-        */
        switch (dev->flags & MODEL_MASK) {
        case MODEL_AMD_NAVI_GPU:
                ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
                goto done_nolock;
-       case MODEL_WANGXUN_SP:
-               ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num);
-               goto done_nolock;
        default:
                break;
        }
@@ -685,12 +779,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        i2c_dw_xfer_init(dev);
 
        /* Wait for tx to complete */
-       if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
+       ret = i2c_dw_wait_transfer(dev);
+       if (ret) {
                dev_err(dev->dev, "controller timed out\n");
-               /* i2c_dw_init implicitly disables the adapter */
+               /* i2c_dw_init_master() implicitly disables the adapter */
                i2c_recover_bus(&dev->adapter);
                i2c_dw_init_master(dev);
-               ret = -ETIMEDOUT;
                goto done;
        }
 
@@ -698,7 +792,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
         * We must disable the adapter before returning and signaling the end
         * of the current transfer. Otherwise the hardware might continue
         * generating interrupts which in turn causes a race condition with
-        * the following transfer.  Needs some more investigation if the
+        * the following transfer. Needs some more investigation if the
         * additional interrupts are a hardware bug or this driver doesn't
         * handle them correctly yet.
         */
@@ -746,132 +840,6 @@ static const struct i2c_adapter_quirks i2c_dw_quirks = {
        .flags = I2C_AQ_NO_ZERO_LEN,
 };
 
-static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
-{
-       unsigned int stat, dummy;
-
-       /*
-        * The IC_INTR_STAT register just indicates "enabled" interrupts.
-        * The unmasked raw version of interrupt status bits is available
-        * in the IC_RAW_INTR_STAT register.
-        *
-        * That is,
-        *   stat = readl(IC_INTR_STAT);
-        * equals to,
-        *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
-        *
-        * The raw version might be useful for debugging purposes.
-        */
-       regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
-
-       /*
-        * Do not use the IC_CLR_INTR register to clear interrupts, or
-        * you'll miss some interrupts, triggered during the period from
-        * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
-        *
-        * Instead, use the separately-prepared IC_CLR_* registers.
-        */
-       if (stat & DW_IC_INTR_RX_UNDER)
-               regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &dummy);
-       if (stat & DW_IC_INTR_RX_OVER)
-               regmap_read(dev->map, DW_IC_CLR_RX_OVER, &dummy);
-       if (stat & DW_IC_INTR_TX_OVER)
-               regmap_read(dev->map, DW_IC_CLR_TX_OVER, &dummy);
-       if (stat & DW_IC_INTR_RD_REQ)
-               regmap_read(dev->map, DW_IC_CLR_RD_REQ, &dummy);
-       if (stat & DW_IC_INTR_TX_ABRT) {
-               /*
-                * The IC_TX_ABRT_SOURCE register is cleared whenever
-                * the IC_CLR_TX_ABRT is read.  Preserve it beforehand.
-                */
-               regmap_read(dev->map, DW_IC_TX_ABRT_SOURCE, &dev->abort_source);
-               regmap_read(dev->map, DW_IC_CLR_TX_ABRT, &dummy);
-       }
-       if (stat & DW_IC_INTR_RX_DONE)
-               regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy);
-       if (stat & DW_IC_INTR_ACTIVITY)
-               regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy);
-       if ((stat & DW_IC_INTR_STOP_DET) &&
-           ((dev->rx_outstanding == 0) || (stat & DW_IC_INTR_RX_FULL)))
-               regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy);
-       if (stat & DW_IC_INTR_START_DET)
-               regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy);
-       if (stat & DW_IC_INTR_GEN_CALL)
-               regmap_read(dev->map, DW_IC_CLR_GEN_CALL, &dummy);
-
-       return stat;
-}
-
-/*
- * Interrupt service routine. This gets called whenever an I2C master interrupt
- * occurs.
- */
-static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
-{
-       struct dw_i2c_dev *dev = dev_id;
-       unsigned int stat, enabled;
-
-       regmap_read(dev->map, DW_IC_ENABLE, &enabled);
-       regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
-       if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
-               return IRQ_NONE;
-       if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0))
-               return IRQ_NONE;
-       dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
-
-       stat = i2c_dw_read_clear_intrbits(dev);
-
-       if (!(dev->status & STATUS_ACTIVE)) {
-               /*
-                * Unexpected interrupt in driver point of view. State
-                * variables are either unset or stale so acknowledge and
-                * disable interrupts for suppressing further interrupts if
-                * interrupt really came from this HW (E.g. firmware has left
-                * the HW active).
-                */
-               regmap_write(dev->map, DW_IC_INTR_MASK, 0);
-               return IRQ_HANDLED;
-       }
-
-       if (stat & DW_IC_INTR_TX_ABRT) {
-               dev->cmd_err |= DW_IC_ERR_TX_ABRT;
-               dev->status &= ~STATUS_MASK;
-               dev->rx_outstanding = 0;
-
-               /*
-                * Anytime TX_ABRT is set, the contents of the tx/rx
-                * buffers are flushed. Make sure to skip them.
-                */
-               regmap_write(dev->map, DW_IC_INTR_MASK, 0);
-               goto tx_aborted;
-       }
-
-       if (stat & DW_IC_INTR_RX_FULL)
-               i2c_dw_read(dev);
-
-       if (stat & DW_IC_INTR_TX_EMPTY)
-               i2c_dw_xfer_msg(dev);
-
-       /*
-        * No need to modify or disable the interrupt mask here.
-        * i2c_dw_xfer_msg() will take care of it according to
-        * the current transmit status.
-        */
-
-tx_aborted:
-       if (((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) &&
-            (dev->rx_outstanding == 0))
-               complete(&dev->cmd_complete);
-       else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
-               /* Workaround to trigger pending interrupt */
-               regmap_read(dev->map, DW_IC_INTR_MASK, &stat);
-               regmap_write(dev->map, DW_IC_INTR_MASK, 0);
-               regmap_write(dev->map, DW_IC_INTR_MASK, stat);
-       }
-
-       return IRQ_HANDLED;
-}
-
 void i2c_dw_configure_master(struct dw_i2c_dev *dev)
 {
        struct i2c_timings *t = &dev->timings;
@@ -953,31 +921,6 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
        return 0;
 }
 
-static int i2c_dw_poll_adap_quirk(struct dw_i2c_dev *dev)
-{
-       struct i2c_adapter *adap = &dev->adapter;
-       int ret;
-
-       pm_runtime_get_noresume(dev->dev);
-       ret = i2c_add_numbered_adapter(adap);
-       if (ret)
-               dev_err(dev->dev, "Failed to add adapter: %d\n", ret);
-       pm_runtime_put_noidle(dev->dev);
-
-       return ret;
-}
-
-static bool i2c_dw_is_model_poll(struct dw_i2c_dev *dev)
-{
-       switch (dev->flags & MODEL_MASK) {
-       case MODEL_AMD_NAVI_GPU:
-       case MODEL_WANGXUN_SP:
-               return true;
-       default:
-               return false;
-       }
-}
-
 int i2c_dw_probe_master(struct dw_i2c_dev *dev)
 {
        struct i2c_adapter *adap = &dev->adapter;
@@ -1033,9 +976,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
        adap->dev.parent = dev->dev;
        i2c_set_adapdata(adap, dev);
 
-       if (i2c_dw_is_model_poll(dev))
-               return i2c_dw_poll_adap_quirk(dev);
-
        if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
                irq_flags = IRQF_NO_SUSPEND;
        } else {
@@ -1046,15 +986,17 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
        if (ret)
                return ret;
 
-       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+       __i2c_dw_write_intr_mask(dev, 0);
        i2c_dw_release_lock(dev);
 
-       ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
-                              dev_name(dev->dev), dev);
-       if (ret) {
-               dev_err(dev->dev, "failure requesting irq %i: %d\n",
-                       dev->irq, ret);
-               return ret;
+       if (!(dev->flags & ACCESS_POLLING)) {
+               ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
+                                      irq_flags, dev_name(dev->dev), dev);
+               if (ret) {
+                       dev_err(dev->dev, "failure requesting irq %i: %d\n",
+                               dev->irq, ret);
+                       return ret;
+               }
        }
 
        ret = i2c_dw_init_recovery_info(dev);
index 61d7a27aa070184db6a7754561ad42c25c79de6c..9be9a2658e1f6ede697906827b26da319b098902 100644 (file)
@@ -154,7 +154,7 @@ static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
 {
        struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       dev->flags |= MODEL_AMD_NAVI_GPU;
+       dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING;
        dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
        return 0;
 }
index 855b698e99c08004df29a5da485722974de63335..4ab41ba39d55fb6312c6ecc8068d894d7e37e936 100644 (file)
@@ -290,7 +290,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 
        dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
        if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))
-               dev->flags = MODEL_WANGXUN_SP;
+               dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING;
 
        dev->dev = &pdev->dev;
        dev->irq = irq;
index dfad5bad507550d00efa0ac282e18c4e4de44310..975c0b1c44deb61ae84bfbe877de390f01502c60 100644 (file)
@@ -57,6 +57,8 @@
 #define   HISI_I2C_FS_SPK_LEN_CNT      GENMASK(7, 0)
 #define HISI_I2C_HS_SPK_LEN            0x003c
 #define   HISI_I2C_HS_SPK_LEN_CNT      GENMASK(7, 0)
+#define HISI_I2C_TX_INT_CLR            0x0040
+#define   HISI_I2C_TX_AEMPTY_INT               BIT(0)
 #define HISI_I2C_INT_MSTAT             0x0044
 #define HISI_I2C_INT_CLR               0x0048
 #define HISI_I2C_INT_MASK              0x004C
@@ -124,6 +126,11 @@ static void hisi_i2c_clear_int(struct hisi_i2c_controller *ctlr, u32 mask)
        writel_relaxed(mask, ctlr->iobase + HISI_I2C_INT_CLR);
 }
 
+static void hisi_i2c_clear_tx_int(struct hisi_i2c_controller *ctlr, u32 mask)
+{
+       writel_relaxed(mask, ctlr->iobase + HISI_I2C_TX_INT_CLR);
+}
+
 static void hisi_i2c_handle_errors(struct hisi_i2c_controller *ctlr)
 {
        u32 int_err = ctlr->xfer_err, reg;
@@ -168,6 +175,7 @@ static int hisi_i2c_start_xfer(struct hisi_i2c_controller *ctlr)
        writel(reg, ctlr->iobase + HISI_I2C_FIFO_CTRL);
 
        hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
+       hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
        hisi_i2c_enable_int(ctlr, HISI_I2C_INT_ALL);
 
        return 0;
@@ -266,7 +274,7 @@ static int hisi_i2c_read_rx_fifo(struct hisi_i2c_controller *ctlr)
 
 static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr)
 {
-       int max_write = HISI_I2C_TX_FIFO_DEPTH;
+       int max_write = HISI_I2C_TX_FIFO_DEPTH - HISI_I2C_TX_F_AE_THRESH;
        bool need_restart = false, last_msg;
        struct i2c_msg *cur_msg;
        u32 cmd, fifo_state;
@@ -323,6 +331,8 @@ static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr)
         */
        if (ctlr->msg_tx_idx == ctlr->msg_num)
                hisi_i2c_disable_int(ctlr, HISI_I2C_INT_TX_EMPTY);
+
+       hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
 }
 
 static irqreturn_t hisi_i2c_irq(int irq, void *context)
@@ -363,6 +373,7 @@ out:
        if (int_stat & HISI_I2C_INT_TRANS_CPLT) {
                hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL);
                hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
+               hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
                complete(ctlr->completion);
        }
 
index 274e987e4cfa0f9b90a576b83d2a96368b7f50a3..a6861660cb8ca771f38415c08561f0cbb232588b 100644 (file)
 #define STATUS_FLAGS           (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \
                                 STATUS_ERROR_FLAGS)
 
+#define SMBUS_LEN_SENTINEL (I2C_SMBUS_BLOCK_MAX + 1)
+
 /* Older devices have their ID defined in <linux/pci_ids.h> */
 #define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS            0x02a3
 #define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS          0x06a3
@@ -328,11 +330,39 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
        "\t\t  0x10  don't use interrupts\n"
        "\t\t  0x20  disable SMBus Host Notify ");
 
+static int i801_get_block_len(struct i801_priv *priv)
+{
+       u8 len = inb_p(SMBHSTDAT0(priv));
+
+       if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+               pci_err(priv->pci_dev, "Illegal SMBus block read size %u\n", len);
+               return -EPROTO;
+       }
+
+       return len;
+}
+
+static int i801_check_and_clear_pec_error(struct i801_priv *priv)
+{
+       u8 status;
+
+       if (!(priv->features & FEATURE_SMBUS_PEC))
+               return 0;
+
+       status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
+       if (status) {
+               outb_p(status, SMBAUXSTS(priv));
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
 /* Make sure the SMBus host is ready to start transmitting.
    Return 0 if it is, -EBUSY if it is not. */
 static int i801_check_pre(struct i801_priv *priv)
 {
-       int status;
+       int status, result;
 
        status = inb_p(SMBHSTSTS(priv));
        if (status & SMBHSTSTS_HOST_BUSY) {
@@ -353,13 +383,9 @@ static int i801_check_pre(struct i801_priv *priv)
         * the hardware was already in this state when the driver
         * started.
         */
-       if (priv->features & FEATURE_SMBUS_PEC) {
-               status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
-               if (status) {
-                       pci_dbg(priv->pci_dev, "Clearing aux status flags (%02x)\n", status);
-                       outb_p(status, SMBAUXSTS(priv));
-               }
-       }
+       result = i801_check_and_clear_pec_error(priv);
+       if (result)
+               pci_dbg(priv->pci_dev, "Clearing aux status flag CRCE\n");
 
        return 0;
 }
@@ -408,14 +434,12 @@ static int i801_check_post(struct i801_priv *priv, int status)
                 * bit is harmless as long as it's cleared before
                 * the next operation.
                 */
-               if ((priv->features & FEATURE_SMBUS_PEC) &&
-                   (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) {
-                       outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv));
-                       result = -EBADMSG;
-                       dev_dbg(&priv->pci_dev->dev, "PEC error\n");
+               result = i801_check_and_clear_pec_error(priv);
+               if (result) {
+                       pci_dbg(priv->pci_dev, "PEC error\n");
                } else {
                        result = -ENXIO;
-                       dev_dbg(&priv->pci_dev->dev, "No response\n");
+                       pci_dbg(priv->pci_dev, "No response\n");
                }
        }
        if (status & SMBHSTSTS_BUS_ERR) {
@@ -512,12 +536,11 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
 
        if (read_write == I2C_SMBUS_READ ||
            command == I2C_SMBUS_BLOCK_PROC_CALL) {
-               len = inb_p(SMBHSTDAT0(priv));
-               if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
-                       status = -EPROTO;
+               status = i801_get_block_len(priv);
+               if (status < 0)
                        goto out;
-               }
 
+               len = status;
                data->block[0] = len;
                inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
                for (i = 0; i < len; i++)
@@ -531,17 +554,17 @@ out:
 static void i801_isr_byte_done(struct i801_priv *priv)
 {
        if (priv->is_read) {
-               /* For SMBus block reads, length is received with first byte */
-               if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) &&
-                   (priv->count == 0)) {
-                       priv->len = inb_p(SMBHSTDAT0(priv));
-                       if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) {
-                               dev_err(&priv->pci_dev->dev,
-                                       "Illegal SMBus block read size %d\n",
-                                       priv->len);
+               /*
+                * At transfer start i801_smbus_block_transaction() marks
+                * the block length as invalid. Check for this sentinel value
+                * and read the block length from SMBHSTDAT0.
+                */
+               if (priv->len == SMBUS_LEN_SENTINEL) {
+                       priv->len = i801_get_block_len(priv);
+                       if (priv->len < 0)
                                /* FIXME: Recover */
                                priv->len = I2C_SMBUS_BLOCK_MAX;
-                       }
+
                        priv->data[-1] = priv->len;
                }
 
@@ -688,13 +711,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
                if (status)
                        return status;
 
-               if (i == 1 && read_write == I2C_SMBUS_READ
-                && command != I2C_SMBUS_I2C_BLOCK_DATA) {
-                       len = inb_p(SMBHSTDAT0(priv));
-                       if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
-                               dev_err(&priv->pci_dev->dev,
-                                       "Illegal SMBus block read size %d\n",
-                                       len);
+               /*
+                * At transfer start i801_smbus_block_transaction() marks
+                * the block length as invalid. Check for this sentinel value
+                * and read the block length from SMBHSTDAT0.
+                */
+               if (len == SMBUS_LEN_SENTINEL) {
+                       len = i801_get_block_len(priv);
+                       if (len < 0) {
                                /* Recover */
                                while (inb_p(SMBHSTSTS(priv)) &
                                       SMBHSTSTS_HOST_BUSY)
@@ -792,77 +816,66 @@ static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data
        return 0;
 }
 
-/* Block transaction function */
-static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
-                                 u8 addr, u8 hstcmd, char read_write, int command)
+static int i801_smbus_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
+                                       u8 addr, u8 hstcmd, char read_write, int command)
 {
-       int result = 0;
-       unsigned char hostc;
-
        if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA)
-               data->block[0] = I2C_SMBUS_BLOCK_MAX;
+               /* Mark block length as invalid */
+               data->block[0] = SMBUS_LEN_SENTINEL;
        else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
                return -EPROTO;
 
-       switch (command) {
-       case I2C_SMBUS_BLOCK_DATA:
-               i801_set_hstadd(priv, addr, read_write);
-               outb_p(hstcmd, SMBHSTCMD(priv));
-               break;
-       case I2C_SMBUS_I2C_BLOCK_DATA:
-               /*
-                * NB: page 240 of ICH5 datasheet shows that the R/#W
-                * bit should be cleared here, even when reading.
-                * However if SPD Write Disable is set (Lynx Point and later),
-                * the read will fail if we don't set the R/#W bit.
-                */
-               i801_set_hstadd(priv, addr,
-                               priv->original_hstcfg & SMBHSTCFG_SPD_WD ?
-                               read_write : I2C_SMBUS_WRITE);
-               if (read_write == I2C_SMBUS_READ) {
-                       /* NB: page 240 of ICH5 datasheet also shows
-                        * that DATA1 is the cmd field when reading
-                        */
-                       outb_p(hstcmd, SMBHSTDAT1(priv));
-               } else
-                       outb_p(hstcmd, SMBHSTCMD(priv));
-
-               if (read_write == I2C_SMBUS_WRITE) {
-                       /* set I2C_EN bit in configuration register */
-                       pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
-                       pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
-                                             hostc | SMBHSTCFG_I2C_EN);
-               } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
-                       dev_err(&priv->pci_dev->dev,
-                               "I2C block read is unsupported!\n");
-                       return -EOPNOTSUPP;
-               }
-               break;
-       case I2C_SMBUS_BLOCK_PROC_CALL:
+       if (command == I2C_SMBUS_BLOCK_PROC_CALL)
                /* Needs to be flagged as write transaction */
                i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
+       else
+               i801_set_hstadd(priv, addr, read_write);
+       outb_p(hstcmd, SMBHSTCMD(priv));
+
+       if (priv->features & FEATURE_BLOCK_BUFFER)
+               return i801_block_transaction_by_block(priv, data, read_write, command);
+       else
+               return i801_block_transaction_byte_by_byte(priv, data, read_write, command);
+}
+
+static int i801_i2c_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
+                                     u8 addr, u8 hstcmd, char read_write, int command)
+{
+       int result;
+       u8 hostc;
+
+       if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+               return -EPROTO;
+       /*
+        * NB: page 240 of ICH5 datasheet shows that the R/#W bit should be cleared here,
+        * even when reading. However if SPD Write Disable is set (Lynx Point and later),
+        * the read will fail if we don't set the R/#W bit.
+        */
+       i801_set_hstadd(priv, addr,
+                       priv->original_hstcfg & SMBHSTCFG_SPD_WD ? read_write : I2C_SMBUS_WRITE);
+
+       /* NB: page 240 of ICH5 datasheet shows that DATA1 is the cmd field when reading */
+       if (read_write == I2C_SMBUS_READ)
+               outb_p(hstcmd, SMBHSTDAT1(priv));
+       else
                outb_p(hstcmd, SMBHSTCMD(priv));
-               break;
+
+       if (read_write == I2C_SMBUS_WRITE) {
+               /* set I2C_EN bit in configuration register */
+               pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+               pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN);
+       } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+               pci_err(priv->pci_dev, "I2C block read is unsupported!\n");
+               return -EOPNOTSUPP;
        }
 
-       /* Experience has shown that the block buffer can only be used for
-          SMBus (not I2C) block transactions, even though the datasheet
-          doesn't mention this limitation. */
-       if ((priv->features & FEATURE_BLOCK_BUFFER) &&
-           command != I2C_SMBUS_I2C_BLOCK_DATA)
-               result = i801_block_transaction_by_block(priv, data,
-                                                        read_write,
-                                                        command);
-       else
-               result = i801_block_transaction_byte_by_byte(priv, data,
-                                                            read_write,
-                                                            command);
+       /* Block buffer isn't supported for I2C block transactions */
+       result = i801_block_transaction_byte_by_byte(priv, data, read_write, command);
 
-       if (command == I2C_SMBUS_I2C_BLOCK_DATA
-        && read_write == I2C_SMBUS_WRITE) {
-               /* restore saved configuration register value */
+       /* restore saved configuration register value */
+       if (read_write == I2C_SMBUS_WRITE)
                pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
-       }
+
        return result;
 }
 
@@ -893,10 +906,10 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
                outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
                       SMBAUXCTL(priv));
 
-       if (size == I2C_SMBUS_BLOCK_DATA ||
-           size == I2C_SMBUS_I2C_BLOCK_DATA ||
-           size == I2C_SMBUS_BLOCK_PROC_CALL)
-               ret = i801_block_transaction(priv, data, addr, command, read_write, size);
+       if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_BLOCK_PROC_CALL)
+               ret = i801_smbus_block_transaction(priv, data, addr, command, read_write, size);
+       else if (size == I2C_SMBUS_I2C_BLOCK_DATA)
+               ret = i801_i2c_block_transaction(priv, data, addr, command, read_write, size);
        else
                ret = i801_simple_transaction(priv, data, addr, command, read_write, size);
 
@@ -969,11 +982,10 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = i801_func,
 };
 
-#define FEATURES_ICH5  (FEATURE_BLOCK_PROC | FEATURE_I2C_BLOCK_READ    | \
-                        FEATURE_IRQ | FEATURE_SMBUS_PEC                | \
-                        FEATURE_BLOCK_BUFFER | FEATURE_HOST_NOTIFY)
 #define FEATURES_ICH4  (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER | \
                         FEATURE_HOST_NOTIFY)
+#define FEATURES_ICH5  (FEATURES_ICH4 | FEATURE_BLOCK_PROC | \
+                        FEATURE_I2C_BLOCK_READ | FEATURE_IRQ)
 
 static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE_DATA(INTEL, 82801AA_3,                     0)                               },
@@ -1117,7 +1129,7 @@ static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
 {
        int i, count;
 
-       if (dm->type != 10)
+       if (dm->type != DMI_ENTRY_ONBOARD_DEVICE)
                return;
 
        count = (dm->length - sizeof(struct dmi_header)) / 2;
@@ -1447,8 +1459,7 @@ static inline void i801_del_mux(struct i801_priv *priv) { }
 #endif
 
 static struct platform_device *
-i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
-                struct resource *tco_res)
+i801_add_tco_spt(struct pci_dev *pci_dev, struct resource *tco_res)
 {
        static const struct itco_wdt_platform_data pldata = {
                .name = "Intel PCH",
@@ -1479,8 +1490,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
 }
 
 static struct platform_device *
-i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev,
-                struct resource *tco_res)
+i801_add_tco_cnl(struct pci_dev *pci_dev, struct resource *tco_res)
 {
        static const struct itco_wdt_platform_data pldata = {
                .name = "Intel PCH",
@@ -1520,9 +1530,9 @@ static void i801_add_tco(struct i801_priv *priv)
        res->flags = IORESOURCE_IO;
 
        if (priv->features & FEATURE_TCO_CNL)
-               priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res);
+               priv->tco_pdev = i801_add_tco_cnl(pci_dev, tco_res);
        else
-               priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res);
+               priv->tco_pdev = i801_add_tco_spt(pci_dev, tco_res);
 
        if (IS_ERR(priv->tco_pdev))
                dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
index 678b30e90492ad17294453a5e6c482007946e8f5..6d72e4e126dde6ba07770b20b358ba74dbda78b8 100644 (file)
@@ -106,6 +106,7 @@ struct lpi2c_imx_struct {
        unsigned int            txfifosize;
        unsigned int            rxfifosize;
        enum lpi2c_imx_mode     mode;
+       struct i2c_bus_recovery_info rinfo;
 };
 
 static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
@@ -133,6 +134,8 @@ static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
 
                if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
                        dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
+                       if (lpi2c_imx->adapter.bus_recovery_info)
+                               i2c_recover_bus(&lpi2c_imx->adapter);
                        return -ETIMEDOUT;
                }
                schedule();
@@ -190,6 +193,8 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
 
                if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
                        dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
+                       if (lpi2c_imx->adapter.bus_recovery_info)
+                               i2c_recover_bus(&lpi2c_imx->adapter);
                        break;
                }
                schedule();
@@ -325,6 +330,8 @@ static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
 
                if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
                        dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
+                       if (lpi2c_imx->adapter.bus_recovery_info)
+                               i2c_recover_bus(&lpi2c_imx->adapter);
                        return -ETIMEDOUT;
                }
                schedule();
@@ -526,6 +533,20 @@ static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
+                                 struct platform_device *pdev)
+{
+       struct i2c_bus_recovery_info *bri = &lpi2c_imx->rinfo;
+
+       bri->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (IS_ERR(bri->pinctrl))
+               return PTR_ERR(bri->pinctrl);
+
+       lpi2c_imx->adapter.bus_recovery_info = bri;
+
+       return 0;
+}
+
 static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
@@ -600,6 +621,12 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
        lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
        lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
 
+       /* Init optional bus recovery function */
+       ret = lpi2c_imx_init_recovery_info(lpi2c_imx, pdev);
+       /* Give it another chance if pinctrl used is not ready yet */
+       if (ret == -EPROBE_DEFER)
+               goto rpm_disable;
+
        ret = i2c_add_adapter(&lpi2c_imx->adapter);
        if (ret)
                goto rpm_disable;
index 60e813137f8442895b19c6e9d871252cc32c7f24..3842e527116b799b02860a8807c44d49b5c72375 100644 (file)
@@ -212,10 +212,6 @@ struct imx_i2c_struct {
        const struct imx_i2c_hwdata     *hwdata;
        struct i2c_bus_recovery_info rinfo;
 
-       struct pinctrl *pinctrl;
-       struct pinctrl_state *pinctrl_pins_default;
-       struct pinctrl_state *pinctrl_pins_gpio;
-
        struct imx_i2c_dma      *dma;
        struct i2c_client       *slave;
        enum i2c_slave_event last_slave_event;
@@ -1362,24 +1358,6 @@ static int i2c_imx_xfer_atomic(struct i2c_adapter *adapter,
        return result;
 }
 
-static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
-{
-       struct imx_i2c_struct *i2c_imx;
-
-       i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
-
-       pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
-}
-
-static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
-{
-       struct imx_i2c_struct *i2c_imx;
-
-       i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
-
-       pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
-}
-
 /*
  * We switch SCL and SDA to their GPIO function and do some bitbanging
  * for bus recovery. These alternative pinmux settings can be
@@ -1390,43 +1368,13 @@ static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
 static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
                struct platform_device *pdev)
 {
-       struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
-
-       i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
-       if (!i2c_imx->pinctrl) {
-               dev_info(&pdev->dev, "pinctrl unavailable, bus recovery not supported\n");
-               return 0;
-       }
-       if (IS_ERR(i2c_imx->pinctrl)) {
-               dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
-               return PTR_ERR(i2c_imx->pinctrl);
-       }
-
-       i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
-                       PINCTRL_STATE_DEFAULT);
-       i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
-                       "gpio");
-       rinfo->sda_gpiod = devm_gpiod_get_optional(&pdev->dev, "sda", GPIOD_IN);
-       rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
-
-       if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
-           PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
-               return -EPROBE_DEFER;
-       } else if (IS_ERR(rinfo->sda_gpiod) ||
-                  IS_ERR(rinfo->scl_gpiod) ||
-                  IS_ERR(i2c_imx->pinctrl_pins_default) ||
-                  IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
-               dev_dbg(&pdev->dev, "recovery information incomplete\n");
-               return 0;
-       }
+       struct i2c_bus_recovery_info *bri = &i2c_imx->rinfo;
 
-       dev_dbg(&pdev->dev, "using scl%s for recovery\n",
-               rinfo->sda_gpiod ? ",sda" : "");
+       bri->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (IS_ERR(bri->pinctrl))
+               return PTR_ERR(bri->pinctrl);
 
-       rinfo->prepare_recovery = i2c_imx_prepare_recovery;
-       rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
-       rinfo->recover_bus = i2c_generic_scl_recovery;
-       i2c_imx->adapter.bus_recovery_info = rinfo;
+       i2c_imx->adapter.bus_recovery_info = bri;
 
        return 0;
 }
index e4e4995ab22430e0cdb50b19167feb3d638bb92a..8d73c0f405ed567ca980331d86ed56eee29d4f53 100644 (file)
@@ -30,8 +30,6 @@
 #include <asm/mpc85xx.h>
 #include <sysdev/fsl_soc.h>
 
-#define DRV_NAME "mpc-i2c"
-
 #define MPC_I2C_CLOCK_LEGACY   0
 #define MPC_I2C_CLOCK_PRESERVE (~0U)
 
@@ -844,14 +842,14 @@ static int fsl_i2c_probe(struct platform_device *op)
                        mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock);
        }
 
-       /*
-        * "fsl,timeout" has been marked as deprecated and, to maintain
-        * backward compatibility, we will only look for it if
-        * "i2c-scl-clk-low-timeout-us" is not present.
-        */
+       /* Sadly, we have to support two deprecated bindings here */
        result = of_property_read_u32(op->dev.of_node,
-                                     "i2c-scl-clk-low-timeout-us",
+                                     "i2c-transfer-timeout-us",
                                      &mpc_ops.timeout);
+       if (result == -EINVAL)
+               result = of_property_read_u32(op->dev.of_node,
+                                             "i2c-scl-clk-low-timeout-us",
+                                             &mpc_ops.timeout);
        if (result == -EINVAL)
                result = of_property_read_u32(op->dev.of_node,
                                              "fsl,timeout", &mpc_ops.timeout);
@@ -960,7 +958,7 @@ static struct platform_driver mpc_i2c_driver = {
        .probe          = fsl_i2c_probe,
        .remove_new     = fsl_i2c_remove,
        .driver = {
-               .name = DRV_NAME,
+               .name = "mpc-i2c",
                .of_match_table = mpc_i2c_of_match,
                .pm = &mpc_i2c_pm_ops,
        },
index 54181b3f1919625a83010efbb7b439f8fd2316b7..2fe68615942efeb3b3b6d8df28ac53a1a38d4136 100644 (file)
@@ -1264,9 +1264,6 @@ static int npcm_i2c_reg_slave(struct i2c_client *client)
 
        bus->slave = client;
 
-       if (!bus->slave)
-               return -EINVAL;
-
        if (client->flags & I2C_CLIENT_TEN)
                return -EAFNOSUPPORT;
 
index 5adbe62cf6212865aa6df5bb532f9def35196e4a..c65ac3d7eadc5b58c5d9e29d9a6ec0d894e2e844 100644 (file)
@@ -773,7 +773,7 @@ static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
        iic_wr(pd, ICCR, ICCR_TRS);
        udelay(10);
 
-       return sh_mobile_i2c_init(pd);
+       return sh_mobile_i2c_v2_init(pd);
 }
 
 static const struct sh_mobile_dt_config default_dt_config = {
@@ -782,11 +782,6 @@ static const struct sh_mobile_dt_config default_dt_config = {
 };
 
 static const struct sh_mobile_dt_config fast_clock_dt_config = {
-       .clks_per_count = 2,
-       .setup = sh_mobile_i2c_init,
-};
-
-static const struct sh_mobile_dt_config v2_freq_calc_dt_config = {
        .clks_per_count = 2,
        .setup = sh_mobile_i2c_v2_init,
 };
@@ -799,17 +794,17 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = {
 static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
        { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
-       { .compatible = "renesas,iic-r8a774c0", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a7793", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a7794", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a7795", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,iic-r8a77990", .data = &v2_freq_calc_dt_config },
+       { .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config },
        { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
-       { .compatible = "renesas,rcar-gen2-iic", .data = &v2_freq_calc_dt_config },
-       { .compatible = "renesas,rcar-gen3-iic", .data = &v2_freq_calc_dt_config },
+       { .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config },
+       { .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config },
        { .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
        {},
 };
index c52d1bec60b4cd4090c5acf11783e4cbc88ec308..28c88901d9bcd1db6e856983c8a81194e3eb163e 100644 (file)
@@ -570,7 +570,7 @@ err_rpm_put:
        return ret;
 }
 
-static int sprd_i2c_remove(struct platform_device *pdev)
+static void sprd_i2c_remove(struct platform_device *pdev)
 {
        struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev);
        int ret;
@@ -586,8 +586,6 @@ static int sprd_i2c_remove(struct platform_device *pdev)
 
        pm_runtime_put_noidle(i2c_dev->dev);
        pm_runtime_disable(i2c_dev->dev);
-
-       return 0;
 }
 
 static int __maybe_unused sprd_i2c_suspend_noirq(struct device *dev)
@@ -645,7 +643,7 @@ MODULE_DEVICE_TABLE(of, sprd_i2c_of_match);
 
 static struct platform_driver sprd_i2c_driver = {
        .probe = sprd_i2c_probe,
-       .remove = sprd_i2c_remove,
+       .remove_new = sprd_i2c_remove,
        .driver = {
                   .name = "sprd-i2c",
                   .of_match_table = sprd_i2c_of_match,
index 3bd48d4b6318fe1fe83e3718c59713f354ff9878..ff5c486a1dbb1fa4a17d0d3f74885a7e3a0a69ec 100644 (file)
@@ -701,7 +701,7 @@ const struct bus_type i2c_bus_type = {
 };
 EXPORT_SYMBOL_GPL(i2c_bus_type);
 
-struct device_type i2c_client_type = {
+const struct device_type i2c_client_type = {
        .groups         = i2c_dev_groups,
        .uevent         = i2c_device_uevent,
        .release        = i2c_client_dev_release,
@@ -1343,7 +1343,7 @@ static struct attribute *i2c_adapter_attrs[] = {
 };
 ATTRIBUTE_GROUPS(i2c_adapter);
 
-struct device_type i2c_adapter_type = {
+const struct device_type i2c_adapter_type = {
        .groups         = i2c_adapter_groups,
        .release        = i2c_adapter_dev_release,
 };
index 74807c6db596d810fffe035268875a61b1074881..97f338b123b11872402df5d84ef7c20ef33454f2 100644 (file)
@@ -351,13 +351,18 @@ void i2c_register_spd(struct i2c_adapter *adap)
        if (!dimm_count)
                return;
 
-       dev_info(&adap->dev, "%d/%d memory slots populated (from DMI)\n",
-                dimm_count, slot_count);
-
-       if (slot_count > 8) {
-               dev_warn(&adap->dev,
-                        "Systems with more than 8 memory slots not supported yet, not instantiating SPD\n");
-               return;
+       /*
+        * If we're a child adapter on a muxed segment, then limit slots to 8,
+        * as this is the max number of SPD EEPROMs that can be addressed per bus.
+        */
+       if (i2c_parent_is_i2c_adapter(adap)) {
+               slot_count = 8;
+       } else {
+               if (slot_count > 8) {
+                       dev_warn(&adap->dev,
+                                "More than 8 memory slots on a single bus, contact i801 maintainer to add missing mux config\n");
+                       return;
+               }
        }
 
        /*
index 2219062104fbca4fcd23b89012090c7c30602790..f5dfc33b97c0ab94dfee90ae29d81c69395f180b 100644 (file)
 
 #define PCA954X_IRQ_OFFSET 4
 
+/*
+ * MAX7357's configuration register is writeable after POR, but
+ * can be locked by setting the basic mode bit. MAX7358 configuration
+ * register is locked by default and needs to be unlocked first.
+ * The configuration register holds the following settings:
+ */
+#define MAX7357_CONF_INT_ENABLE                        BIT(0)
+#define MAX7357_CONF_FLUSH_OUT                 BIT(1)
+#define MAX7357_CONF_RELEASE_INT               BIT(2)
+#define MAX7357_CONF_DISCON_SINGLE_CHAN                BIT(4)
+#define MAX7357_CONF_PRECONNECT_TEST           BIT(7)
+
+#define MAX7357_POR_DEFAULT_CONF               MAX7357_CONF_INT_ENABLE
+
 enum pca_type {
        max_7356,
        max_7357,
@@ -470,7 +484,34 @@ static int pca954x_init(struct i2c_client *client, struct pca954x *data)
        else
                data->last_chan = 0; /* Disconnect multiplexer */
 
-       ret = i2c_smbus_write_byte(client, data->last_chan);
+       if (device_is_compatible(&client->dev, "maxim,max7357")) {
+               if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+                       u8 conf = MAX7357_POR_DEFAULT_CONF;
+                       /*
+                        * The interrupt signal is shared with the reset pin. Release the
+                        * interrupt after 1.6 seconds to allow using the pin as reset.
+                        */
+                       conf |= MAX7357_CONF_RELEASE_INT;
+
+                       if (device_property_read_bool(&client->dev, "maxim,isolate-stuck-channel"))
+                               conf |= MAX7357_CONF_DISCON_SINGLE_CHAN;
+                       if (device_property_read_bool(&client->dev,
+                                                     "maxim,send-flush-out-sequence"))
+                               conf |= MAX7357_CONF_FLUSH_OUT;
+                       if (device_property_read_bool(&client->dev,
+                                                     "maxim,preconnection-wiggle-test-enable"))
+                               conf |= MAX7357_CONF_PRECONNECT_TEST;
+
+                       ret = i2c_smbus_write_byte_data(client, data->last_chan, conf);
+               } else {
+                       dev_warn(&client->dev, "Write byte data not supported."
+                                "Cannot enable enhanced mode features\n");
+                       ret = i2c_smbus_write_byte(client, data->last_chan);
+               }
+       } else {
+               ret = i2c_smbus_write_byte(client, data->last_chan);
+       }
+
        if (ret < 0)
                data->last_chan = 0;
 
index 652ecb7abedae4b5bc3c451410139168702a63f9..5e6cd43a6dbdd9fcd29e30d59492c736a149e25a 100644 (file)
@@ -24,8 +24,8 @@
 #include <uapi/linux/i2c.h>
 
 extern const struct bus_type i2c_bus_type;
-extern struct device_type i2c_adapter_type;
-extern struct device_type i2c_client_type;
+extern const struct device_type i2c_adapter_type;
+extern const struct device_type i2c_client_type;
 
 /* --- General options ------------------------------------------------        */
 
@@ -931,7 +931,7 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
 
 static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
 {
-       return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
+       return (msg->addr << 1) | (msg->flags & I2C_M_RD);
 }
 
 u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold);