Merge remote-tracking branch 'i2c/i2c/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 00:34:37 +0000 (11:34 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 00:34:37 +0000 (11:34 +1100)
49 files changed:
Documentation/acpi/enumeration.txt
Documentation/acpi/i2c-muxes.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-davinci.txt
Documentation/devicetree/bindings/i2c/i2c-imx.txt
Documentation/devicetree/bindings/i2c/i2c-rcar.txt
Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-uniphier.txt [new file with mode: 0644]
Documentation/i2c/busses/i2c-i801
MAINTAINERS
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-img-scb.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/busses/i2c-meson.c
drivers/i2c/busses/i2c-mt65xx.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-pnx.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-sirf.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/busses/i2c-uniphier-f.c [new file with mode: 0644]
drivers/i2c/busses/i2c-uniphier.c [new file with mode: 0644]
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/i2c/i2c-mux.c
drivers/mfd/intel_quark_i2c_gpio.c
drivers/mfd/mfd-core.c
drivers/misc/eeprom/at24.c
fs/compat_ioctl.c
include/linux/acpi.h
include/linux/i2c-ocores.h
include/linux/i2c/i2c-rcar.h [deleted file]
include/linux/mfd/core.h
include/uapi/linux/i2c-dev.h

index b731b29..a91ec5a 100644 (file)
@@ -347,13 +347,18 @@ For the first case, the MFD drivers do not need to do anything. The
 resulting child platform device will have its ACPI_COMPANION() set to point
 to the parent device.
 
-If the ACPI namespace has a device that we can match using an ACPI id,
-the id should be set like:
+If the ACPI namespace has a device that we can match using an ACPI id or ACPI
+adr, the cell should be set like:
+
+       static struct mfd_cell_acpi_match my_subdevice_cell_acpi_match = {
+               .pnpid = "XYZ0001",
+               .adr = 0,
+       };
 
        static struct mfd_cell my_subdevice_cell = {
                .name = "my_subdevice",
                /* set the resources relative to the parent */
-               .acpi_pnpid = "XYZ0001",
+               .acpi_match = &my_subdevice_cell_acpi_match,
        };
 
 The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
diff --git a/Documentation/acpi/i2c-muxes.txt b/Documentation/acpi/i2c-muxes.txt
new file mode 100644 (file)
index 0000000..9fcc4f0
--- /dev/null
@@ -0,0 +1,58 @@
+ACPI I2C Muxes
+--------------
+
+Describing an I2C device hierarchy that includes I2C muxes requires an ACPI
+Device () scope per mux channel.
+
+Consider this topology:
+
++------+   +------+
+| SMB1 |-->| MUX0 |--CH00--> i2c client A (0x50)
+|      |   | 0x70 |--CH01--> i2c client B (0x50)
++------+   +------+
+
+which corresponds to the following ASL:
+
+Device (SMB1)
+{
+    Name (_HID, ...)
+    Device (MUX0)
+    {
+        Name (_HID, ...)
+        Name (_CRS, ResourceTemplate () {
+            I2cSerialBus (0x70, ControllerInitiated, I2C_SPEED,
+                          AddressingMode7Bit, "^SMB1", 0x00,
+                          ResourceConsumer,,)
+        }
+
+        Device (CH00)
+        {
+            Name (_ADR, 0)
+
+            Device (CLIA)
+            {
+                Name (_HID, ...)
+                Name (_CRS, ResourceTemplate () {
+                    I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
+                                  AddressingMode7Bit, "^CH00", 0x00,
+                                  ResourceConsumer,,)
+                }
+            }
+        }
+
+        Device (CH01)
+        {
+            Name (_ADR, 1)
+
+            Device (CLIB)
+            {
+                Name (_HID, ...)
+                Name (_CRS, ResourceTemplate () {
+                    I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
+                                  AddressingMode7Bit, "^CH01", 0x00,
+                                  ResourceConsumer,,)
+                }
+            }
+        }
+    }
+}
index a4e1cbc..5b123e0 100644 (file)
@@ -1,10 +1,10 @@
-* Texas Instruments Davinci I2C
+* Texas Instruments Davinci/Keystone I2C
 
 This file provides information, what the device node for the
-davinci i2c interface contain.
+davinci/keystone i2c interface contains.
 
 Required properties:
-- compatible: "ti,davinci-i2c";
+- compatible: "ti,davinci-i2c" or "ti,keystone-i2c";
 - reg : Offset and length of the register set for the device
 
 Recommended properties :
index ce4311d..eab5836 100644 (file)
@@ -14,6 +14,10 @@ Optional properties:
   The absence of the propoerty indicates the default frequency 100 kHz.
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
+- scl-gpios: specify the gpio related to SCL pin
+- sda-gpios: specify the gpio related to SDA pin
+- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c
+  bus recovery, call it "gpio" state
 
 Examples:
 
@@ -37,4 +41,9 @@ i2c0: i2c@40066000 { /* i2c0 on vf610 */
        dmas = <&edma0 0 50>,
                <&edma0 0 51>;
        dma-names = "rx","tx";
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_gpio>;
+       scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>;
+       sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
 };
index 16b3e07..ea406eb 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
        "renesas,i2c-r8a7792"
        "renesas,i2c-r8a7793"
        "renesas,i2c-r8a7794"
+       "renesas,i2c-r8a7795"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: interrupt specifier.
index 2bfc6e7..214f94c 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
                        - "renesas,iic-r8a7792" (R-Car V2H)
                        - "renesas,iic-r8a7793" (R-Car M2-N)
                        - "renesas,iic-r8a7794" (R-Car E2)
+                       - "renesas,iic-r8a7795" (R-Car H3)
                        - "renesas,iic-sh73a0" (SH-Mobile AG5)
 - reg             : address start and address range size of device
 - interrupts      : interrupt of device
diff --git a/Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt b/Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt
new file mode 100644 (file)
index 0000000..27fc6f8
--- /dev/null
@@ -0,0 +1,25 @@
+UniPhier I2C controller (FIFO-builtin)
+
+Required properties:
+- compatible: should be "socionext,uniphier-fi2c".
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- reg: offset and length of the register set for the device.
+- interrupts: a single interrupt specifier.
+- clocks: phandle to the input clock.
+
+Optional properties:
+- clock-frequency: desired I2C bus frequency in Hz.  The maximum supported
+  value is 400000.  Defaults to 100000 if not specified.
+
+Examples:
+
+       i2c0: i2c@58780000 {
+               compatible = "socionext,uniphier-fi2c";
+               reg = <0x58780000 0x80>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupts = <0 41 4>;
+               clocks = <&i2c_clk>;
+               clock-frequency = <100000>;
+       };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-uniphier.txt b/Documentation/devicetree/bindings/i2c/i2c-uniphier.txt
new file mode 100644 (file)
index 0000000..26f9d95
--- /dev/null
@@ -0,0 +1,25 @@
+UniPhier I2C controller (FIFO-less)
+
+Required properties:
+- compatible: should be "socionext,uniphier-i2c".
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- reg: offset and length of the register set for the device.
+- interrupts: a single interrupt specifier.
+- clocks: phandle to the input clock.
+
+Optional properties:
+- clock-frequency: desired I2C bus frequency in Hz.  The maximum supported
+  value is 400000.  Defaults to 100000 if not specified.
+
+Examples:
+
+       i2c0: i2c@58400000 {
+               compatible = "socionext,uniphier-i2c";
+               reg = <0x58400000 0x40>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupts = <0 41 1>;
+               clocks = <&i2c_clk>;
+               clock-frequency = <100000>;
+       };
index 82f48f7..6a4b1af 100644 (file)
@@ -30,6 +30,8 @@ Supported adapters:
   * Intel BayTrail (SOC)
   * Intel Sunrise Point-H (PCH)
   * Intel Sunrise Point-LP (PCH)
+  * Intel DNV (SOC)
+  * Intel Broxton (SOC)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index 73c952b..1e1c3f8 100644 (file)
@@ -1628,6 +1628,7 @@ F:        arch/arm/boot/dts/uniphier*
 F:     arch/arm/include/asm/hardware/cache-uniphier.h
 F:     arch/arm/mach-uniphier/
 F:     arch/arm/mm/cache-uniphier.c
+F:     drivers/i2c/busses/i2c-uniphier*
 F:     drivers/pinctrl/uniphier/
 F:     drivers/tty/serial/8250/8250_uniphier.c
 N:     uniphier
@@ -5150,6 +5151,7 @@ S:        Maintained
 F:     Documentation/devicetree/bindings/i2c/
 F:     Documentation/i2c/
 F:     drivers/i2c/
+F:     drivers/i2c/*/
 F:     include/linux/i2c.h
 F:     include/linux/i2c-*.h
 F:     include/uapi/linux/i2c.h
@@ -8359,12 +8361,6 @@ M:       "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
 S:     Maintained
 F:     drivers/pnp/
 
-PNXxxxx I2C DRIVER
-M:     Vitaly Wool <vitalywool@gmail.com>
-L:     linux-i2c@vger.kernel.org
-S:     Maintained
-F:     drivers/i2c/busses/i2c-pnx.c
-
 PPP PROTOCOL DRIVERS AND COMPRESSORS
 M:     Paul Mackerras <paulus@samba.org>
 L:     linux-ppp@vger.kernel.org
index 08b8617..e24c2b6 100644 (file)
@@ -124,6 +124,8 @@ config I2C_I801
            BayTrail (SOC)
            Sunrise Point-H (PCH)
            Sunrise Point-LP (PCH)
+           DNV (SOC)
+           Broxton (SOC)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -422,7 +424,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
 
 config I2C_CADENCE
        tristate "Cadence I2C Controller"
-       depends on ARCH_ZYNQ
+       depends on ARCH_ZYNQ || ARM64
        help
          Say yes here to select Cadence I2C Host Controller. This controller is
          e.g. used by Xilinx Zynq.
@@ -582,10 +584,10 @@ config I2C_IMG
 
 config I2C_IMX
        tristate "IMX I2C interface"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || ARCH_LAYERSCAPE
        help
          Say Y here if you want to use the IIC bus controller on
-         the Freescale i.MX/MXC processors.
+         the Freescale i.MX/MXC or Layerscape processors.
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-imx.
@@ -902,6 +904,22 @@ config I2C_TEGRA
          If you say yes to this option, support will be included for the
          I2C controller embedded in NVIDIA Tegra SOCs
 
+config I2C_UNIPHIER
+       tristate "UniPhier FIFO-less I2C controller"
+       depends on ARCH_UNIPHIER
+       help
+         If you say yes to this option, support will be included for
+         the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8,
+         or older UniPhier SoCs.
+
+config I2C_UNIPHIER_F
+       tristate "UniPhier FIFO-builtin I2C controller"
+       depends on ARCH_UNIPHIER
+       help
+         If you say yes to this option, support will be included for
+         the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4,
+         PH1-Pro5, or newer UniPhier SoCs.
+
 config I2C_VERSATILE
        tristate "ARM Versatile/Realview I2C bus support"
        depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
index 6df3b30..37f2819 100644 (file)
@@ -87,6 +87,8 @@ obj-$(CONFIG_I2C_ST)          += i2c-st.o
 obj-$(CONFIG_I2C_STU300)       += i2c-stu300.o
 obj-$(CONFIG_I2C_SUN6I_P2WI)   += i2c-sun6i-p2wi.o
 obj-$(CONFIG_I2C_TEGRA)                += i2c-tegra.o
+obj-$(CONFIG_I2C_UNIPHIER)     += i2c-uniphier.o
+obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)    += i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)          += i2c-wmt.o
 obj-$(CONFIG_I2C_OCTEON)       += i2c-octeon.o
index 1c758cd..10835d1 100644 (file)
@@ -347,8 +347,14 @@ error:
 
 static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
 {
-       if (!dev->buf_len)
+       /*
+        * If we are in this case, it means there is garbage data in RHR, so
+        * delete them.
+        */
+       if (!dev->buf_len) {
+               at91_twi_read(dev, AT91_TWI_RHR);
                return;
+       }
 
        /* 8bit read works with and without FIFO */
        *dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR);
@@ -465,19 +471,73 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
 
        if (!irqstatus)
                return IRQ_NONE;
-       else if (irqstatus & AT91_TWI_RXRDY)
+       /*
+        * In reception, the behavior of the twi device (before sama5d2) is
+        * weird. There is some magic about RXRDY flag! When a data has been
+        * almost received, the reception of a new one is anticipated if there
+        * is no stop command to send. That is the reason why ask for sending
+        * the stop command not on the last data but on the second last one.
+        *
+        * Unfortunately, we could still have the RXRDY flag set even if the
+        * transfer is done and we have read the last data. It might happen
+        * when the i2c slave device sends too quickly data after receiving the
+        * ack from the master. The data has been almost received before having
+        * the order to send stop. In this case, sending the stop command could
+        * cause a RXRDY interrupt with a TXCOMP one. It is better to manage
+        * the RXRDY interrupt first in order to not keep garbage data in the
+        * Receive Holding Register for the next transfer.
+        */
+       if (irqstatus & AT91_TWI_RXRDY)
                at91_twi_read_next_byte(dev);
-       else if (irqstatus & AT91_TWI_TXRDY)
-               at91_twi_write_next_byte(dev);
-
-       /* catch error flags */
-       dev->transfer_status |= status;
 
+       /*
+        * When a NACK condition is detected, the I2C controller sets the NACK,
+        * TXCOMP and TXRDY bits all together in the Status Register (SR).
+        *
+        * 1 - Handling NACK errors with CPU write transfer.
+        *
+        * In such case, we should not write the next byte into the Transmit
+        * Holding Register (THR) otherwise the I2C controller would start a new
+        * transfer and the I2C slave is likely to reply by another NACK.
+        *
+        * 2 - Handling NACK errors with DMA write transfer.
+        *
+        * By setting the TXRDY bit in the SR, the I2C controller also triggers
+        * the DMA controller to write the next data into the THR. Then the
+        * result depends on the hardware version of the I2C controller.
+        *
+        * 2a - Without support of the Alternative Command mode.
+        *
+        * This is the worst case: the DMA controller is triggered to write the
+        * next data into the THR, hence starting a new transfer: the I2C slave
+        * is likely to reply by another NACK.
+        * Concurrently, this interrupt handler is likely to be called to manage
+        * the first NACK before the I2C controller detects the second NACK and
+        * sets once again the NACK bit into the SR.
+        * When handling the first NACK, this interrupt handler disables the I2C
+        * controller interruptions, especially the NACK interrupt.
+        * Hence, the NACK bit is pending into the SR. This is why we should
+        * read the SR to clear all pending interrupts at the beginning of
+        * at91_do_twi_transfer() before actually starting a new transfer.
+        *
+        * 2b - With support of the Alternative Command mode.
+        *
+        * When a NACK condition is detected, the I2C controller also locks the
+        * THR (and sets the LOCK bit in the SR): even though the DMA controller
+        * is triggered by the TXRDY bit to write the next data into the THR,
+        * this data actually won't go on the I2C bus hence a second NACK is not
+        * generated.
+        */
        if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) {
                at91_disable_twi_interrupts(dev);
                complete(&dev->cmd_complete);
+       } else if (irqstatus & AT91_TWI_TXRDY) {
+               at91_twi_write_next_byte(dev);
        }
 
+       /* catch error flags */
+       dev->transfer_status |= status;
+
        return IRQ_HANDLED;
 }
 
@@ -537,6 +597,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
        reinit_completion(&dev->cmd_complete);
        dev->transfer_status = 0;
 
+       /* Clear pending interrupts, such as NACK. */
+       at91_twi_read(dev, AT91_TWI_SR);
+
        if (dev->fifo_size) {
                unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR);
 
@@ -558,11 +621,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
        } else if (dev->msg->flags & I2C_M_RD) {
                unsigned start_flags = AT91_TWI_START;
 
-               if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
-                       dev_err(dev->dev, "RXRDY still set!");
-                       at91_twi_read(dev, AT91_TWI_RHR);
-               }
-
                /* if only one byte is to be read, immediately stop transfer */
                if (!has_alt_cmd && dev->buf_len <= 1 &&
                    !(dev->msg->flags & I2C_M_RECV_LEN))
index a6aae84..5bcb1f0 100644 (file)
@@ -48,7 +48,6 @@ struct i2c_au1550_data {
        void __iomem *psc_base;
        int     xfer_timeout;
        struct i2c_adapter adap;
-       struct resource *ioarea;
 };
 
 static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
@@ -284,10 +283,10 @@ static void i2c_au1550_setup(struct i2c_au1550_data *priv)
        /* Set the protocol timer values.  See Table 71 in the
         * Au1550 Data Book for standard timing values.
         */
-       WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
-               PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
-               PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
-               PSC_SMBTMR_SET_CH(15));
+       WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(20) | \
+               PSC_SMBTMR_SET_PU(20) | PSC_SMBTMR_SET_SH(20) | \
+               PSC_SMBTMR_SET_SU(20) | PSC_SMBTMR_SET_CL(20) | \
+               PSC_SMBTMR_SET_CH(20));
 
        cfg |= PSC_SMBCFG_DE_ENABLE;
        WR(priv, PSC_SMBCFG, cfg);
@@ -315,30 +314,16 @@ i2c_au1550_probe(struct platform_device *pdev)
        struct resource *r;
        int ret;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r) {
-               ret = -ENODEV;
-               goto out;
-       }
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
-       priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
-       if (!priv) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       priv->ioarea = request_mem_region(r->start, resource_size(r),
-                                         pdev->name);
-       if (!priv->ioarea) {
-               ret = -EBUSY;
-               goto out_mem;
-       }
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(priv->psc_base))
+               return PTR_ERR(priv->psc_base);
 
-       priv->psc_base = ioremap(r->start, resource_size(r));
-       if (!priv->psc_base) {
-               ret = -EIO;
-               goto out_map;
-       }
        priv->xfer_timeout = 200;
 
        priv->adap.nr = pdev->id;
@@ -351,20 +336,13 @@ i2c_au1550_probe(struct platform_device *pdev)
        i2c_au1550_setup(priv);
 
        ret = i2c_add_numbered_adapter(&priv->adap);
-       if (ret == 0) {
-               platform_set_drvdata(pdev, priv);
-               return 0;
+       if (ret) {
+               i2c_au1550_disable(priv);
+               return ret;
        }
 
-       i2c_au1550_disable(priv);
-       iounmap(priv->psc_base);
-out_map:
-       release_resource(priv->ioarea);
-       kfree(priv->ioarea);
-out_mem:
-       kfree(priv);
-out:
-       return ret;
+       platform_set_drvdata(pdev, priv);
+       return 0;
 }
 
 static int i2c_au1550_remove(struct platform_device *pdev)
@@ -373,10 +351,6 @@ static int i2c_au1550_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&priv->adap);
        i2c_au1550_disable(priv);
-       iounmap(priv->psc_base);
-       release_resource(priv->ioarea);
-       kfree(priv->ioarea);
-       kfree(priv);
        return 0;
 }
 
index 3fbb9a0..c5628a4 100644 (file)
@@ -181,6 +181,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
        u32 clkh;
        u32 clkl;
        u32 input_clock = clk_get_rate(dev->clk);
+       struct device_node *of_node = dev->dev->of_node;
 
        /* NOTE: I2C Clock divider programming info
         * As per I2C specs the following formulas provide prescaler
@@ -196,6 +197,9 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
         * where if PSC == 0, d = 7,
         *       if PSC == 1, d = 6
         *       if PSC > 1 , d = 5
+        *
+        * Note:
+        * d is always 6 on Keystone I2C controller
         */
 
        /* get minimum of 7 MHz clock, but max of 12 MHz */
@@ -204,6 +208,9 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
                psc++;  /* better to run under spec than over */
        d = (psc >= 2) ? 5 : 7 - psc;
 
+       if (of_node && of_device_is_compatible(of_node, "ti,keystone-i2c"))
+               d = 6;
+
        clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000));
        /* Avoid driving the bus too fast because of rounding errors above */
        if (input_clock / (psc + 1) / clk > pdata->bus_freq * 1000)
@@ -726,6 +733,7 @@ static struct i2c_algorithm i2c_davinci_algo = {
 
 static const struct of_device_id davinci_i2c_of_match[] = {
        {.compatible = "ti,davinci-i2c", },
+       {.compatible = "ti,keystone-i2c", },
        {},
 };
 MODULE_DEVICE_TABLE(of, davinci_i2c_of_match);
index 7441cdc..8c48b27 100644 (file)
@@ -165,7 +165,7 @@ static char *abort_sources[] = {
                "lost arbitration",
 };
 
-u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+static u32 dw_readl(struct dw_i2c_dev *dev, int offset)
 {
        u32 value;
 
@@ -181,7 +181,7 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
                return value;
 }
 
-void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
 {
        if (dev->accessor_flags & ACCESS_SWAP)
                b = swab32(b);
@@ -438,7 +438,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
        __i2c_dw_enable(dev, true);
 
        /* Clear and enable interrupts */
-       i2c_dw_clear_int(dev);
+       dw_readl(dev, DW_IC_CLR_INTR);
        dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
 }
 
@@ -618,7 +618,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
 /*
  * Prepare controller for a transaction and call i2c_dw_xfer_msg
  */
-int
+static int
 i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
        struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
@@ -702,14 +702,17 @@ done_nolock:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(i2c_dw_xfer);
 
-u32 i2c_dw_func(struct i2c_adapter *adap)
+static u32 i2c_dw_func(struct i2c_adapter *adap)
 {
        struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
        return dev->functionality;
 }
-EXPORT_SYMBOL_GPL(i2c_dw_func);
+
+static struct i2c_algorithm i2c_dw_algo = {
+       .master_xfer    = i2c_dw_xfer,
+       .functionality  = i2c_dw_func,
+};
 
 static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
 {
@@ -770,7 +773,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
  * Interrupt service routine. This gets called whenever an I2C interrupt
  * occurs.
  */
-irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 {
        struct dw_i2c_dev *dev = dev_id;
        u32 stat, enabled;
@@ -813,20 +816,6 @@ tx_aborted:
 
        return IRQ_HANDLED;
 }
-EXPORT_SYMBOL_GPL(i2c_dw_isr);
-
-void i2c_dw_enable(struct dw_i2c_dev *dev)
-{
-       /* Enable the adapter */
-       __i2c_dw_enable(dev, true);
-}
-EXPORT_SYMBOL_GPL(i2c_dw_enable);
-
-u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
-{
-       return dw_readl(dev, DW_IC_ENABLE);
-}
-EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
 
 void i2c_dw_disable(struct dw_i2c_dev *dev)
 {
@@ -839,12 +828,6 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
 }
 EXPORT_SYMBOL_GPL(i2c_dw_disable);
 
-void i2c_dw_clear_int(struct dw_i2c_dev *dev)
-{
-       dw_readl(dev, DW_IC_CLR_INTR);
-}
-EXPORT_SYMBOL_GPL(i2c_dw_clear_int);
-
 void i2c_dw_disable_int(struct dw_i2c_dev *dev)
 {
        dw_writel(dev, 0, DW_IC_INTR_MASK);
@@ -857,5 +840,40 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
 }
 EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
 
+int i2c_dw_probe(struct dw_i2c_dev *dev)
+{
+       struct i2c_adapter *adap = &dev->adapter;
+       int r;
+
+       init_completion(&dev->cmd_complete);
+       mutex_init(&dev->lock);
+
+       r = i2c_dw_init(dev);
+       if (r)
+               return r;
+
+       snprintf(adap->name, sizeof(adap->name),
+                "Synopsys DesignWare I2C adapter");
+       adap->algo = &i2c_dw_algo;
+       adap->dev.parent = dev->dev;
+       i2c_set_adapdata(adap, dev);
+
+       i2c_dw_disable_int(dev);
+       r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
+                            dev_name(dev->dev), dev);
+       if (r) {
+               dev_err(dev->dev, "failure requesting irq %i: %d\n",
+                       dev->irq, r);
+               return r;
+       }
+
+       r = i2c_add_numbered_adapter(adap);
+       if (r)
+               dev_err(dev->dev, "failure adding adapter: %d\n", r);
+
+       return r;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_probe);
+
 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
 MODULE_LICENSE("GPL");
index 9630222..1d50898 100644 (file)
@@ -112,19 +112,11 @@ struct dw_i2c_dev {
 #define ACCESS_SWAP            0x00000001
 #define ACCESS_16BIT           0x00000002
 
-extern u32 dw_readl(struct dw_i2c_dev *dev, int offset);
-extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
 extern int i2c_dw_init(struct dw_i2c_dev *dev);
-extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
-               int num);
-extern u32 i2c_dw_func(struct i2c_adapter *adap);
-extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
-extern void i2c_dw_enable(struct dw_i2c_dev *dev);
-extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
 extern void i2c_dw_disable(struct dw_i2c_dev *dev);
-extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
 extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
 extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
+extern int i2c_dw_probe(struct dw_i2c_dev *dev);
 
 #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
 extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
index df23e8c..1543d35 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <linux/acpi.h>
 #include "i2c-designware-core.h"
 
 #define DRIVER_NAME "i2c-designware-pci"
@@ -158,11 +159,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
        },
 };
 
-static struct i2c_algorithm i2c_dw_algo = {
-       .master_xfer    = i2c_dw_xfer,
-       .functionality  = i2c_dw_func,
-};
-
 #ifdef CONFIG_PM
 static int i2c_dw_pci_suspend(struct device *dev)
 {
@@ -222,13 +218,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
        if (!dev)
                return -ENOMEM;
 
-       init_completion(&dev->cmd_complete);
-       mutex_init(&dev->lock);
        dev->clk = NULL;
        dev->controller = controller;
        dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
        dev->base = pcim_iomap_table(pdev)[0];
        dev->dev = &pdev->dev;
+       dev->irq = pdev->irq;
        dev->functionality = controller->functionality |
                                DW_DEFAULT_FUNCTIONALITY;
 
@@ -246,34 +241,16 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
 
        dev->tx_fifo_depth = controller->tx_fifo_depth;
        dev->rx_fifo_depth = controller->rx_fifo_depth;
-       r = i2c_dw_init(dev);
-       if (r)
-               return r;
 
        adap = &dev->adapter;
-       i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
        adap->class = 0;
-       adap->algo = &i2c_dw_algo;
-       adap->dev.parent = &pdev->dev;
+       ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
        adap->nr = controller->bus_num;
 
-       snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
-
-       r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr,
-                       IRQF_SHARED | IRQF_COND_SUSPEND, adap->name, dev);
-       if (r) {
-               dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
-               return r;
-       }
-
-       i2c_dw_disable_int(dev);
-       i2c_dw_clear_int(dev);
-       r = i2c_add_numbered_adapter(adap);
-       if (r) {
-               dev_err(&pdev->dev, "failure adding adapter\n");
+       r = i2c_dw_probe(dev);
+       if (r)
                return r;
-       }
 
        pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
        pm_runtime_use_autosuspend(&pdev->dev);
index 472b882..809579e 100644 (file)
 #include <linux/platform_data/i2c-designware.h>
 #include "i2c-designware-core.h"
 
-static struct i2c_algorithm i2c_dw_algo = {
-       .master_xfer    = i2c_dw_xfer,
-       .functionality  = i2c_dw_func,
-};
 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
 {
        return clk_get_rate(dev->clk)/1000;
@@ -97,7 +93,6 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
 static int dw_i2c_acpi_configure(struct platform_device *pdev)
 {
        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
-       const struct acpi_device_id *id;
 
        dev->adapter.nr = -1;
        dev->tx_fifo_depth = 32;
@@ -111,29 +106,9 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
        dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
                           &dev->sda_hold_time);
 
-       /*
-        * Provide a way for Designware I2C host controllers that are not
-        * based on Intel LPSS to specify their input clock frequency via
-        * id->driver_data.
-        */
-       id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
-       if (id && id->driver_data)
-               clk_register_fixed_rate(&pdev->dev, dev_name(&pdev->dev), NULL,
-                                       CLK_IS_ROOT, id->driver_data);
-
        return 0;
 }
 
-static void dw_i2c_acpi_unconfigure(struct platform_device *pdev)
-{
-       struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
-       const struct acpi_device_id *id;
-
-       id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
-       if (id && id->driver_data)
-               clk_unregister(dev->clk);
-}
-
 static const struct acpi_device_id dw_i2c_acpi_match[] = {
        { "INT33C2", 0 },
        { "INT33C3", 0 },
@@ -141,7 +116,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
        { "INT3433", 0 },
        { "80860F41", 0 },
        { "808622C1", 0 },
-       { "AMD0010", 133 * 1000 * 1000 },
+       { "AMD0010", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
@@ -150,10 +125,9 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
 {
        return -ENODEV;
 }
-static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { }
 #endif
 
-static int dw_i2c_probe(struct platform_device *pdev)
+static int dw_i2c_plat_probe(struct platform_device *pdev)
 {
        struct dw_i2c_dev *dev;
        struct i2c_adapter *adap;
@@ -175,8 +149,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
        if (IS_ERR(dev->base))
                return PTR_ERR(dev->base);
 
-       init_completion(&dev->cmd_complete);
-       mutex_init(&dev->lock);
        dev->dev = &pdev->dev;
        dev->irq = irq;
        platform_set_drvdata(pdev, dev);
@@ -251,26 +223,11 @@ static int dw_i2c_probe(struct platform_device *pdev)
                dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
                dev->adapter.nr = pdev->id;
        }
-       r = i2c_dw_init(dev);
-       if (r)
-               return r;
-
-       i2c_dw_disable_int(dev);
-       r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
-                       pdev->name, dev);
-       if (r) {
-               dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
-               return r;
-       }
 
        adap = &dev->adapter;
-       i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
        adap->class = I2C_CLASS_DEPRECATED;
-       strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
-                       sizeof(adap->name));
-       adap->algo = &i2c_dw_algo;
-       adap->dev.parent = &pdev->dev;
+       ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
        adap->dev.of_node = pdev->dev.of_node;
 
        if (dev->pm_runtime_disabled) {
@@ -282,9 +239,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
                pm_runtime_enable(&pdev->dev);
        }
 
-       r = i2c_add_numbered_adapter(adap);
+       r = i2c_dw_probe(dev);
        if (r) {
-               dev_err(&pdev->dev, "failure adding adapter\n");
                pm_runtime_disable(&pdev->dev);
                return r;
        }
@@ -292,7 +248,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int dw_i2c_remove(struct platform_device *pdev)
+static int dw_i2c_plat_remove(struct platform_device *pdev)
 {
        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 
@@ -306,9 +262,6 @@ static int dw_i2c_remove(struct platform_device *pdev)
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-       if (has_acpi_companion(&pdev->dev))
-               dw_i2c_acpi_unconfigure(pdev);
-
        return 0;
 }
 
@@ -321,23 +274,23 @@ MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
 #endif
 
 #ifdef CONFIG_PM_SLEEP
-static int dw_i2c_prepare(struct device *dev)
+static int dw_i2c_plat_prepare(struct device *dev)
 {
        return pm_runtime_suspended(dev);
 }
 
-static void dw_i2c_complete(struct device *dev)
+static void dw_i2c_plat_complete(struct device *dev)
 {
        if (dev->power.direct_complete)
                pm_request_resume(dev);
 }
 #else
-#define dw_i2c_prepare NULL
-#define dw_i2c_complete        NULL
+#define dw_i2c_plat_prepare    NULL
+#define dw_i2c_plat_complete   NULL
 #endif
 
 #ifdef CONFIG_PM
-static int dw_i2c_suspend(struct device *dev)
+static int dw_i2c_plat_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -348,7 +301,7 @@ static int dw_i2c_suspend(struct device *dev)
        return 0;
 }
 
-static int dw_i2c_resume(struct device *dev)
+static int dw_i2c_plat_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -362,10 +315,10 @@ static int dw_i2c_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
-       .prepare = dw_i2c_prepare,
-       .complete = dw_i2c_complete,
-       SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_suspend, dw_i2c_resume)
-       SET_RUNTIME_PM_OPS(dw_i2c_suspend, dw_i2c_resume, NULL)
+       .prepare = dw_i2c_plat_prepare,
+       .complete = dw_i2c_plat_complete,
+       SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
+       SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
 };
 
 #define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
@@ -377,8 +330,8 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
 MODULE_ALIAS("platform:i2c_designware");
 
 static struct platform_driver dw_i2c_driver = {
-       .probe = dw_i2c_probe,
-       .remove = dw_i2c_remove,
+       .probe = dw_i2c_plat_probe,
+       .remove = dw_i2c_plat_remove,
        .driver         = {
                .name   = "i2c_designware",
                .of_match_table = of_match_ptr(dw_i2c_of_match),
index eaef9bc..c306751 100644 (file)
@@ -60,6 +60,8 @@
  * BayTrail (SOC)              0x0f12  32      hard    yes     yes     yes
  * Sunrise Point-H (PCH)       0xa123  32      hard    yes     yes     yes
  * Sunrise Point-LP (PCH)      0x9d23  32      hard    yes     yes     yes
+ * DNV (SOC)                   0x19df  32      hard    yes     yes     yes
+ * Broxton (SOC)               0x5ad4  32      hard    yes     yes     yes
  *
  * Features supported by this driver:
  * Software PEC                                no
 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS      0x9ca2
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS       0xa123
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS      0x9d23
+#define PCI_DEVICE_ID_INTEL_DNV_SMBUS                  0x19df
+#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS              0x5ad4
 
 struct i801_mux_config {
        char *gpio_chip;
@@ -863,6 +867,8 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
        { 0, }
 };
 
@@ -1251,11 +1257,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
        priv->adapter.owner = THIS_MODULE;
        priv->adapter.class = i801_get_adapter_class(priv);
        priv->adapter.algo = &smbus_algorithm;
+       priv->adapter.dev.parent = &dev->dev;
+       ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
+       priv->adapter.retries = 3;
 
        priv->pci_dev = dev;
        switch (dev->device) {
        case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
        case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
+       case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
                priv->features |= FEATURE_I2C_BLOCK_READ;
                priv->features |= FEATURE_IRQ;
                priv->features |= FEATURE_SMBUS_PEC;
@@ -1381,12 +1391,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        i801_add_tco(priv);
 
-       /* set up the sysfs linkage to our parent device */
-       priv->adapter.dev.parent = &dev->dev;
-
-       /* Retry up to 3 times on lost arbitration */
-       priv->adapter.retries = 3;
-
        snprintf(priv->adapter.name, sizeof(priv->adapter.name),
                "SMBus I801 adapter at %04lx", priv->smba);
        err = i2c_add_adapter(&priv->adapter);
index 722f839..ab49230 100644 (file)
@@ -798,6 +798,7 @@ static const struct of_device_id ibm_iic_match[] = {
        { .compatible = "ibm,iic", },
        {}
 };
+MODULE_DEVICE_TABLE(of, ibm_iic_match);
 
 static struct platform_driver ibm_iic_driver = {
        .driver = {
index 00ffd66..3795fe1 100644 (file)
 #define ISR_COMPLETE(err)      (ISR_COMPLETE_M | (ISR_STATUS_M & (err)))
 #define ISR_FATAL(err)         (ISR_COMPLETE(err) | ISR_FATAL_M)
 
-#define REL_SOC_IP_SCB_2_2_1   0x00020201
-
 enum img_i2c_mode {
        MODE_INACTIVE,
        MODE_RAW,
@@ -536,6 +534,7 @@ static void img_i2c_read_fifo(struct img_i2c *i2c)
                u32 fifo_status;
                u8 data;
 
+               img_i2c_wr_rd_fence(i2c);
                fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
                if (fifo_status & FIFO_READ_EMPTY)
                        break;
@@ -544,7 +543,6 @@ static void img_i2c_read_fifo(struct img_i2c *i2c)
                *i2c->msg.buf = data;
 
                img_i2c_writel(i2c, SCB_READ_FIFO_REG, 0xff);
-               img_i2c_wr_rd_fence(i2c);
                i2c->msg.len--;
                i2c->msg.buf++;
        }
@@ -556,12 +554,12 @@ static void img_i2c_write_fifo(struct img_i2c *i2c)
        while (i2c->msg.len) {
                u32 fifo_status;
 
+               img_i2c_wr_rd_fence(i2c);
                fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
                if (fifo_status & FIFO_WRITE_FULL)
                        break;
 
                img_i2c_writel(i2c, SCB_WRITE_DATA_REG, *i2c->msg.buf);
-               img_i2c_wr_rd_fence(i2c);
                i2c->msg.len--;
                i2c->msg.buf++;
        }
@@ -859,7 +857,7 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c,
        }
 
        /* Enable transaction halt on start bit */
-       if (!i2c->last_msg && i2c->line_status & LINESTAT_START_BIT_DET) {
+       if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) {
                img_i2c_transaction_halt(i2c, true);
                /* we're no longer interested in the slave event */
                i2c->int_enable &= ~INT_SLAVE_EVENT;
@@ -1062,6 +1060,15 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                i2c->last_msg = (i == num - 1);
                reinit_completion(&i2c->msg_complete);
 
+               /*
+                * Clear line status and all interrupts before starting a
+                * transfer, as we may have unserviced interrupts from
+                * previous transfers that might be handled in the context
+                * of the new transfer.
+                */
+               img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
+               img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
+
                if (atomic)
                        img_i2c_atomic_start(i2c);
                else if (msg->flags & I2C_M_RD)
@@ -1120,13 +1127,8 @@ static int img_i2c_init(struct img_i2c *i2c)
                return -EINVAL;
        }
 
-       if (rev == REL_SOC_IP_SCB_2_2_1) {
-               i2c->need_wr_rd_fence = true;
-               dev_info(i2c->adap.dev.parent, "fence quirk enabled");
-       }
-
-       bitrate_khz = i2c->bitrate / 1000;
-       clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
+       /* Fencing enabled by default. */
+       i2c->need_wr_rd_fence = true;
 
        /* Determine what mode we're in from the bitrate */
        timing = timings[0];
@@ -1136,6 +1138,17 @@ static int img_i2c_init(struct img_i2c *i2c)
                        break;
                }
        }
+       if (i2c->bitrate > timings[ARRAY_SIZE(timings) - 1].max_bitrate) {
+               dev_warn(i2c->adap.dev.parent,
+                        "requested bitrate (%u) is higher than the max bitrate supported (%u)\n",
+                        i2c->bitrate,
+                        timings[ARRAY_SIZE(timings) - 1].max_bitrate);
+               timing = timings[ARRAY_SIZE(timings) - 1];
+               i2c->bitrate = timing.max_bitrate;
+       }
+
+       bitrate_khz = i2c->bitrate / 1000;
+       clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
 
        /* Find the prescale that would give us that inc (approx delay = 0) */
        prescale = SCB_OPT_INC * clk_khz / (256 * 16 * bitrate_khz);
@@ -1182,32 +1195,32 @@ static int img_i2c_init(struct img_i2c *i2c)
            ((bitrate_khz * clk_period) / 2))
                int_bitrate++;
 
-       /* Setup TCKH value */
-       tckh = timing.tckh / clk_period;
-       if (timing.tckh % clk_period)
-               tckh++;
+       /*
+        * Setup clock duty cycle, start with 50% and adjust TCKH and TCKL
+        * values from there if they don't meet minimum timing requirements
+        */
+       tckh = int_bitrate / 2;
+       tckl = int_bitrate - tckh;
 
-       if (tckh > 0)
-               data = tckh - 1;
-       else
-               data = 0;
+       /* Adjust TCKH and TCKL values */
+       data = DIV_ROUND_UP(timing.tckl, clk_period);
 
-       img_i2c_writel(i2c, SCB_TIME_TCKH_REG, data);
+       if (tckl < data) {
+               tckl = data;
+               tckh = int_bitrate - tckl;
+       }
 
-       /* Setup TCKL value */
-       tckl = int_bitrate - tckh;
+       if (tckh > 0)
+               --tckh;
 
        if (tckl > 0)
-               data = tckl - 1;
-       else
-               data = 0;
+               --tckl;
 
-       img_i2c_writel(i2c, SCB_TIME_TCKL_REG, data);
+       img_i2c_writel(i2c, SCB_TIME_TCKH_REG, tckh);
+       img_i2c_writel(i2c, SCB_TIME_TCKL_REG, tckl);
 
        /* Setup TSDH value */
-       tsdh = timing.tsdh / clk_period;
-       if (timing.tsdh % clk_period)
-               tsdh++;
+       tsdh = DIV_ROUND_UP(timing.tsdh, clk_period);
 
        if (tsdh > 1)
                data = tsdh - 1;
index 785aa67..1e4d99d 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_data/i2c-imx.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
@@ -207,6 +208,11 @@ struct imx_i2c_struct {
        unsigned int            cur_clk;
        unsigned int            bitrate;
        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;
 };
@@ -461,7 +467,7 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
 {
        if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) {
                dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
-               return -EIO;  /* No ACK */
+               return -ENXIO;  /* No ACK */
        }
 
        dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
@@ -896,6 +902,13 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
 
        /* Start I2C transfer */
        result = i2c_imx_start(i2c_imx);
+       if (result) {
+               if (i2c_imx->adapter.bus_recovery_info) {
+                       i2c_recover_bus(&i2c_imx->adapter);
+                       result = i2c_imx_start(i2c_imx);
+               }
+       }
+
        if (result)
                goto fail0;
 
@@ -956,6 +969,55 @@ fail0:
        return (result < 0) ? result : num;
 }
 
+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);
+}
+
+static void 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_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_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+                       "sda-gpios", 0, NULL);
+       rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+                       "scl-gpios", 0, NULL);
+
+       if (!gpio_is_valid(rinfo->sda_gpio) ||
+           !gpio_is_valid(rinfo->scl_gpio) ||
+           IS_ERR(i2c_imx->pinctrl_pins_default) ||
+           IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
+               dev_dbg(&pdev->dev, "recovery information incomplete\n");
+               return;
+       }
+
+       dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
+                       rinfo->sda_gpio, rinfo->scl_gpio);
+
+       rinfo->prepare_recovery = i2c_imx_prepare_recovery;
+       rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
+       rinfo->recover_bus = i2c_generic_gpio_recovery;
+       i2c_imx->adapter.bus_recovery_info = rinfo;
+}
+
 static u32 i2c_imx_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@@ -1023,6 +1085,13 @@ static int i2c_imx_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "can't enable I2C clock\n");
                return ret;
        }
+
+       i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (IS_ERR(i2c_imx->pinctrl)) {
+               ret = PTR_ERR(i2c_imx->pinctrl);
+               goto clk_disable;
+       }
+
        /* Request IRQ */
        ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
                                pdev->name, i2c_imx);
@@ -1056,6 +1125,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
+       i2c_imx_init_recovery_info(i2c_imx, pdev);
+
        /* Set up platform driver data */
        platform_set_drvdata(pdev, i2c_imx);
        clk_disable_unprepare(i2c_imx->clk);
index 39becbb..7ba795b 100644 (file)
@@ -165,14 +165,13 @@ struct ismt_desc {
 
 struct ismt_priv {
        struct i2c_adapter adapter;
-       void *smba;                             /* PCI BAR */
+       void __iomem *smba;                     /* PCI BAR */
        struct pci_dev *pci_dev;
        struct ismt_desc *hw;                   /* descriptor virt base addr */
        dma_addr_t io_rng_dma;                  /* descriptor HW base addr */
        u8 head;                                /* ring buffer head pointer */
        struct completion cmp;                  /* interrupt completion */
        u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */
-       bool using_msi;                         /* type of interrupt flag */
 };
 
 /**
@@ -398,7 +397,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
        desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
 
        /* Initialize common control bits */
-       if (likely(priv->using_msi))
+       if (likely(pci_dev_msi_enabled(priv->pci_dev)))
                desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
        else
                desc->control = ISMT_DESC_FAIR;
@@ -789,11 +788,8 @@ static int ismt_int_init(struct ismt_priv *priv)
 
        /* Try using MSI interrupts */
        err = pci_enable_msi(priv->pci_dev);
-       if (err) {
-               dev_warn(&priv->pci_dev->dev,
-                        "Unable to use MSI interrupts, falling back to legacy\n");
+       if (err)
                goto intx;
-       }
 
        err = devm_request_irq(&priv->pci_dev->dev,
                               priv->pci_dev->irq,
@@ -806,11 +802,13 @@ static int ismt_int_init(struct ismt_priv *priv)
                goto intx;
        }
 
-       priv->using_msi = true;
-       goto done;
+       return 0;
 
        /* Try using legacy interrupts */
 intx:
+       dev_warn(&priv->pci_dev->dev,
+                "Unable to use MSI interrupts, falling back to legacy\n");
+
        err = devm_request_irq(&priv->pci_dev->dev,
                               priv->pci_dev->irq,
                               ismt_do_interrupt,
@@ -819,12 +817,9 @@ intx:
                               priv);
        if (err) {
                dev_err(&priv->pci_dev->dev, "no usable interrupts\n");
-               return -ENODEV;
+               return err;
        }
 
-       priv->using_msi = false;
-
-done:
        return 0;
 }
 
@@ -847,17 +842,13 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENOMEM;
 
        pci_set_drvdata(pdev, priv);
+
        i2c_set_adapdata(&priv->adapter, priv);
        priv->adapter.owner = THIS_MODULE;
-
        priv->adapter.class = I2C_CLASS_HWMON;
-
        priv->adapter.algo = &smbus_algorithm;
-
-       /* set up the sysfs linkage to our parent device */
        priv->adapter.dev.parent = &pdev->dev;
-
-       /* number of retries on lost arbitration */
+       ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
        priv->adapter.retries = ISMT_MAX_RETRIES;
 
        priv->pci_dev = pdev;
@@ -904,8 +895,7 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        priv->smba = pcim_iomap(pdev, SMBBAR, len);
        if (!priv->smba) {
                dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n");
-               err = -ENODEV;
-               goto fail;
+               return -ENODEV;
        }
 
        if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) ||
@@ -915,32 +905,26 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                                                 DMA_BIT_MASK(32)) != 0)) {
                        dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n",
                                pdev);
-                       err = -ENODEV;
-                       goto fail;
+                       return -ENODEV;
                }
        }
 
        err = ismt_dev_init(priv);
        if (err)
-               goto fail;
+               return err;
 
        ismt_hw_init(priv);
 
        err = ismt_int_init(priv);
        if (err)
-               goto fail;
+               return err;
 
        err = i2c_add_adapter(&priv->adapter);
        if (err) {
                dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n");
-               err = -ENODEV;
-               goto fail;
+               return -ENODEV;
        }
        return 0;
-
-fail:
-       pci_release_region(pdev, SMBBAR);
-       return err;
 }
 
 /**
@@ -952,47 +936,13 @@ static void ismt_remove(struct pci_dev *pdev)
        struct ismt_priv *priv = pci_get_drvdata(pdev);
 
        i2c_del_adapter(&priv->adapter);
-       pci_release_region(pdev, SMBBAR);
 }
 
-/**
- * ismt_suspend() - place the device in suspend
- * @pdev: PCI-Express device
- * @mesg: PM message
- */
-#ifdef CONFIG_PM
-static int ismt_suspend(struct pci_dev *pdev, pm_message_t mesg)
-{
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
-       return 0;
-}
-
-/**
- * ismt_resume() - PCI resume code
- * @pdev: PCI-Express device
- */
-static int ismt_resume(struct pci_dev *pdev)
-{
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-       return pci_enable_device(pdev);
-}
-
-#else
-
-#define ismt_suspend NULL
-#define ismt_resume NULL
-
-#endif
-
 static struct pci_driver ismt_driver = {
        .name = "ismt_smbus",
        .id_table = ismt_ids,
        .probe = ismt_probe,
        .remove = ismt_remove,
-       .suspend = ismt_suspend,
-       .resume = ismt_resume,
 };
 
 module_pci_driver(ismt_driver);
index 5e176ad..71d3929 100644 (file)
@@ -475,6 +475,7 @@ static const struct of_device_id meson_i2c_match[] = {
        { .compatible = "amlogic,meson6-i2c" },
        { },
 };
+MODULE_DEVICE_TABLE(of, meson_i2c_match);
 
 static struct platform_driver meson_i2c_driver = {
        .probe   = meson_i2c_probe,
index c02e6c0..9b86716 100644 (file)
@@ -728,11 +728,27 @@ static int mtk_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int mtk_i2c_resume(struct device *dev)
+{
+       struct mtk_i2c *i2c = dev_get_drvdata(dev);
+
+       mtk_i2c_init_hw(i2c);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk_i2c_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume)
+};
+
 static struct platform_driver mtk_i2c_driver = {
        .probe = mtk_i2c_probe,
        .remove = mtk_i2c_remove,
        .driver = {
                .name = I2C_DRV_NAME,
+               .pm = &mtk_i2c_pm,
                .of_match_table = of_match_ptr(mtk_i2c_of_match),
        },
 };
index abf5db7..11b7b87 100644 (file)
@@ -92,6 +92,16 @@ static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value)
        iowrite32(value, i2c->base + (reg << i2c->reg_shift));
 }
 
+static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value)
+{
+       iowrite16be(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value)
+{
+       iowrite32be(value, i2c->base + (reg << i2c->reg_shift));
+}
+
 static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg)
 {
        return ioread8(i2c->base + (reg << i2c->reg_shift));
@@ -107,6 +117,16 @@ static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg)
        return ioread32(i2c->base + (reg << i2c->reg_shift));
 }
 
+static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg)
+{
+       return ioread16be(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg)
+{
+       return ioread32be(i2c->base + (reg << i2c->reg_shift));
+}
+
 static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
 {
        i2c->setreg(i2c, reg, value);
@@ -428,6 +448,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
                i2c->reg_io_width = 1; /* Set to default value */
 
        if (!i2c->setreg || !i2c->getreg) {
+               bool be = pdata ? pdata->big_endian :
+                       of_device_is_big_endian(pdev->dev.of_node);
+
                switch (i2c->reg_io_width) {
                case 1:
                        i2c->setreg = oc_setreg_8;
@@ -435,13 +458,13 @@ static int ocores_i2c_probe(struct platform_device *pdev)
                        break;
 
                case 2:
-                       i2c->setreg = oc_setreg_16;
-                       i2c->getreg = oc_getreg_16;
+                       i2c->setreg = be ? oc_setreg_16be : oc_setreg_16;
+                       i2c->getreg = be ? oc_getreg_16be : oc_getreg_16;
                        break;
 
                case 4:
-                       i2c->setreg = oc_setreg_32;
-                       i2c->getreg = oc_getreg_32;
+                       i2c->setreg = be ? oc_setreg_32be : oc_setreg_32;
+                       i2c->getreg = be ? oc_getreg_32be : oc_getreg_32;
                        break;
 
                default:
index 6f8b446..7ea67aa 100644 (file)
@@ -496,7 +496,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        struct i2c_msg *pmsg;
        int rc = 0, completed = 0, i;
        struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-       u32 stat = ioread32(I2C_REG_STS(alg_data));
+       u32 stat;
 
        dev_dbg(&alg_data->adapter.dev,
                "%s(): entering: %d messages, stat = %04x.\n",
@@ -659,9 +659,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
        if (IS_ERR(alg_data->clk))
                return PTR_ERR(alg_data->clk);
 
-       init_timer(&alg_data->mif.timer);
-       alg_data->mif.timer.function = i2c_pnx_timeout;
-       alg_data->mif.timer.data = (unsigned long)alg_data;
+       setup_timer(&alg_data->mif.timer, i2c_pnx_timeout,
+                       (unsigned long)alg_data);
 
        snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
                 "%s", pdev->name);
index 645e4b7..0d35195 100644 (file)
@@ -46,12 +46,15 @@ struct pxa_reg_layout {
        u32 icr;
        u32 isr;
        u32 isar;
+       u32 ilcr;
+       u32 iwcr;
 };
 
 enum pxa_i2c_types {
        REGS_PXA2XX,
        REGS_PXA3XX,
        REGS_CE4100,
+       REGS_PXA910,
 };
 
 /*
@@ -79,12 +82,22 @@ static struct pxa_reg_layout pxa_reg_layout[] = {
                .isr =  0x04,
                /* no isar register */
        },
+       [REGS_PXA910] = {
+               .ibmr = 0x00,
+               .idbr = 0x08,
+               .icr =  0x10,
+               .isr =  0x18,
+               .isar = 0x20,
+               .ilcr = 0x28,
+               .iwcr = 0x30,
+       },
 };
 
 static const struct platform_device_id i2c_pxa_id_table[] = {
        { "pxa2xx-i2c",         REGS_PXA2XX },
        { "pxa3xx-pwri2c",      REGS_PXA3XX },
        { "ce4100-i2c",         REGS_CE4100 },
+       { "pxa910-i2c",         REGS_PXA910 },
        { },
 };
 MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
@@ -124,6 +137,23 @@ MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
 #define ISR_SAD                (1 << 9)           /* slave address detected */
 #define ISR_BED                (1 << 10)          /* bus error no ACK/NAK */
 
+/* bit field shift & mask */
+#define ILCR_SLV_SHIFT         0
+#define ILCR_SLV_MASK          (0x1FF << ILCR_SLV_SHIFT)
+#define ILCR_FLV_SHIFT         9
+#define ILCR_FLV_MASK          (0x1FF << ILCR_FLV_SHIFT)
+#define ILCR_HLVL_SHIFT                18
+#define ILCR_HLVL_MASK         (0x1FF << ILCR_HLVL_SHIFT)
+#define ILCR_HLVH_SHIFT                27
+#define ILCR_HLVH_MASK         (0x1F << ILCR_HLVH_SHIFT)
+
+#define IWCR_CNT_SHIFT         0
+#define IWCR_CNT_MASK          (0x1F << IWCR_CNT_SHIFT)
+#define IWCR_HS_CNT1_SHIFT     5
+#define IWCR_HS_CNT1_MASK      (0x1F << IWCR_HS_CNT1_SHIFT)
+#define IWCR_HS_CNT2_SHIFT     10
+#define IWCR_HS_CNT2_MASK      (0x1F << IWCR_HS_CNT2_SHIFT)
+
 struct pxa_i2c {
        spinlock_t              lock;
        wait_queue_head_t       wait;
@@ -150,6 +180,8 @@ struct pxa_i2c {
        void __iomem            *reg_icr;
        void __iomem            *reg_isr;
        void __iomem            *reg_isar;
+       void __iomem            *reg_ilcr;
+       void __iomem            *reg_iwcr;
 
        unsigned long           iobase;
        unsigned long           iosize;
@@ -168,6 +200,8 @@ struct pxa_i2c {
 #define _ICR(i2c)      ((i2c)->reg_icr)
 #define _ISR(i2c)      ((i2c)->reg_isr)
 #define _ISAR(i2c)     ((i2c)->reg_isar)
+#define _ILCR(i2c)     ((i2c)->reg_ilcr)
+#define _IWCR(i2c)     ((i2c)->reg_iwcr)
 
 /*
  * I2C Slave mode address
@@ -1102,7 +1136,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
 static const struct of_device_id i2c_pxa_dt_ids[] = {
        { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
        { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
-       { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
+       { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 },
        {}
 };
 MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
@@ -1203,6 +1237,11 @@ static int i2c_pxa_probe(struct platform_device *dev)
        if (i2c_type != REGS_CE4100)
                i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
 
+       if (i2c_type == REGS_PXA910) {
+               i2c->reg_ilcr = i2c->reg_base + pxa_reg_layout[i2c_type].ilcr;
+               i2c->reg_iwcr = i2c->reg_base + pxa_reg_layout[i2c_type].iwcr;
+       }
+
        i2c->iobase = res->start;
        i2c->iosize = resource_size(res);
 
index d8b5a8f..b0ae560 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
-#include <linux/i2c/i2c-rcar.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 enum rcar_i2c_type {
        I2C_RCAR_GEN1,
        I2C_RCAR_GEN2,
+       I2C_RCAR_GEN3,
 };
 
 struct rcar_i2c_priv {
@@ -178,6 +178,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
                cdf_width = 2;
                break;
        case I2C_RCAR_GEN2:
+       case I2C_RCAR_GEN3:
                cdf_width = 3;
                break;
        default:
@@ -625,13 +626,13 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
        { .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 },
        { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
        { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
+       { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
        {},
 };
 MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
 
 static int rcar_i2c_probe(struct platform_device *pdev)
 {
-       struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct rcar_i2c_priv *priv;
        struct i2c_adapter *adap;
        struct resource *res;
@@ -650,15 +651,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
        }
 
        bus_speed = 100000; /* default 100 kHz */
-       ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
-       if (ret < 0 && pdata && pdata->bus_speed)
-               bus_speed = pdata->bus_speed;
+       of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
 
-       if (pdev->dev.of_node)
-               priv->devtype = (long)of_match_device(rcar_i2c_dt_ids,
-                                                     dev)->data;
-       else
-               priv->devtype = platform_get_device_id(pdev)->driver_data;
+       priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
 
        ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
        if (ret < 0)
@@ -716,14 +711,6 @@ static int rcar_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct platform_device_id rcar_i2c_id_table[] = {
-       { "i2c-rcar",           I2C_RCAR_GEN1 },
-       { "i2c-rcar_gen1",      I2C_RCAR_GEN1 },
-       { "i2c-rcar_gen2",      I2C_RCAR_GEN2 },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table);
-
 static struct platform_driver rcar_i2c_driver = {
        .driver = {
                .name   = "i2c-rcar",
@@ -731,7 +718,6 @@ static struct platform_driver rcar_i2c_driver = {
        },
        .probe          = rcar_i2c_probe,
        .remove         = rcar_i2c_remove,
-       .id_table       = rcar_i2c_id_table,
 };
 
 module_platform_driver(rcar_i2c_driver);
index 72e97e3..c1935eb 100644 (file)
@@ -858,6 +858,7 @@ static const struct of_device_id rk3x_i2c_match[] = {
        { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
        {},
 };
+MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
 
 static int rk3x_i2c_probe(struct platform_device *pdev)
 {
index 47659a9..7d2bd3e 100644 (file)
@@ -836,6 +836,7 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
        { .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-sh73a0", .data = &fast_clock_dt_config },
        {},
 };
index 1092d4e..13e51ef 100644 (file)
@@ -358,11 +358,29 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
        if (err < 0)
                bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
 
-       if (bitrate < 100000)
-               regval =
-                       (2 * ctrl_speed) / (bitrate * 11);
-       else
+       /*
+        * Due to some hardware design issues, we need to tune the formula.
+        * Since i2c is open drain interface that allows the slave to
+        * stall the transaction by holding the SCL line at '0', the RTL
+        * implementation is waiting for SCL feedback from the pin after
+        * setting it to High-Z ('1'). This wait adds to the high-time
+        * interval counter few cycles of the input synchronization
+        * (depending on the SCL_FILTER_REG field), and also the time it
+        * takes for the board pull-up resistor to rise the SCL line.
+        * For slow SCL settings these additions are negligible,
+        * but they start to affect the speed when clock is set to faster
+        * frequencies.
+        * Through the actual tests, use the different user_div value(which
+        * in the divider formular 'Fio / (Fi2c * user_div)') to adapt
+        * the different ranges of i2c bus clock frequency, to make the SCL
+        * more accurate.
+        */
+       if (bitrate <= 30000)
                regval = ctrl_speed / (bitrate * 5);
+       else if (bitrate > 30000 && bitrate <= 280000)
+               regval = (2 * ctrl_speed) / (bitrate * 11);
+       else
+               regval = ctrl_speed / (bitrate * 6);
 
        writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
        if (regval > 0xFF)
index 4885da9..460c134 100644 (file)
@@ -977,6 +977,7 @@ static const struct of_device_id stu300_dt_match[] = {
        { .compatible = "st,ddci2c" },
        {},
 };
+MODULE_DEVICE_TABLE(of, stu300_dt_match);
 
 static struct platform_driver stu300_i2c_driver = {
        .driver = {
index b7e1a36..a0522fc 100644 (file)
@@ -873,7 +873,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
        i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
        strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
                sizeof(i2c_dev->adapter.name));
-       i2c_dev->adapter.algo = &tegra_i2c_algo;
        i2c_dev->adapter.dev.parent = &pdev->dev;
        i2c_dev->adapter.nr = pdev->id;
        i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
new file mode 100644 (file)
index 0000000..e8d03bc
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define UNIPHIER_FI2C_CR       0x00    /* control register */
+#define     UNIPHIER_FI2C_CR_MST       BIT(3)  /* master mode */
+#define     UNIPHIER_FI2C_CR_STA       BIT(2)  /* start condition */
+#define     UNIPHIER_FI2C_CR_STO       BIT(1)  /* stop condition */
+#define     UNIPHIER_FI2C_CR_NACK      BIT(0)  /* do not return ACK */
+#define UNIPHIER_FI2C_DTTX     0x04    /* TX FIFO */
+#define     UNIPHIER_FI2C_DTTX_CMD     BIT(8)  /* send command (slave addr) */
+#define     UNIPHIER_FI2C_DTTX_RD      BIT(0)  /* read transaction */
+#define UNIPHIER_FI2C_DTRX     0x04    /* RX FIFO */
+#define UNIPHIER_FI2C_SLAD     0x0c    /* slave address */
+#define UNIPHIER_FI2C_CYC      0x10    /* clock cycle control */
+#define UNIPHIER_FI2C_LCTL     0x14    /* clock low period control */
+#define UNIPHIER_FI2C_SSUT     0x18    /* restart/stop setup time control */
+#define UNIPHIER_FI2C_DSUT     0x1c    /* data setup time control */
+#define UNIPHIER_FI2C_INT      0x20    /* interrupt status */
+#define UNIPHIER_FI2C_IE       0x24    /* interrupt enable */
+#define UNIPHIER_FI2C_IC       0x28    /* interrupt clear */
+#define     UNIPHIER_FI2C_INT_TE       BIT(9)  /* TX FIFO empty */
+#define     UNIPHIER_FI2C_INT_RF       BIT(8)  /* RX FIFO full */
+#define     UNIPHIER_FI2C_INT_TC       BIT(7)  /* send complete (STOP) */
+#define     UNIPHIER_FI2C_INT_RC       BIT(6)  /* receive complete (STOP) */
+#define     UNIPHIER_FI2C_INT_TB       BIT(5)  /* sent specified bytes */
+#define     UNIPHIER_FI2C_INT_RB       BIT(4)  /* received specified bytes */
+#define     UNIPHIER_FI2C_INT_NA       BIT(2)  /* no ACK */
+#define     UNIPHIER_FI2C_INT_AL       BIT(1)  /* arbitration lost */
+#define UNIPHIER_FI2C_SR       0x2c    /* status register */
+#define     UNIPHIER_FI2C_SR_DB                BIT(12) /* device busy */
+#define     UNIPHIER_FI2C_SR_STS       BIT(11) /* stop condition detected */
+#define     UNIPHIER_FI2C_SR_BB                BIT(8)  /* bus busy */
+#define     UNIPHIER_FI2C_SR_RFF       BIT(3)  /* RX FIFO full */
+#define     UNIPHIER_FI2C_SR_RNE       BIT(2)  /* RX FIFO not empty */
+#define     UNIPHIER_FI2C_SR_TNF       BIT(1)  /* TX FIFO not full */
+#define     UNIPHIER_FI2C_SR_TFE       BIT(0)  /* TX FIFO empty */
+#define UNIPHIER_FI2C_RST      0x34    /* reset control */
+#define     UNIPHIER_FI2C_RST_TBRST    BIT(2)  /* clear TX FIFO */
+#define     UNIPHIER_FI2C_RST_RBRST    BIT(1)  /* clear RX FIFO */
+#define     UNIPHIER_FI2C_RST_RST      BIT(0)  /* forcible bus reset */
+#define UNIPHIER_FI2C_BM       0x38    /* bus monitor */
+#define     UNIPHIER_FI2C_BM_SDAO      BIT(3)  /* output for SDA line */
+#define     UNIPHIER_FI2C_BM_SDAS      BIT(2)  /* readback of SDA line */
+#define     UNIPHIER_FI2C_BM_SCLO      BIT(1)  /* output for SCL line */
+#define     UNIPHIER_FI2C_BM_SCLS      BIT(0)  /* readback of SCL line */
+#define UNIPHIER_FI2C_NOISE    0x3c    /* noise filter control */
+#define UNIPHIER_FI2C_TBC      0x40    /* TX byte count setting */
+#define UNIPHIER_FI2C_RBC      0x44    /* RX byte count setting */
+#define UNIPHIER_FI2C_TBCM     0x48    /* TX byte count monitor */
+#define UNIPHIER_FI2C_RBCM     0x4c    /* RX byte count monitor */
+#define UNIPHIER_FI2C_BRST     0x50    /* bus reset */
+#define     UNIPHIER_FI2C_BRST_FOEN    BIT(1)  /* normal operation */
+#define     UNIPHIER_FI2C_BRST_RSCL    BIT(0)  /* release SCL */
+
+#define UNIPHIER_FI2C_INT_FAULTS       \
+                               (UNIPHIER_FI2C_INT_NA | UNIPHIER_FI2C_INT_AL)
+#define UNIPHIER_FI2C_INT_STOP         \
+                               (UNIPHIER_FI2C_INT_TC | UNIPHIER_FI2C_INT_RC)
+
+#define UNIPHIER_FI2C_RD               BIT(0)
+#define UNIPHIER_FI2C_STOP             BIT(1)
+#define UNIPHIER_FI2C_MANUAL_NACK      BIT(2)
+#define UNIPHIER_FI2C_BYTE_WISE                BIT(3)
+#define UNIPHIER_FI2C_DEFER_STOP_COMP  BIT(4)
+
+#define UNIPHIER_FI2C_DEFAULT_SPEED    100000
+#define UNIPHIER_FI2C_MAX_SPEED                400000
+#define UNIPHIER_FI2C_FIFO_SIZE                8
+
+struct uniphier_fi2c_priv {
+       struct completion comp;
+       struct i2c_adapter adap;
+       void __iomem *membase;
+       struct clk *clk;
+       unsigned int len;
+       u8 *buf;
+       u32 enabled_irqs;
+       int error;
+       unsigned int flags;
+       unsigned int busy_cnt;
+};
+
+static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
+                                     bool first)
+{
+       int fifo_space = UNIPHIER_FI2C_FIFO_SIZE;
+
+       /*
+        * TX-FIFO stores slave address in it for the first access.
+        * Decrement the counter.
+        */
+       if (first)
+               fifo_space--;
+
+       while (priv->len) {
+               if (fifo_space-- <= 0)
+                       break;
+
+               dev_dbg(&priv->adap.dev, "write data: %02x\n", *priv->buf);
+               writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX);
+               priv->len--;
+       }
+}
+
+static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv)
+{
+       int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ?
+                                               1 : UNIPHIER_FI2C_FIFO_SIZE;
+
+       while (priv->len) {
+               if (fifo_left-- <= 0)
+                       break;
+
+               *priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX);
+               dev_dbg(&priv->adap.dev, "read data: %02x\n", priv->buf[-1]);
+               priv->len--;
+       }
+}
+
+static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
+{
+       writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
+}
+
+static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv)
+{
+       writel(-1, priv->membase + UNIPHIER_FI2C_IC);
+}
+
+static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
+{
+       dev_dbg(&priv->adap.dev, "stop condition\n");
+
+       priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP;
+       uniphier_fi2c_set_irqs(priv);
+       writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO,
+              priv->membase + UNIPHIER_FI2C_CR);
+}
+
+static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
+{
+       struct uniphier_fi2c_priv *priv = dev_id;
+       u32 irq_status;
+
+       irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
+
+       dev_dbg(&priv->adap.dev,
+               "interrupt: enabled_irqs=%04x, irq_status=%04x\n",
+               priv->enabled_irqs, irq_status);
+
+       if (irq_status & UNIPHIER_FI2C_INT_STOP)
+               goto complete;
+
+       if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) {
+               dev_dbg(&priv->adap.dev, "arbitration lost\n");
+               priv->error = -EAGAIN;
+               goto complete;
+       }
+
+       if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) {
+               dev_dbg(&priv->adap.dev, "could not get ACK\n");
+               priv->error = -ENXIO;
+               if (priv->flags & UNIPHIER_FI2C_RD) {
+                       /*
+                        * work around a hardware bug:
+                        * The receive-completed interrupt is never set even if
+                        * STOP condition is detected after the address phase
+                        * of read transaction fails to get ACK.
+                        * To avoid time-out error, we issue STOP here,
+                        * but do not wait for its completion.
+                        * It should be checked after exiting this handler.
+                        */
+                       uniphier_fi2c_stop(priv);
+                       priv->flags |= UNIPHIER_FI2C_DEFER_STOP_COMP;
+                       goto complete;
+               }
+               goto stop;
+       }
+
+       if (irq_status & UNIPHIER_FI2C_INT_TE) {
+               if (!priv->len)
+                       goto data_done;
+
+               uniphier_fi2c_fill_txfifo(priv, false);
+               goto handled;
+       }
+
+       if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) {
+               uniphier_fi2c_drain_rxfifo(priv);
+               if (!priv->len)
+                       goto data_done;
+
+               if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
+                       if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE &&
+                           !(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) {
+                               dev_dbg(&priv->adap.dev,
+                                       "enable read byte count IRQ\n");
+                               priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB;
+                               uniphier_fi2c_set_irqs(priv);
+                               priv->flags |= UNIPHIER_FI2C_BYTE_WISE;
+                       }
+                       if (priv->len <= 1) {
+                               dev_dbg(&priv->adap.dev, "set NACK\n");
+                               writel(UNIPHIER_FI2C_CR_MST |
+                                      UNIPHIER_FI2C_CR_NACK,
+                                      priv->membase + UNIPHIER_FI2C_CR);
+                       }
+               }
+
+               goto handled;
+       }
+
+       return IRQ_NONE;
+
+data_done:
+       if (priv->flags & UNIPHIER_FI2C_STOP) {
+stop:
+               uniphier_fi2c_stop(priv);
+       } else {
+complete:
+               priv->enabled_irqs = 0;
+               uniphier_fi2c_set_irqs(priv);
+               complete(&priv->comp);
+       }
+
+handled:
+       uniphier_fi2c_clear_irqs(priv);
+
+       return IRQ_HANDLED;
+}
+
+static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
+{
+       priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
+       /* do not use TX byte counter */
+       writel(0, priv->membase + UNIPHIER_FI2C_TBC);
+       /* set slave address */
+       writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1,
+              priv->membase + UNIPHIER_FI2C_DTTX);
+       /* first chunk of data */
+       uniphier_fi2c_fill_txfifo(priv, true);
+}
+
+static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
+{
+       priv->flags |= UNIPHIER_FI2C_RD;
+
+       if (likely(priv->len < 256)) {
+               /*
+                * If possible, use RX byte counter.
+                * It can automatically handle NACK for the last byte.
+                */
+               writel(priv->len, priv->membase + UNIPHIER_FI2C_RBC);
+               priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF |
+                                     UNIPHIER_FI2C_INT_RB;
+       } else {
+               /*
+                * The byte counter can not count over 256.  In this case,
+                * do not use it at all.  Drain data when FIFO gets full,
+                * but treat the last portion as a special case.
+                */
+               writel(0, priv->membase + UNIPHIER_FI2C_RBC);
+               priv->flags |= UNIPHIER_FI2C_MANUAL_NACK;
+               priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
+       }
+
+       /* set slave address with RD bit */
+       writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
+              priv->membase + UNIPHIER_FI2C_DTTX);
+}
+
+static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv)
+{
+       writel(UNIPHIER_FI2C_RST_RST, priv->membase + UNIPHIER_FI2C_RST);
+}
+
+static void uniphier_fi2c_prepare_operation(struct uniphier_fi2c_priv *priv)
+{
+       writel(UNIPHIER_FI2C_BRST_FOEN | UNIPHIER_FI2C_BRST_RSCL,
+              priv->membase + UNIPHIER_FI2C_BRST);
+}
+
+static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
+{
+       uniphier_fi2c_reset(priv);
+       i2c_recover_bus(&priv->adap);
+}
+
+static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
+                                        struct i2c_msg *msg, bool stop)
+{
+       struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+       bool is_read = msg->flags & I2C_M_RD;
+       unsigned long time_left;
+
+       dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
+               is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
+
+       priv->len = msg->len;
+       priv->buf = msg->buf;
+       priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS;
+       priv->error = 0;
+       priv->flags = 0;
+
+       if (stop)
+               priv->flags |= UNIPHIER_FI2C_STOP;
+
+       reinit_completion(&priv->comp);
+       uniphier_fi2c_clear_irqs(priv);
+       writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
+              priv->membase + UNIPHIER_FI2C_RST);      /* reset TX/RX FIFO */
+
+       if (is_read)
+               uniphier_fi2c_rx_init(priv, msg->addr);
+       else
+               uniphier_fi2c_tx_init(priv, msg->addr);
+
+       uniphier_fi2c_set_irqs(priv);
+
+       dev_dbg(&adap->dev, "start condition\n");
+       writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
+              priv->membase + UNIPHIER_FI2C_CR);
+
+       time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+       if (!time_left) {
+               dev_err(&adap->dev, "transaction timeout.\n");
+               uniphier_fi2c_recover(priv);
+               return -ETIMEDOUT;
+       }
+       dev_dbg(&adap->dev, "complete\n");
+
+       if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) {
+               u32 status = readl(priv->membase + UNIPHIER_FI2C_SR);
+
+               if (!(status & UNIPHIER_FI2C_SR_STS) ||
+                   status & UNIPHIER_FI2C_SR_BB) {
+                       dev_err(&adap->dev,
+                               "stop condition was not completed.\n");
+                       uniphier_fi2c_recover(priv);
+                       return -EBUSY;
+               }
+       }
+
+       return priv->error;
+}
+
+static int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap)
+{
+       struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+       if (readl(priv->membase + UNIPHIER_FI2C_SR) & UNIPHIER_FI2C_SR_DB) {
+               if (priv->busy_cnt++ > 3) {
+                       /*
+                        * If bus busy continues too long, it is probably
+                        * in a wrong state.  Try bus recovery.
+                        */
+                       uniphier_fi2c_recover(priv);
+                       priv->busy_cnt = 0;
+               }
+
+               return -EAGAIN;
+       }
+
+       priv->busy_cnt = 0;
+       return 0;
+}
+
+static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
+                                    struct i2c_msg *msgs, int num)
+{
+       struct i2c_msg *msg, *emsg = msgs + num;
+       int ret;
+
+       ret = uniphier_fi2c_check_bus_busy(adap);
+       if (ret)
+               return ret;
+
+       for (msg = msgs; msg < emsg; msg++) {
+               /* If next message is read, skip the stop condition */
+               bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
+               /* but, force it if I2C_M_STOP is set */
+               if (msg->flags & I2C_M_STOP)
+                       stop = true;
+
+               ret = uniphier_fi2c_master_xfer_one(adap, msg, stop);
+               if (ret)
+                       return ret;
+       }
+
+       return num;
+}
+
+static u32 uniphier_fi2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm uniphier_fi2c_algo = {
+       .master_xfer = uniphier_fi2c_master_xfer,
+       .functionality = uniphier_fi2c_functionality,
+};
+
+static int uniphier_fi2c_get_scl(struct i2c_adapter *adap)
+{
+       struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+       return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
+                                                       UNIPHIER_FI2C_BM_SCLS);
+}
+
+static void uniphier_fi2c_set_scl(struct i2c_adapter *adap, int val)
+{
+       struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+       writel(val ? UNIPHIER_FI2C_BRST_RSCL : 0,
+              priv->membase + UNIPHIER_FI2C_BRST);
+}
+
+static int uniphier_fi2c_get_sda(struct i2c_adapter *adap)
+{
+       struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+       return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
+                                                       UNIPHIER_FI2C_BM_SDAS);
+}
+
+static void uniphier_fi2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+       uniphier_fi2c_prepare_operation(i2c_get_adapdata(adap));
+}
+
+static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = {
+       .recover_bus = i2c_generic_scl_recovery,
+       .get_scl = uniphier_fi2c_get_scl,
+       .set_scl = uniphier_fi2c_set_scl,
+       .get_sda = uniphier_fi2c_get_sda,
+       .unprepare_recovery = uniphier_fi2c_unprepare_recovery,
+};
+
+static int uniphier_fi2c_clk_init(struct device *dev,
+                                 struct uniphier_fi2c_priv *priv)
+{
+       struct device_node *np = dev->of_node;
+       unsigned long clk_rate;
+       u32 bus_speed, clk_count;
+       int ret;
+
+       if (of_property_read_u32(np, "clock-frequency", &bus_speed))
+               bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
+
+       if (bus_speed > UNIPHIER_FI2C_MAX_SPEED)
+               bus_speed = UNIPHIER_FI2C_MAX_SPEED;
+
+       /* Get input clk rate through clk driver */
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(dev, "failed to get clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
+
+       clk_rate = clk_get_rate(priv->clk);
+
+       uniphier_fi2c_reset(priv);
+
+       clk_count = clk_rate / bus_speed;
+
+       writel(clk_count, priv->membase + UNIPHIER_FI2C_CYC);
+       writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_LCTL);
+       writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_SSUT);
+       writel(clk_count / 16, priv->membase + UNIPHIER_FI2C_DSUT);
+
+       uniphier_fi2c_prepare_operation(priv);
+
+       return 0;
+}
+
+static int uniphier_fi2c_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct uniphier_fi2c_priv *priv;
+       struct resource *regs;
+       int irq;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->membase = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(priv->membase))
+               return PTR_ERR(priv->membase);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "failed to get IRQ number");
+               return irq;
+       }
+
+       init_completion(&priv->comp);
+       priv->adap.owner = THIS_MODULE;
+       priv->adap.algo = &uniphier_fi2c_algo;
+       priv->adap.dev.parent = dev;
+       priv->adap.dev.of_node = dev->of_node;
+       strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name));
+       priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info;
+       i2c_set_adapdata(&priv->adap, priv);
+       platform_set_drvdata(pdev, priv);
+
+       ret = uniphier_fi2c_clk_init(dev, priv);
+       if (ret)
+               return ret;
+
+       ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
+                              pdev->name, priv);
+       if (ret) {
+               dev_err(dev, "failed to request irq %d\n", irq);
+               goto err;
+       }
+
+       ret = i2c_add_adapter(&priv->adap);
+       if (ret) {
+               dev_err(dev, "failed to add I2C adapter\n");
+               goto err;
+       }
+
+err:
+       if (ret)
+               clk_disable_unprepare(priv->clk);
+
+       return ret;
+}
+
+static int uniphier_fi2c_remove(struct platform_device *pdev)
+{
+       struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&priv->adap);
+       clk_disable_unprepare(priv->clk);
+
+       return 0;
+}
+
+static const struct of_device_id uniphier_fi2c_match[] = {
+       { .compatible = "socionext,uniphier-fi2c" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_fi2c_match);
+
+static struct platform_driver uniphier_fi2c_drv = {
+       .probe  = uniphier_fi2c_probe,
+       .remove = uniphier_fi2c_remove,
+       .driver = {
+               .name  = "uniphier-fi2c",
+               .of_match_table = uniphier_fi2c_match,
+       },
+};
+module_platform_driver(uniphier_fi2c_drv);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier FIFO-builtin I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
new file mode 100644 (file)
index 0000000..e3c3861
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define UNIPHIER_I2C_DTRM      0x00    /* TX register */
+#define     UNIPHIER_I2C_DTRM_IRQEN    BIT(11) /* enable interrupt */
+#define     UNIPHIER_I2C_DTRM_STA      BIT(10) /* start condition */
+#define     UNIPHIER_I2C_DTRM_STO      BIT(9)  /* stop condition */
+#define     UNIPHIER_I2C_DTRM_NACK     BIT(8)  /* do not return ACK */
+#define     UNIPHIER_I2C_DTRM_RD       BIT(0)  /* read transaction */
+#define UNIPHIER_I2C_DREC      0x04    /* RX register */
+#define     UNIPHIER_I2C_DREC_MST      BIT(14) /* 1 = master, 0 = slave */
+#define     UNIPHIER_I2C_DREC_TX       BIT(13) /* 1 = transmit, 0 = receive */
+#define     UNIPHIER_I2C_DREC_STS      BIT(12) /* stop condition detected */
+#define     UNIPHIER_I2C_DREC_LRB      BIT(11) /* no ACK */
+#define     UNIPHIER_I2C_DREC_LAB      BIT(9)  /* arbitration lost */
+#define     UNIPHIER_I2C_DREC_BBN      BIT(8)  /* bus not busy */
+#define UNIPHIER_I2C_MYAD      0x08    /* slave address */
+#define UNIPHIER_I2C_CLK       0x0c    /* clock frequency control */
+#define UNIPHIER_I2C_BRST      0x10    /* bus reset */
+#define     UNIPHIER_I2C_BRST_FOEN     BIT(1)  /* normal operation */
+#define     UNIPHIER_I2C_BRST_RSCL     BIT(0)  /* release SCL */
+#define UNIPHIER_I2C_HOLD      0x14    /* hold time control */
+#define UNIPHIER_I2C_BSTS      0x18    /* bus status monitor */
+#define     UNIPHIER_I2C_BSTS_SDA      BIT(1)  /* readback of SDA line */
+#define     UNIPHIER_I2C_BSTS_SCL      BIT(0)  /* readback of SCL line */
+#define UNIPHIER_I2C_NOISE     0x1c    /* noise filter control */
+#define UNIPHIER_I2C_SETUP     0x20    /* setup time control */
+
+#define UNIPHIER_I2C_DEFAULT_SPEED     100000
+#define UNIPHIER_I2C_MAX_SPEED         400000
+
+struct uniphier_i2c_priv {
+       struct completion comp;
+       struct i2c_adapter adap;
+       void __iomem *membase;
+       struct clk *clk;
+       unsigned int busy_cnt;
+};
+
+static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id)
+{
+       struct uniphier_i2c_priv *priv = dev_id;
+
+       /*
+        * This hardware uses edge triggered interrupt.  Do not touch the
+        * hardware registers in this handler to make sure to catch the next
+        * interrupt edge.  Just send a complete signal and return.
+        */
+       complete(&priv->comp);
+
+       return IRQ_HANDLED;
+}
+
+static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
+                                 u32 *rxdatap)
+{
+       struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+       unsigned long time_left;
+       u32 rxdata;
+
+       reinit_completion(&priv->comp);
+
+       txdata |= UNIPHIER_I2C_DTRM_IRQEN;
+       dev_dbg(&adap->dev, "write data: 0x%04x\n", txdata);
+       writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
+
+       time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+       if (unlikely(!time_left)) {
+               dev_err(&adap->dev, "transaction timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
+       dev_dbg(&adap->dev, "read data: 0x%04x\n", rxdata);
+
+       if (rxdatap)
+               *rxdatap = rxdata;
+
+       return 0;
+}
+
+static int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata)
+{
+       u32 rxdata;
+       int ret;
+
+       ret = uniphier_i2c_xfer_byte(adap, txdata, &rxdata);
+       if (ret)
+               return ret;
+
+       if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB)) {
+               dev_dbg(&adap->dev, "arbitration lost\n");
+               return -EAGAIN;
+       }
+       if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB)) {
+               dev_dbg(&adap->dev, "could not get ACK\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len,
+                          const u8 *buf)
+{
+       int ret;
+
+       dev_dbg(&adap->dev, "start condition\n");
+       ret = uniphier_i2c_send_byte(adap, addr << 1 |
+                                    UNIPHIER_I2C_DTRM_STA |
+                                    UNIPHIER_I2C_DTRM_NACK);
+       if (ret)
+               return ret;
+
+       while (len--) {
+               ret = uniphier_i2c_send_byte(adap,
+                                            UNIPHIER_I2C_DTRM_NACK | *buf++);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
+                          u8 *buf)
+{
+       int ret;
+
+       dev_dbg(&adap->dev, "start condition\n");
+       ret = uniphier_i2c_send_byte(adap, addr << 1 |
+                                    UNIPHIER_I2C_DTRM_STA |
+                                    UNIPHIER_I2C_DTRM_NACK |
+                                    UNIPHIER_I2C_DTRM_RD);
+       if (ret)
+               return ret;
+
+       while (len--) {
+               u32 rxdata;
+
+               ret = uniphier_i2c_xfer_byte(adap,
+                                            len ? 0 : UNIPHIER_I2C_DTRM_NACK,
+                                            &rxdata);
+               if (ret)
+                       return ret;
+               *buf++ = rxdata;
+       }
+
+       return 0;
+}
+
+static int uniphier_i2c_stop(struct i2c_adapter *adap)
+{
+       dev_dbg(&adap->dev, "stop condition\n");
+       return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO |
+                                     UNIPHIER_I2C_DTRM_NACK);
+}
+
+static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
+                                       struct i2c_msg *msg, bool stop)
+{
+       bool is_read = msg->flags & I2C_M_RD;
+       bool recovery = false;
+       int ret;
+
+       dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
+               is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
+
+       if (is_read)
+               ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf);
+       else
+               ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf);
+
+       if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */
+               return ret;
+
+       if (ret == -ETIMEDOUT) {
+               /* This error is fatal.  Needs recovery. */
+               stop = false;
+               recovery = true;
+       }
+
+       if (stop) {
+               int ret2 = uniphier_i2c_stop(adap);
+
+               if (ret2) {
+                       /* Failed to issue STOP.  The bus needs recovery. */
+                       recovery = true;
+                       ret = ret ?: ret2;
+               }
+       }
+
+       if (recovery)
+               i2c_recover_bus(adap);
+
+       return ret;
+}
+
+static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap)
+{
+       struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+       if (!(readl(priv->membase + UNIPHIER_I2C_DREC) &
+                                               UNIPHIER_I2C_DREC_BBN)) {
+               if (priv->busy_cnt++ > 3) {
+                       /*
+                        * If bus busy continues too long, it is probably
+                        * in a wrong state.  Try bus recovery.
+                        */
+                       i2c_recover_bus(adap);
+                       priv->busy_cnt = 0;
+               }
+
+               return -EAGAIN;
+       }
+
+       priv->busy_cnt = 0;
+       return 0;
+}
+
+static int uniphier_i2c_master_xfer(struct i2c_adapter *adap,
+                                   struct i2c_msg *msgs, int num)
+{
+       struct i2c_msg *msg, *emsg = msgs + num;
+       int ret;
+
+       ret = uniphier_i2c_check_bus_busy(adap);
+       if (ret)
+               return ret;
+
+       for (msg = msgs; msg < emsg; msg++) {
+               /* If next message is read, skip the stop condition */
+               bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
+               /* but, force it if I2C_M_STOP is set */
+               if (msg->flags & I2C_M_STOP)
+                       stop = true;
+
+               ret = uniphier_i2c_master_xfer_one(adap, msg, stop);
+               if (ret)
+                       return ret;
+       }
+
+       return num;
+}
+
+static u32 uniphier_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm uniphier_i2c_algo = {
+       .master_xfer = uniphier_i2c_master_xfer,
+       .functionality = uniphier_i2c_functionality,
+};
+
+static void uniphier_i2c_reset(struct uniphier_i2c_priv *priv, bool reset_on)
+{
+       u32 val = UNIPHIER_I2C_BRST_RSCL;
+
+       val |= reset_on ? 0 : UNIPHIER_I2C_BRST_FOEN;
+       writel(val, priv->membase + UNIPHIER_I2C_BRST);
+}
+
+static int uniphier_i2c_get_scl(struct i2c_adapter *adap)
+{
+       struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+       return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
+                                                       UNIPHIER_I2C_BSTS_SCL);
+}
+
+static void uniphier_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+       struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+       writel(val ? UNIPHIER_I2C_BRST_RSCL : 0,
+              priv->membase + UNIPHIER_I2C_BRST);
+}
+
+static int uniphier_i2c_get_sda(struct i2c_adapter *adap)
+{
+       struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+       return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
+                                                       UNIPHIER_I2C_BSTS_SDA);
+}
+
+static void uniphier_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+       uniphier_i2c_reset(i2c_get_adapdata(adap), false);
+}
+
+static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
+       .recover_bus = i2c_generic_scl_recovery,
+       .get_scl = uniphier_i2c_get_scl,
+       .set_scl = uniphier_i2c_set_scl,
+       .get_sda = uniphier_i2c_get_sda,
+       .unprepare_recovery = uniphier_i2c_unprepare_recovery,
+};
+
+static int uniphier_i2c_clk_init(struct device *dev,
+                                struct uniphier_i2c_priv *priv)
+{
+       struct device_node *np = dev->of_node;
+       unsigned long clk_rate;
+       u32 bus_speed;
+       int ret;
+
+       if (of_property_read_u32(np, "clock-frequency", &bus_speed))
+               bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
+
+       if (bus_speed > UNIPHIER_I2C_MAX_SPEED)
+               bus_speed = UNIPHIER_I2C_MAX_SPEED;
+
+       /* Get input clk rate through clk driver */
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(dev, "failed to get clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
+
+       clk_rate = clk_get_rate(priv->clk);
+
+       uniphier_i2c_reset(priv, true);
+
+       writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed),
+              priv->membase + UNIPHIER_I2C_CLK);
+
+       uniphier_i2c_reset(priv, false);
+
+       return 0;
+}
+
+static int uniphier_i2c_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct uniphier_i2c_priv *priv;
+       struct resource *regs;
+       int irq;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->membase = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(priv->membase))
+               return PTR_ERR(priv->membase);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "failed to get IRQ number");
+               return irq;
+       }
+
+       init_completion(&priv->comp);
+       priv->adap.owner = THIS_MODULE;
+       priv->adap.algo = &uniphier_i2c_algo;
+       priv->adap.dev.parent = dev;
+       priv->adap.dev.of_node = dev->of_node;
+       strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name));
+       priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info;
+       i2c_set_adapdata(&priv->adap, priv);
+       platform_set_drvdata(pdev, priv);
+
+       ret = uniphier_i2c_clk_init(dev, priv);
+       if (ret)
+               return ret;
+
+       ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
+                              priv);
+       if (ret) {
+               dev_err(dev, "failed to request irq %d\n", irq);
+               goto err;
+       }
+
+       ret = i2c_add_adapter(&priv->adap);
+       if (ret) {
+               dev_err(dev, "failed to add I2C adapter\n");
+               goto err;
+       }
+
+err:
+       if (ret)
+               clk_disable_unprepare(priv->clk);
+
+       return ret;
+}
+
+static int uniphier_i2c_remove(struct platform_device *pdev)
+{
+       struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&priv->adap);
+       clk_disable_unprepare(priv->clk);
+
+       return 0;
+}
+
+static const struct of_device_id uniphier_i2c_match[] = {
+       { .compatible = "socionext,uniphier-i2c" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_i2c_match);
+
+static struct platform_driver uniphier_i2c_drv = {
+       .probe  = uniphier_i2c_probe,
+       .remove = uniphier_i2c_remove,
+       .driver = {
+               .name  = "uniphier-i2c",
+               .of_match_table = uniphier_i2c_match,
+       },
+};
+module_platform_driver(uniphier_i2c_drv);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier I2C bus driver");
+MODULE_LICENSE("GPL");
index a59c311..040af5c 100644 (file)
@@ -99,27 +99,40 @@ struct gsb_buffer {
        };
 } __packed;
 
-static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
+struct acpi_i2c_lookup {
+       struct i2c_board_info *info;
+       acpi_handle adapter_handle;
+       acpi_handle device_handle;
+};
+
+static int acpi_i2c_find_address(struct acpi_resource *ares, void *data)
 {
-       struct i2c_board_info *info = data;
+       struct acpi_i2c_lookup *lookup = data;
+       struct i2c_board_info *info = lookup->info;
+       struct acpi_resource_i2c_serialbus *sb;
+       acpi_handle adapter_handle;
+       acpi_status status;
 
-       if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
-               struct acpi_resource_i2c_serialbus *sb;
+       if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+               return 1;
 
-               sb = &ares->data.i2c_serial_bus;
-               if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
-                       info->addr = sb->slave_address;
-                       if (sb->access_mode == ACPI_I2C_10BIT_MODE)
-                               info->flags |= I2C_CLIENT_TEN;
-               }
-       } else if (!info->irq) {
-               struct resource r;
+       sb = &ares->data.i2c_serial_bus;
+       if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+               return 1;
 
-               if (acpi_dev_resource_interrupt(ares, 0, &r))
-                       info->irq = r.start;
+       /*
+        * Extract the ResourceSource and make sure that the handle matches
+        * with the I2C adapter handle.
+        */
+       status = acpi_get_handle(lookup->device_handle,
+                                sb->resource_source.string_ptr,
+                                &adapter_handle);
+       if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) {
+               info->addr = sb->slave_address;
+               if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+                       info->flags |= I2C_CLIENT_TEN;
        }
 
-       /* Tell the ACPI core to skip this resource */
        return 1;
 }
 
@@ -128,6 +141,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
 {
        struct i2c_adapter *adapter = data;
        struct list_head resource_list;
+       struct acpi_i2c_lookup lookup;
+       struct resource_entry *entry;
        struct i2c_board_info info;
        struct acpi_device *adev;
        int ret;
@@ -140,14 +155,37 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
        memset(&info, 0, sizeof(info));
        info.fwnode = acpi_fwnode_handle(adev);
 
+       memset(&lookup, 0, sizeof(lookup));
+       lookup.adapter_handle = ACPI_HANDLE(&adapter->dev);
+       lookup.device_handle = handle;
+       lookup.info = &info;
+
+       /*
+        * Look up for I2cSerialBus resource with ResourceSource that
+        * matches with this adapter.
+        */
        INIT_LIST_HEAD(&resource_list);
        ret = acpi_dev_get_resources(adev, &resource_list,
-                                    acpi_i2c_add_resource, &info);
+                                    acpi_i2c_find_address, &lookup);
        acpi_dev_free_resource_list(&resource_list);
 
        if (ret < 0 || !info.addr)
                return AE_OK;
 
+       /* Then fill IRQ number if any */
+       ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+       if (ret < 0)
+               return AE_OK;
+
+       resource_list_for_each_entry(entry, &resource_list) {
+               if (resource_type(entry->res) == IORESOURCE_IRQ) {
+                       info.irq = entry->res->start;
+                       break;
+               }
+       }
+
+       acpi_dev_free_resource_list(&resource_list);
+
        adev->power.flags.ignore_parent = true;
        strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
        if (!i2c_new_device(adapter, &info)) {
@@ -160,6 +198,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
        return AE_OK;
 }
 
+#define ACPI_I2C_MAX_SCAN_DEPTH 32
+
 /**
  * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
  * @adap: pointer to adapter
@@ -170,17 +210,13 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
  */
 static void acpi_i2c_register_devices(struct i2c_adapter *adap)
 {
-       acpi_handle handle;
        acpi_status status;
 
-       if (!adap->dev.parent)
-               return;
-
-       handle = ACPI_HANDLE(adap->dev.parent);
-       if (!handle)
+       if (!has_acpi_companion(&adap->dev))
                return;
 
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                                    ACPI_I2C_MAX_SCAN_DEPTH,
                                     acpi_i2c_add_device, NULL,
                                     adap, NULL);
        if (ACPI_FAILURE(status))
index 71c7a39..2413ec9 100644 (file)
@@ -235,7 +235,7 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
        return result;
 }
 
-static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
                unsigned long arg)
 {
        struct i2c_rdwr_ioctl_data rdwr_arg;
@@ -250,7 +250,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
 
        /* Put an arbitrary limit on the number of messages that can
         * be sent at once */
-       if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+       if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
                return -EINVAL;
 
        rdwr_pa = memdup_user(rdwr_arg.msgs,
@@ -421,16 +421,6 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case I2C_SLAVE:
        case I2C_SLAVE_FORCE:
-               /* NOTE:  devices set up to work with "new style" drivers
-                * can't use I2C_SLAVE, even when the device node is not
-                * bound to a driver.  Only I2C_SLAVE_FORCE will work.
-                *
-                * Setting the PEC flag here won't affect kernel drivers,
-                * which will be using the i2c_client node registered with
-                * the driver model core.  Likewise, when that client has
-                * the PEC flag already set, the i2c-dev driver won't see
-                * (or use) this setting.
-                */
                if ((arg > 0x3ff) ||
                    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
                        return -EINVAL;
@@ -446,6 +436,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        client->flags &= ~I2C_M_TEN;
                return 0;
        case I2C_PEC:
+               /*
+                * Setting the PEC flag here won't affect kernel drivers,
+                * which will be using the i2c_client node registered with
+                * the driver model core.  Likewise, when that client has
+                * the PEC flag already set, the i2c-dev driver won't see
+                * (or use) this setting.
+                */
                if (arg)
                        client->flags |= I2C_CLIENT_PEC;
                else
@@ -456,7 +453,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return put_user(funcs, (unsigned long __user *)arg);
 
        case I2C_RDWR:
-               return i2cdev_ioctl_rdrw(client, arg);
+               return i2cdev_ioctl_rdwr(client, arg);
 
        case I2C_SMBUS:
                return i2cdev_ioctl_smbus(client, arg);
index 2ba7c0f..00fc5b1 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/of.h>
+#include <linux/acpi.h>
 
 /* multiplexer per channel data */
 struct i2c_mux_priv {
@@ -173,6 +174,13 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
                }
        }
 
+       /*
+        * Associate the mux channel with an ACPI node.
+        */
+       if (has_acpi_companion(mux_dev))
+               acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
+                                     chan_id);
+
        if (force_nr) {
                priv->adap.nr = force_nr;
                ret = i2c_add_numbered_adapter(&priv->adap);
index 1ce1603..0421374 100644 (file)
 #define MFD_I2C_BAR            0
 #define MFD_GPIO_BAR           1
 
+/* ACPI _ADR value to match the child node */
+#define MFD_ACPI_MATCH_GPIO    0ULL
+#define MFD_ACPI_MATCH_I2C     1ULL
+
 /* The base GPIO number under GPIOLIB framework */
 #define INTEL_QUARK_MFD_GPIO_BASE      8
 
@@ -82,27 +86,37 @@ static struct resource intel_quark_i2c_res[] = {
        },
 };
 
+static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = {
+       .adr = MFD_ACPI_MATCH_I2C,
+};
+
 static struct resource intel_quark_gpio_res[] = {
        [INTEL_QUARK_IORES_MEM] = {
                .flags = IORESOURCE_MEM,
        },
 };
 
+static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = {
+       .adr = MFD_ACPI_MATCH_GPIO,
+};
+
 static struct mfd_cell intel_quark_mfd_cells[] = {
-       {
-               .id = MFD_I2C_BAR,
-               .name = "i2c_designware",
-               .num_resources = ARRAY_SIZE(intel_quark_i2c_res),
-               .resources = intel_quark_i2c_res,
-               .ignore_resource_conflicts = true,
-       },
        {
                .id = MFD_GPIO_BAR,
                .name = "gpio-dwapb",
+               .acpi_match = &intel_quark_acpi_match_gpio,
                .num_resources = ARRAY_SIZE(intel_quark_gpio_res),
                .resources = intel_quark_gpio_res,
                .ignore_resource_conflicts = true,
        },
+       {
+               .id = MFD_I2C_BAR,
+               .name = "i2c_designware",
+               .acpi_match = &intel_quark_acpi_match_i2c,
+               .num_resources = ARRAY_SIZE(intel_quark_i2c_res),
+               .resources = intel_quark_i2c_res,
+               .ignore_resource_conflicts = true,
+       },
 };
 
 static const struct pci_device_id intel_quark_mfd_ids[] = {
@@ -248,12 +262,11 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev,
 
        dev_set_drvdata(&pdev->dev, quark_mfd);
 
-       ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[MFD_I2C_BAR]);
+       ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]);
        if (ret)
                return ret;
 
-       ret = intel_quark_gpio_setup(pdev,
-                                    &intel_quark_mfd_cells[MFD_GPIO_BAR]);
+       ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]);
        if (ret)
                return ret;
 
index c17635d..60b60dc 100644 (file)
@@ -82,29 +82,49 @@ static int mfd_platform_add_cell(struct platform_device *pdev,
 static void mfd_acpi_add_device(const struct mfd_cell *cell,
                                struct platform_device *pdev)
 {
-       struct acpi_device *parent_adev;
+       const struct mfd_cell_acpi_match *match = cell->acpi_match;
+       struct acpi_device *parent, *child;
        struct acpi_device *adev;
 
-       parent_adev = ACPI_COMPANION(pdev->dev.parent);
-       if (!parent_adev)
+       parent = ACPI_COMPANION(pdev->dev.parent);
+       if (!parent)
                return;
 
        /*
-        * MFD child device gets its ACPI handle either from the ACPI
-        * device directly under the parent that matches the acpi_pnpid or
-        * it will use the parent handle if is no acpi_pnpid is given.
+        * MFD child device gets its ACPI handle either from the ACPI device
+        * directly under the parent that matches the either _HID or _CID, or
+        * _ADR or it will use the parent handle if is no ID is given.
+        *
+        * Note that use of _ADR is a grey area in the ACPI specification,
+        * though Intel Galileo Gen2 is using it to distinguish the children
+        * devices.
         */
-       adev = parent_adev;
-       if (cell->acpi_pnpid) {
-               struct acpi_device_id ids[2] = {};
-               struct acpi_device *child_adev;
-
-               strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id));
-               list_for_each_entry(child_adev, &parent_adev->children, node)
-                       if (acpi_match_device_ids(child_adev, ids)) {
-                               adev = child_adev;
-                               break;
+       adev = parent;
+       if (match) {
+               if (match->pnpid) {
+                       struct acpi_device_id ids[2] = {};
+
+                       strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
+                       list_for_each_entry(child, &parent->children, node) {
+                               if (acpi_match_device_ids(child, ids)) {
+                                       adev = child;
+                                       break;
+                               }
+                       }
+               } else {
+                       unsigned long long adr;
+                       acpi_status status;
+
+                       list_for_each_entry(child, &parent->children, node) {
+                               status = acpi_evaluate_integer(child->handle,
+                                                              "_ADR", NULL,
+                                                              &adr);
+                               if (ACPI_SUCCESS(status) && match->adr == adr) {
+                                       adev = child;
+                                       break;
+                               }
                        }
+               }
        }
 
        ACPI_COMPANION_SET(&pdev->dev, adev);
index c6cb7f8..5d7c090 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 #include <linux/of.h>
+#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/at24.h>
 
@@ -131,6 +132,12 @@ static const struct i2c_device_id at24_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, at24_ids);
 
+static const struct acpi_device_id at24_acpi_ids[] = {
+       { "INT3499", AT24_DEVICE_MAGIC(8192 / 8, 0) },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -467,21 +474,29 @@ static void at24_get_ofdata(struct i2c_client *client,
 static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct at24_platform_data chip;
+       kernel_ulong_t magic = 0;
        bool writable;
        int use_smbus = 0;
        int use_smbus_write = 0;
        struct at24_data *at24;
        int err;
        unsigned i, num_addresses;
-       kernel_ulong_t magic;
 
        if (client->dev.platform_data) {
                chip = *(struct at24_platform_data *)client->dev.platform_data;
        } else {
-               if (!id->driver_data)
+               if (id) {
+                       magic = id->driver_data;
+               } else {
+                       const struct acpi_device_id *aid;
+
+                       aid = acpi_match_device(at24_acpi_ids, &client->dev);
+                       if (aid)
+                               magic = aid->driver_data;
+               }
+               if (!magic)
                        return -ENODEV;
 
-               magic = id->driver_data;
                chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
                magic >>= AT24_SIZE_BYTELEN;
                chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
@@ -661,6 +676,7 @@ static int at24_remove(struct i2c_client *client)
 static struct i2c_driver at24_driver = {
        .driver = {
                .name = "at24",
+               .acpi_match_table = ACPI_PTR(at24_acpi_ids),
        },
        .probe = at24_probe,
        .remove = at24_remove,
index 48851f6..dcf2653 100644 (file)
@@ -686,7 +686,7 @@ static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
 
        if (get_user(nmsgs, &udata->nmsgs))
                return -EFAULT;
-       if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+       if (nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
                return -EINVAL;
 
        if (get_user(datap, &udata->msgs))
index d863e12..55af199 100644 (file)
@@ -480,6 +480,11 @@ static inline bool has_acpi_companion(struct device *dev)
        return false;
 }
 
+static inline void acpi_preset_companion(struct device *dev,
+                                        struct acpi_device *parent, u64 addr)
+{
+}
+
 static inline const char *acpi_dev_name(struct acpi_device *adev)
 {
        return NULL;
index 1c06b5c..01edd96 100644 (file)
@@ -15,6 +15,7 @@ struct ocores_i2c_platform_data {
        u32 reg_shift; /* register offset shift value */
        u32 reg_io_width; /* register io read/write width */
        u32 clock_khz; /* input clock in kHz */
+       bool big_endian; /* registers are big endian */
        u8 num_devices; /* number of devices in the devices list */
        struct i2c_board_info const *devices; /* devices connected to the bus */
 };
diff --git a/include/linux/i2c/i2c-rcar.h b/include/linux/i2c/i2c-rcar.h
deleted file mode 100644 (file)
index 496f5c2..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __I2C_R_CAR_H__
-#define __I2C_R_CAR_H__
-
-#include <linux/platform_device.h>
-
-struct i2c_rcar_platform_data {
-       u32 bus_speed;
-};
-
-#endif /* __I2C_R_CAR_H__ */
index a76bc10..27dac3f 100644 (file)
 
 struct irq_domain;
 
+/* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
+struct mfd_cell_acpi_match {
+       const char                      *pnpid;
+       const unsigned long long        adr;
+};
+
 /*
  * This struct describes the MFD part ("cell").
  * After registration the copy of this structure will become the platform data
@@ -44,8 +50,8 @@ struct mfd_cell {
         */
        const char              *of_compatible;
 
-       /* Matches ACPI PNP id, either _HID or _CID */
-       const char              *acpi_pnpid;
+       /* Matches ACPI */
+       const struct mfd_cell_acpi_match        *acpi_match;
 
        /*
         * These resources can be specified relative to the parent device.
index 3f31155..2f05e66 100644 (file)
@@ -66,7 +66,9 @@ struct i2c_rdwr_ioctl_data {
        __u32 nmsgs;                    /* number of i2c_msgs */
 };
 
-#define  I2C_RDRW_IOCTL_MAX_MSGS       42
+#define  I2C_RDWR_IOCTL_MAX_MSGS       42
+/* Originally defined with a typo, keep it for compatibility */
+#define  I2C_RDRW_IOCTL_MAX_MSGS       I2C_RDWR_IOCTL_MAX_MSGS
 
 
 #endif /* _UAPI_LINUX_I2C_DEV_H */