Merge branch 'i2c/for-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 21 Feb 2015 20:41:50 +0000 (12:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 21 Feb 2015 20:41:50 +0000 (12:41 -0800)
Pull i2c updates from Wolfram Sang:
 "Summary:

   - legacy PM code removed from the core, there were no users anymore
     (thanks to Lars-Peter Clausen)

   - new driver for Broadcom iProc

   - bigger driver updates for designware, rk3x, cadence, ocores

   - a bunch of smaller updates and bugfixes"

* 'i2c/for-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (31 commits)
  i2c: ocores: rework clk code to handle NULL cookie
  i2c: designware-baytrail: another fixup for proper Kconfig dependencies
  i2c: fix reference to functionality constants definition
  i2c: iproc: Add Broadcom iProc I2C Driver
  i2c: designware-pci: update Intel copyright line
  i2c: ocores: add common clock support
  i2c: hix5hd2: add COMPILE_TEST
  i2c: clarify comments about the dev_released completion
  i2c: ocores: fix clock-frequency binding usage
  i2c: tegra: Maintain CPU endianness
  i2c: designware-baytrail: use proper Kconfig dependencies
  i2c: designware: Do not calculate SCL timing parameters needlessly
  i2c: do not try to load modules for of-registered devices
  i2c: designware: Add Intel Baytrail PMIC I2C bus support
  i2c: designware: Add i2c bus locking support
  of: i2c: Add i2c-mux-idle-disconnect DT property to PCA954x mux driver
  i2c: designware: use {readl|writel}_relaxed instead of readl/writel
  i2c: designware-pci: no need to provide clk_khz
  i2c: designware-pci: remove Moorestown support
  i2c: imx: whitespace and checkpatch cleanup
  ...

23 files changed:
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
Documentation/devicetree/bindings/i2c/i2c-ocores.txt
Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
Documentation/devicetree/bindings/i2c/trivial-devices.txt
Documentation/i2c/functionality
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-bcm-iproc.c [new file with mode: 0644]
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-designware-baytrail.c [new file with mode: 0644]
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-imx.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/i2c-core.c
drivers/i2c/muxes/i2c-mux-pca954x.c
include/linux/i2c.h

diff --git a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
new file mode 100644 (file)
index 0000000..81f982c
--- /dev/null
@@ -0,0 +1,37 @@
+Broadcom iProc I2C controller
+
+Required properties:
+
+- compatible:
+    Must be "brcm,iproc-i2c"
+
+- reg:
+    Define the base and range of the I/O address space that contain the iProc
+    I2C controller registers
+
+- interrupts:
+    Should contain the I2C interrupt
+
+- clock-frequency:
+    This is the I2C bus clock. Need to be either 100000 or 400000
+
+- #address-cells:
+    Always 1 (for I2C addresses)
+
+- #size-cells:
+    Always 0
+
+Example:
+       i2c0: i2c@18008000 {
+               compatible = "brcm,iproc-i2c";
+               reg = <0x18008000 0x100>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
+               clock-frequency = <100000>;
+
+               codec: wm8750@1a {
+                       compatible = "wlf,wm8750";
+                       reg = <0x1a>;
+               };
+       };
index 34a3fb6f8488b26a9c5def9866898d807ee7df55..cf53d5fba20a0934c631b8320e538cbc5440e155 100644 (file)
@@ -16,6 +16,9 @@ Required Properties:
 Optional Properties:
 
   - reset-gpios: Reference to the GPIO connected to the reset input.
+  - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
+    children in idle state. This is necessary for example, if there are several
+    multiplexers on the bus and the devices behind them use same I2C addresses.
 
 
 Example:
index 1637c298a1b337bf83612cb12129001ecd11da24..17bef9a34e507541ea3f201039b04e199e551fa3 100644 (file)
@@ -4,24 +4,60 @@ Required properties:
 - compatible      : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
 - reg             : bus address start and address range size of device
 - interrupts      : interrupt number
-- clock-frequency : frequency of bus clock in Hz
+- clocks          : handle to the controller clock; see the note below.
+                    Mutually exclusive with opencores,ip-clock-frequency
+- opencores,ip-clock-frequency: frequency of the controller clock in Hz;
+                    see the note below. Mutually exclusive with clocks
 - #address-cells  : should be <1>
 - #size-cells     : should be <0>
 
 Optional properties:
+- clock-frequency : frequency of bus clock in Hz; see the note below.
+                    Defaults to 100 KHz when the property is not specified
 - reg-shift       : device register offsets are shifted by this value
 - reg-io-width    : io register width in bytes (1, 2 or 4)
 - regstep         : deprecated, use reg-shift above
 
-Example:
+Note
+clock-frequency property is meant to control the bus frequency for i2c bus
+drivers, but it was incorrectly used to specify i2c controller input clock
+frequency. So the following rules are set to fix this situation:
+- if clock-frequency is present and neither opencores,ip-clock-frequency nor
+  clocks are, then clock-frequency specifies i2c controller clock frequency.
+  This is to keep backwards compatibility with setups using old DTB. i2c bus
+  frequency is fixed at 100 KHz.
+- if clocks is present it specifies i2c controller clock. clock-frequency
+  property specifies i2c bus frequency.
+- if opencores,ip-clock-frequency is present it specifies i2c controller
+  clock frequency. clock-frequency property specifies i2c bus frequency.
 
+Examples:
+
+       i2c0: ocores@a0000000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "opencores,i2c-ocores";
+               reg = <0xa0000000 0x8>;
+               interrupts = <10>;
+               opencores,ip-clock-frequency = <20000000>;
+
+               reg-shift = <0>;        /* 8 bit registers */
+               reg-io-width = <1>;     /* 8 bit read/write */
+
+               dummy@60 {
+                       compatible = "dummy";
+                       reg = <0x60>;
+               };
+       };
+or
        i2c0: ocores@a0000000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "opencores,i2c-ocores";
                reg = <0xa0000000 0x8>;
                interrupts = <10>;
-               clock-frequency = <20000000>;
+               clocks = <&osc>;
+               clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
 
                reg-shift = <0>;        /* 8 bit registers */
                reg-io-width = <1>;     /* 8 bit read/write */
index dde6c22ce91a13df20eaab99ebd6dbf684983768..f0d71bc52e64be39cea42a7cc04b1e05662ad641 100644 (file)
@@ -21,6 +21,17 @@ Required on RK3066, RK3188 :
 Optional properties :
 
  - clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used.
+ - i2c-scl-rising-time-ns : Number of nanoseconds the SCL signal takes to rise
+       (t(r) in I2C specification). If not specified this is assumed to be
+       the maximum the specification allows(1000 ns for Standard-mode,
+       300 ns for Fast-mode) which might cause slightly slower communication.
+ - i2c-scl-falling-time-ns : Number of nanoseconds the SCL signal takes to fall
+       (t(f) in the I2C specification). If not specified this is assumed to
+       be the maximum the specification allows (300 ns) which might cause
+       slightly slower communication.
+ - i2c-sda-falling-time-ns : Number of nanoseconds the SDA signal takes to fall
+       (t(f) in the I2C specification). If not specified we'll use the SCL
+       value since they are the same in nearly all cases.
 
 Example:
 
@@ -39,4 +50,7 @@ i2c0: i2c@2002d000 {
 
        clock-names = "i2c";
        clocks = <&cru PCLK_I2C0>;
+
+       i2c-scl-rising-time-ns = <800>;
+       i2c-scl-falling-time-ns = <100>;
 };
index 4dcd88d5f7ca453503120236a2ee3670ac7a55e8..aaa8325004d23ae6313223594817f392c1a31359 100644 (file)
@@ -61,9 +61,8 @@ fsl,sgtl5000          SGTL5000: Ultra Low-Power Audio Codec
 gmt,g751               G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
 infineon,slb9635tt     Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
 infineon,slb9645tt     Infineon SLB9645 I2C TPM (new protocol, max 400khz)
-isl,isl12057           Intersil ISL12057 I2C RTC Chip
-isil,isl29028           (deprecated, use isl)
-isl,isl29028            Intersil ISL29028 Ambient Light and Proximity Sensor
+isil,isl12057          Intersil ISL12057 I2C RTC Chip
+isil,isl29028          Intersil ISL29028 Ambient Light and Proximity Sensor
 maxim,ds1050           5 Bit Programmable, Pulse-Width Modulator
 maxim,max1237          Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
 maxim,max6625          9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
index 4556a3eb87c454f3db1c9efbd9c057f454c135d6..4aae8ed15873d1d3c1cc8fc9d80d3ef9b42e5654 100644 (file)
@@ -12,7 +12,7 @@ FUNCTIONALITY CONSTANTS
 -----------------------
 
 For the most up-to-date list of functionality constants, please check
-<linux/i2c.h>!
+<uapi/linux/i2c.h>!
 
   I2C_FUNC_I2C                    Plain i2c-level commands (Pure SMBus
                                   adapters typically can not do these)
index ab838d9e28b6389dc6d97dc633ea6259d2126ca3..22da9c2ffa2250cad9a7172bdbc94890d659a744 100644 (file)
@@ -79,7 +79,7 @@ config I2C_AMD8111
 
 config I2C_HIX5HD2
        tristate "Hix5hd2 high-speed I2C driver"
-       depends on ARCH_HIX5HD2
+       depends on ARCH_HIX5HD2 || COMPILE_TEST
        help
          Say Y here to include support for high-speed I2C controller in the
          Hisilicon based hix5hd2 SoCs.
@@ -372,6 +372,16 @@ config I2C_BCM2835
          This support is also available as a module.  If so, the module
          will be called i2c-bcm2835.
 
+config I2C_BCM_IPROC
+       tristate "Broadcom iProc I2C controller"
+       depends on ARCH_BCM_IPROC || COMPILE_TEST
+       default ARCH_BCM_IPROC
+       help
+         If you say yes to this option, support will be included for the
+         Broadcom iProc I2C controller.
+
+         If you don't know what to do here, say N.
+
 config I2C_BCM_KONA
        tristate "BCM Kona I2C adapter"
        depends on ARCH_BCM_MOBILE
@@ -465,6 +475,16 @@ config I2C_DESIGNWARE_PCI
          This driver can also be built as a module.  If so, the module
          will be called i2c-designware-pci.
 
+config I2C_DESIGNWARE_BAYTRAIL
+       bool "Intel Baytrail I2C semaphore support"
+       depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI
+       help
+         This driver enables managed host access to the PMIC I2C bus on select
+         Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
+         the host to request uninterrupted access to the PMIC's I2C bus from
+         the platform firmware controlling it. You should say Y if running on
+         a BayTrail system using the AXP288.
+
 config I2C_EFM32
        tristate "EFM32 I2C controller"
        depends on ARCH_EFM32 || COMPILE_TEST
index 56388f658d2f2567cbcf4b38433212c94d0d0faf..3638feb6677e1d6d7991b6d0d831ebc1b99c2e11 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91)                += i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)       += i2c-au1550.o
 obj-$(CONFIG_I2C_AXXIA)                += i2c-axxia.o
 obj-$(CONFIG_I2C_BCM2835)      += i2c-bcm2835.o
+obj-$(CONFIG_I2C_BCM_IPROC)    += i2c-bcm-iproc.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
 obj-$(CONFIG_I2C_CADENCE)      += i2c-cadence.o
 obj-$(CONFIG_I2C_CBUS_GPIO)    += i2c-cbus-gpio.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DAVINCI)     += i2c-davinci.o
 obj-$(CONFIG_I2C_DESIGNWARE_CORE)      += i2c-designware-core.o
 obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM)  += i2c-designware-platform.o
 i2c-designware-platform-objs := i2c-designware-platdrv.o
+i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
 obj-$(CONFIG_I2C_DESIGNWARE_PCI)       += i2c-designware-pci.o
 i2c-designware-pci-objs := i2c-designware-pcidrv.o
 obj-$(CONFIG_I2C_EFM32)                += i2c-efm32.o
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
new file mode 100644 (file)
index 0000000..d3c8915
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define CFG_OFFSET                   0x00
+#define CFG_RESET_SHIFT              31
+#define CFG_EN_SHIFT                 30
+#define CFG_M_RETRY_CNT_SHIFT        16
+#define CFG_M_RETRY_CNT_MASK         0x0f
+
+#define TIM_CFG_OFFSET               0x04
+#define TIM_CFG_MODE_400_SHIFT       31
+
+#define M_FIFO_CTRL_OFFSET           0x0c
+#define M_FIFO_RX_FLUSH_SHIFT        31
+#define M_FIFO_TX_FLUSH_SHIFT        30
+#define M_FIFO_RX_CNT_SHIFT          16
+#define M_FIFO_RX_CNT_MASK           0x7f
+#define M_FIFO_RX_THLD_SHIFT         8
+#define M_FIFO_RX_THLD_MASK          0x3f
+
+#define M_CMD_OFFSET                 0x30
+#define M_CMD_START_BUSY_SHIFT       31
+#define M_CMD_STATUS_SHIFT           25
+#define M_CMD_STATUS_MASK            0x07
+#define M_CMD_STATUS_SUCCESS         0x0
+#define M_CMD_STATUS_LOST_ARB        0x1
+#define M_CMD_STATUS_NACK_ADDR       0x2
+#define M_CMD_STATUS_NACK_DATA       0x3
+#define M_CMD_STATUS_TIMEOUT         0x4
+#define M_CMD_PROTOCOL_SHIFT         9
+#define M_CMD_PROTOCOL_MASK          0xf
+#define M_CMD_PROTOCOL_BLK_WR        0x7
+#define M_CMD_PROTOCOL_BLK_RD        0x8
+#define M_CMD_PEC_SHIFT              8
+#define M_CMD_RD_CNT_SHIFT           0
+#define M_CMD_RD_CNT_MASK            0xff
+
+#define IE_OFFSET                    0x38
+#define IE_M_RX_FIFO_FULL_SHIFT      31
+#define IE_M_RX_THLD_SHIFT           30
+#define IE_M_START_BUSY_SHIFT        28
+
+#define IS_OFFSET                    0x3c
+#define IS_M_RX_FIFO_FULL_SHIFT      31
+#define IS_M_RX_THLD_SHIFT           30
+#define IS_M_START_BUSY_SHIFT        28
+
+#define M_TX_OFFSET                  0x40
+#define M_TX_WR_STATUS_SHIFT         31
+#define M_TX_DATA_SHIFT              0
+#define M_TX_DATA_MASK               0xff
+
+#define M_RX_OFFSET                  0x44
+#define M_RX_STATUS_SHIFT            30
+#define M_RX_STATUS_MASK             0x03
+#define M_RX_PEC_ERR_SHIFT           29
+#define M_RX_DATA_SHIFT              0
+#define M_RX_DATA_MASK               0xff
+
+#define I2C_TIMEOUT_MESC             100
+#define M_TX_RX_FIFO_SIZE            64
+
+enum bus_speed_index {
+       I2C_SPD_100K = 0,
+       I2C_SPD_400K,
+};
+
+struct bcm_iproc_i2c_dev {
+       struct device *device;
+       int irq;
+
+       void __iomem *base;
+
+       struct i2c_adapter adapter;
+
+       struct completion done;
+       int xfer_is_done;
+};
+
+/*
+ * Can be expanded in the future if more interrupt status bits are utilized
+ */
+#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT)
+
+static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
+{
+       struct bcm_iproc_i2c_dev *iproc_i2c = data;
+       u32 status = readl(iproc_i2c->base + IS_OFFSET);
+
+       status &= ISR_MASK;
+
+       if (!status)
+               return IRQ_NONE;
+
+       writel(status, iproc_i2c->base + IS_OFFSET);
+       iproc_i2c->xfer_is_done = 1;
+       complete_all(&iproc_i2c->done);
+
+       return IRQ_HANDLED;
+}
+
+static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
+                                     struct i2c_msg *msg)
+{
+       u32 val;
+
+       val = readl(iproc_i2c->base + M_CMD_OFFSET);
+       val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
+
+       switch (val) {
+       case M_CMD_STATUS_SUCCESS:
+               return 0;
+
+       case M_CMD_STATUS_LOST_ARB:
+               dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
+               return -EAGAIN;
+
+       case M_CMD_STATUS_NACK_ADDR:
+               dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
+               return -ENXIO;
+
+       case M_CMD_STATUS_NACK_DATA:
+               dev_dbg(iproc_i2c->device, "NAK data\n");
+               return -ENXIO;
+
+       case M_CMD_STATUS_TIMEOUT:
+               dev_dbg(iproc_i2c->device, "bus timeout\n");
+               return -ETIMEDOUT;
+
+       default:
+               dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
+               return -EIO;
+       }
+}
+
+static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
+                                        struct i2c_msg *msg)
+{
+       int ret, i;
+       u8 addr;
+       u32 val;
+       unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
+
+       /* need to reserve one byte in the FIFO for the slave address */
+       if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
+               dev_err(iproc_i2c->device,
+                       "only support data length up to %u bytes\n",
+                       M_TX_RX_FIFO_SIZE - 1);
+               return -EOPNOTSUPP;
+       }
+
+       /* check if bus is busy */
+       if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
+              BIT(M_CMD_START_BUSY_SHIFT))) {
+               dev_warn(iproc_i2c->device, "bus is busy\n");
+               return -EBUSY;
+       }
+
+       /* format and load slave address into the TX FIFO */
+       addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
+       writel(addr, iproc_i2c->base + M_TX_OFFSET);
+
+       /* for a write transaction, load data into the TX FIFO */
+       if (!(msg->flags & I2C_M_RD)) {
+               for (i = 0; i < msg->len; i++) {
+                       val = msg->buf[i];
+
+                       /* mark the last byte */
+                       if (i == msg->len - 1)
+                               val |= 1 << M_TX_WR_STATUS_SHIFT;
+
+                       writel(val, iproc_i2c->base + M_TX_OFFSET);
+               }
+       }
+
+       /* mark as incomplete before starting the transaction */
+       reinit_completion(&iproc_i2c->done);
+       iproc_i2c->xfer_is_done = 0;
+
+       /*
+        * Enable the "start busy" interrupt, which will be triggered after the
+        * transaction is done, i.e., the internal start_busy bit, transitions
+        * from 1 to 0.
+        */
+       writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET);
+
+       /*
+        * Now we can activate the transfer. For a read operation, specify the
+        * number of bytes to read
+        */
+       val = 1 << M_CMD_START_BUSY_SHIFT;
+       if (msg->flags & I2C_M_RD) {
+               val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
+                      (msg->len << M_CMD_RD_CNT_SHIFT);
+       } else {
+               val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
+       }
+       writel(val, iproc_i2c->base + M_CMD_OFFSET);
+
+       time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
+
+       /* disable all interrupts */
+       writel(0, iproc_i2c->base + IE_OFFSET);
+       /* read it back to flush the write */
+       readl(iproc_i2c->base + IE_OFFSET);
+
+       /* make sure the interrupt handler isn't running */
+       synchronize_irq(iproc_i2c->irq);
+
+       if (!time_left && !iproc_i2c->xfer_is_done) {
+               dev_err(iproc_i2c->device, "transaction timed out\n");
+
+               /* flush FIFOs */
+               val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+                     (1 << M_FIFO_TX_FLUSH_SHIFT);
+               writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+               return -ETIMEDOUT;
+       }
+
+       ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
+       if (ret) {
+               /* flush both TX/RX FIFOs */
+               val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+                     (1 << M_FIFO_TX_FLUSH_SHIFT);
+               writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+               return ret;
+       }
+
+       /*
+        * For a read operation, we now need to load the data from FIFO
+        * into the memory buffer
+        */
+       if (msg->flags & I2C_M_RD) {
+               for (i = 0; i < msg->len; i++) {
+                       msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
+                                     M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
+               }
+       }
+
+       return 0;
+}
+
+static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
+                             struct i2c_msg msgs[], int num)
+{
+       struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
+       int ret, i;
+
+       /* go through all messages */
+       for (i = 0; i < num; i++) {
+               ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
+               if (ret) {
+                       dev_dbg(iproc_i2c->device, "xfer failed\n");
+                       return ret;
+               }
+       }
+
+       return num;
+}
+
+static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm bcm_iproc_algo = {
+       .master_xfer = bcm_iproc_i2c_xfer,
+       .functionality = bcm_iproc_i2c_functionality,
+};
+
+static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+       unsigned int bus_speed;
+       u32 val;
+       int ret = of_property_read_u32(iproc_i2c->device->of_node,
+                                      "clock-frequency", &bus_speed);
+       if (ret < 0) {
+               dev_info(iproc_i2c->device,
+                       "unable to interpret clock-frequency DT property\n");
+               bus_speed = 100000;
+       }
+
+       if (bus_speed < 100000) {
+               dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
+                       bus_speed);
+               dev_err(iproc_i2c->device,
+                       "valid speeds are 100khz and 400khz\n");
+               return -EINVAL;
+       } else if (bus_speed < 400000) {
+               bus_speed = 100000;
+       } else {
+               bus_speed = 400000;
+       }
+
+       val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
+       val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
+       val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
+       writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
+
+       dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
+
+       return 0;
+}
+
+static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+       u32 val;
+
+       /* put controller in reset */
+       val = readl(iproc_i2c->base + CFG_OFFSET);
+       val |= 1 << CFG_RESET_SHIFT;
+       val &= ~(1 << CFG_EN_SHIFT);
+       writel(val, iproc_i2c->base + CFG_OFFSET);
+
+       /* wait 100 usec per spec */
+       udelay(100);
+
+       /* bring controller out of reset */
+       val &= ~(1 << CFG_RESET_SHIFT);
+       writel(val, iproc_i2c->base + CFG_OFFSET);
+
+       /* flush TX/RX FIFOs and set RX FIFO threshold to zero */
+       val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
+       writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+
+       /* disable all interrupts */
+       writel(0, iproc_i2c->base + IE_OFFSET);
+
+       /* clear all pending interrupts */
+       writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
+
+       return 0;
+}
+
+static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
+                                        bool enable)
+{
+       u32 val;
+
+       val = readl(iproc_i2c->base + CFG_OFFSET);
+       if (enable)
+               val |= BIT(CFG_EN_SHIFT);
+       else
+               val &= ~BIT(CFG_EN_SHIFT);
+       writel(val, iproc_i2c->base + CFG_OFFSET);
+}
+
+static int bcm_iproc_i2c_probe(struct platform_device *pdev)
+{
+       int irq, ret = 0;
+       struct bcm_iproc_i2c_dev *iproc_i2c;
+       struct i2c_adapter *adap;
+       struct resource *res;
+
+       iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
+                                GFP_KERNEL);
+       if (!iproc_i2c)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, iproc_i2c);
+       iproc_i2c->device = &pdev->dev;
+       init_completion(&iproc_i2c->done);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res);
+       if (IS_ERR(iproc_i2c->base))
+               return PTR_ERR(iproc_i2c->base);
+
+       ret = bcm_iproc_i2c_init(iproc_i2c);
+       if (ret)
+               return ret;
+
+       ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
+       if (ret)
+               return ret;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(iproc_i2c->device, "no irq resource\n");
+               return irq;
+       }
+       iproc_i2c->irq = irq;
+
+       ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0,
+                              pdev->name, iproc_i2c);
+       if (ret < 0) {
+               dev_err(iproc_i2c->device, "unable to request irq %i\n", irq);
+               return ret;
+       }
+
+       bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+
+       adap = &iproc_i2c->adapter;
+       i2c_set_adapdata(adap, iproc_i2c);
+       strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
+       adap->algo = &bcm_iproc_algo;
+       adap->dev.parent = &pdev->dev;
+       adap->dev.of_node = pdev->dev.of_node;
+
+       ret = i2c_add_adapter(adap);
+       if (ret) {
+               dev_err(iproc_i2c->device, "failed to add adapter\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int bcm_iproc_i2c_remove(struct platform_device *pdev)
+{
+       struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
+
+       /* make sure there's no pending interrupt when we remove the adapter */
+       writel(0, iproc_i2c->base + IE_OFFSET);
+       readl(iproc_i2c->base + IE_OFFSET);
+       synchronize_irq(iproc_i2c->irq);
+
+       i2c_del_adapter(&iproc_i2c->adapter);
+       bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+
+       return 0;
+}
+
+static const struct of_device_id bcm_iproc_i2c_of_match[] = {
+       { .compatible = "brcm,iproc-i2c" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
+
+static struct platform_driver bcm_iproc_i2c_driver = {
+       .driver = {
+               .name = "bcm-iproc-i2c",
+               .of_match_table = bcm_iproc_i2c_of_match,
+       },
+       .probe = bcm_iproc_i2c_probe,
+       .remove = bcm_iproc_i2c_remove,
+};
+module_platform_driver(bcm_iproc_i2c_driver);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
+MODULE_LICENSE("GPL v2");
index 626f74ecd4be4ad40a0b45b2c6730c0afd4b0528..7d7a14cdadfb187d5fd4f95918146c8c6555443a 100644 (file)
  * @suspended:         Flag holding the device's PM status
  * @send_count:                Number of bytes still expected to send
  * @recv_count:                Number of bytes still expected to receive
+ * @curr_recv_count:   Number of bytes to be received in current transfer
  * @irq:               IRQ number
  * @input_clk:         Input clock to I2C controller
  * @i2c_clk:           Maximum I2C clock speed
@@ -146,6 +147,7 @@ struct cdns_i2c {
        u8 suspended;
        unsigned int send_count;
        unsigned int recv_count;
+       unsigned int curr_recv_count;
        int irq;
        unsigned long input_clk;
        unsigned int i2c_clk;
@@ -182,14 +184,15 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
  */
 static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
 {
-       unsigned int isr_status, avail_bytes;
-       unsigned int bytes_to_recv, bytes_to_send;
+       unsigned int isr_status, avail_bytes, updatetx;
+       unsigned int bytes_to_send;
        struct cdns_i2c *id = ptr;
        /* Signal completion only after everything is updated */
        int done_flag = 0;
        irqreturn_t status = IRQ_NONE;
 
        isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+       cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
 
        /* Handling nack and arbitration lost interrupt */
        if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
@@ -197,89 +200,112 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
                status = IRQ_HANDLED;
        }
 
-       /* Handling Data interrupt */
-       if ((isr_status & CDNS_I2C_IXR_DATA) &&
-                       (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) {
-               /* Always read data interrupt threshold bytes */
-               bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH;
-               id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH;
-               avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
-
-               /*
-                * if the tranfer size register value is zero, then
-                * check for the remaining bytes and update the
-                * transfer size register.
-                */
-               if (!avail_bytes) {
-                       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
-                               cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
-                                               CDNS_I2C_XFER_SIZE_OFFSET);
-                       else
-                               cdns_i2c_writereg(id->recv_count,
-                                               CDNS_I2C_XFER_SIZE_OFFSET);
-               }
+       /*
+        * Check if transfer size register needs to be updated again for a
+        * large data receive operation.
+        */
+       updatetx = 0;
+       if (id->recv_count > id->curr_recv_count)
+               updatetx = 1;
+
+       /* When receiving, handle data interrupt and completion interrupt */
+       if (id->p_recv_buf &&
+           ((isr_status & CDNS_I2C_IXR_COMP) ||
+            (isr_status & CDNS_I2C_IXR_DATA))) {
+               /* Read data if receive data valid is set */
+               while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
+                      CDNS_I2C_SR_RXDV) {
+                       /*
+                        * Clear hold bit that was set for FIFO control if
+                        * RX data left is less than FIFO depth, unless
+                        * repeated start is selected.
+                        */
+                       if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) &&
+                           !id->bus_hold_flag)
+                               cdns_i2c_clear_bus_hold(id);
 
-               /* Process the data received */
-               while (bytes_to_recv--)
                        *(id->p_recv_buf)++ =
                                cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+                       id->recv_count--;
+                       id->curr_recv_count--;
 
-               if (!id->bus_hold_flag &&
-                               (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
-                       cdns_i2c_clear_bus_hold(id);
+                       if (updatetx &&
+                           (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1))
+                               break;
+               }
 
-               status = IRQ_HANDLED;
-       }
+               /*
+                * The controller sends NACK to the slave when transfer size
+                * register reaches zero without considering the HOLD bit.
+                * This workaround is implemented for large data transfers to
+                * maintain transfer size non-zero while performing a large
+                * receive operation.
+                */
+               if (updatetx &&
+                   (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) {
+                       /* wait while fifo is full */
+                       while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
+                              (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
+                               ;
 
-       /* Handling Transfer Complete interrupt */
-       if (isr_status & CDNS_I2C_IXR_COMP) {
-               if (!id->p_recv_buf) {
                        /*
-                        * If the device is sending data If there is further
-                        * data to be sent. Calculate the available space
-                        * in FIFO and fill the FIFO with that many bytes.
+                        * Check number of bytes to be received against maximum
+                        * transfer size and update register accordingly.
                         */
-                       if (id->send_count) {
-                               avail_bytes = CDNS_I2C_FIFO_DEPTH -
-                                   cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
-                               if (id->send_count > avail_bytes)
-                                       bytes_to_send = avail_bytes;
-                               else
-                                       bytes_to_send = id->send_count;
-
-                               while (bytes_to_send--) {
-                                       cdns_i2c_writereg(
-                                               (*(id->p_send_buf)++),
-                                                CDNS_I2C_DATA_OFFSET);
-                                       id->send_count--;
-                               }
+                       if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
+                           CDNS_I2C_TRANSFER_SIZE) {
+                               cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+                                                 CDNS_I2C_XFER_SIZE_OFFSET);
+                               id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
+                                                     CDNS_I2C_FIFO_DEPTH;
                        } else {
-                               /*
-                                * Signal the completion of transaction and
-                                * clear the hold bus bit if there are no
-                                * further messages to be processed.
-                                */
-                               done_flag = 1;
+                               cdns_i2c_writereg(id->recv_count -
+                                                 CDNS_I2C_FIFO_DEPTH,
+                                                 CDNS_I2C_XFER_SIZE_OFFSET);
+                               id->curr_recv_count = id->recv_count;
                        }
-                       if (!id->send_count && !id->bus_hold_flag)
-                               cdns_i2c_clear_bus_hold(id);
-               } else {
+               }
+
+               /* Clear hold (if not repeated start) and signal completion */
+               if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
                        if (!id->bus_hold_flag)
                                cdns_i2c_clear_bus_hold(id);
+                       done_flag = 1;
+               }
+
+               status = IRQ_HANDLED;
+       }
+
+       /* When sending, handle transfer complete interrupt */
+       if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
+               /*
+                * If there is more data to be sent, calculate the
+                * space available in FIFO and fill with that many bytes.
+                */
+               if (id->send_count) {
+                       avail_bytes = CDNS_I2C_FIFO_DEPTH -
+                           cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+                       if (id->send_count > avail_bytes)
+                               bytes_to_send = avail_bytes;
+                       else
+                               bytes_to_send = id->send_count;
+
+                       while (bytes_to_send--) {
+                               cdns_i2c_writereg(
+                                       (*(id->p_send_buf)++),
+                                        CDNS_I2C_DATA_OFFSET);
+                               id->send_count--;
+                       }
+               } else {
                        /*
-                        * If the device is receiving data, then signal
-                        * the completion of transaction and read the data
-                        * present in the FIFO. Signal the completion of
-                        * transaction.
+                        * Signal the completion of transaction and
+                        * clear the hold bus bit if there are no
+                        * further messages to be processed.
                         */
-                       while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
-                                       CDNS_I2C_SR_RXDV) {
-                               *(id->p_recv_buf)++ =
-                                       cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
-                               id->recv_count--;
-                       }
                        done_flag = 1;
                }
+               if (!id->send_count && !id->bus_hold_flag)
+                       cdns_i2c_clear_bus_hold(id);
 
                status = IRQ_HANDLED;
        }
@@ -289,8 +315,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
        if (id->err_status)
                status = IRQ_HANDLED;
 
-       cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
-
        if (done_flag)
                complete(&id->xfer_done);
 
@@ -316,6 +340,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
        if (id->p_msg->flags & I2C_M_RECV_LEN)
                id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
 
+       id->curr_recv_count = id->recv_count;
+
        /*
         * Check for the message size against FIFO depth and set the
         * 'hold bus' bit if it is greater than FIFO depth.
@@ -335,11 +361,14 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
         * receive if it is less than transfer size and transfer size if
         * it is more. Enable the interrupts.
         */
-       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
                cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
                                  CDNS_I2C_XFER_SIZE_OFFSET);
-       else
+               id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+       } else {
                cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
+       }
+
        /* Clear the bus hold flag if bytes to receive is less than FIFO size */
        if (!id->bus_hold_flag &&
                ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
@@ -516,6 +545,20 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
         * processed with a repeated start.
         */
        if (num > 1) {
+               /*
+                * This controller does not give completion interrupt after a
+                * master receive message if HOLD bit is set (repeated start),
+                * resulting in SW timeout. Hence, if a receive message is
+                * followed by any other message, an error is returned
+                * indicating that this sequence is not supported.
+                */
+               for (count = 0; count < num - 1; count++) {
+                       if (msgs[count].flags & I2C_M_RD) {
+                               dev_warn(adap->dev.parent,
+                                        "Can't do repeated start after a receive message\n");
+                               return -EOPNOTSUPP;
+                       }
+               }
                id->bus_hold_flag = 1;
                reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
                reg |= CDNS_I2C_CR_HOLD;
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
new file mode 100644 (file)
index 0000000..5f1ff4c
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Intel BayTrail PMIC I2C bus semaphore implementaion
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <asm/iosf_mbi.h>
+#include "i2c-designware-core.h"
+
+#define SEMAPHORE_TIMEOUT      100
+#define PUNIT_SEMAPHORE                0x7
+
+static unsigned long acquired;
+
+static int get_sem(struct device *dev, u32 *sem)
+{
+       u32 reg_val;
+       int ret;
+
+       ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
+                           &reg_val);
+       if (ret) {
+               dev_err(dev, "iosf failed to read punit semaphore\n");
+               return ret;
+       }
+
+       *sem = reg_val & 0x1;
+
+       return 0;
+}
+
+static void reset_semaphore(struct device *dev)
+{
+       u32 data;
+
+       if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
+                               PUNIT_SEMAPHORE, &data)) {
+               dev_err(dev, "iosf failed to reset punit semaphore during read\n");
+               return;
+       }
+
+       data = data & 0xfffffffe;
+       if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
+                                PUNIT_SEMAPHORE, data))
+               dev_err(dev, "iosf failed to reset punit semaphore during write\n");
+}
+
+int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+{
+       u32 sem = 0;
+       int ret;
+       unsigned long start, end;
+
+       if (!dev || !dev->dev)
+               return -ENODEV;
+
+       if (!dev->acquire_lock)
+               return 0;
+
+       /* host driver writes 0x2 to side band semaphore register */
+       ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
+                                PUNIT_SEMAPHORE, 0x2);
+       if (ret) {
+               dev_err(dev->dev, "iosf punit semaphore request failed\n");
+               return ret;
+       }
+
+       /* host driver waits for bit 0 to be set in semaphore register */
+       start = jiffies;
+       end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
+       while (!time_after(jiffies, end)) {
+               ret = get_sem(dev->dev, &sem);
+               if (!ret && sem) {
+                       acquired = jiffies;
+                       dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
+                               jiffies_to_msecs(jiffies - start));
+                       return 0;
+               }
+
+               usleep_range(1000, 2000);
+       }
+
+       dev_err(dev->dev, "punit semaphore timed out, resetting\n");
+       reset_semaphore(dev->dev);
+
+       ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
+               PUNIT_SEMAPHORE, &sem);
+       if (!ret)
+               dev_err(dev->dev, "iosf failed to read punit semaphore\n");
+       else
+               dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
+
+       WARN_ON(1);
+
+       return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(baytrail_i2c_acquire);
+
+void baytrail_i2c_release(struct dw_i2c_dev *dev)
+{
+       if (!dev || !dev->dev)
+               return;
+
+       if (!dev->acquire_lock)
+               return;
+
+       reset_semaphore(dev->dev);
+       dev_dbg(dev->dev, "punit semaphore held for %ums\n",
+               jiffies_to_msecs(jiffies - acquired));
+}
+EXPORT_SYMBOL(baytrail_i2c_release);
+
+int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
+{
+       acpi_status status;
+       unsigned long long shared_host = 0;
+       acpi_handle handle;
+
+       if (!dev || !dev->dev)
+               return 0;
+
+       handle = ACPI_HANDLE(dev->dev);
+       if (!handle)
+               return 0;
+
+       status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
+
+       if (ACPI_FAILURE(status))
+               return 0;
+
+       if (shared_host) {
+               dev_info(dev->dev, "I2C bus managed by PUNIT\n");
+               dev->acquire_lock = baytrail_i2c_acquire;
+               dev->release_lock = baytrail_i2c_release;
+               dev->pm_runtime_disabled = true;
+       }
+
+       if (!iosf_mbi_available())
+               return -EPROBE_DEFER;
+
+       return 0;
+}
+EXPORT_SYMBOL(i2c_dw_eval_lock_support);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
+MODULE_LICENSE("GPL v2");
index 23628b7bfb8d8df208c6e434efb95e887dfad6e6..6e25c010e69037a544ad04f82df46e27e80ca9af 100644 (file)
@@ -170,10 +170,10 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
        u32 value;
 
        if (dev->accessor_flags & ACCESS_16BIT)
-               value = readw(dev->base + offset) |
-                       (readw(dev->base + offset + 2) << 16);
+               value = readw_relaxed(dev->base + offset) |
+                       (readw_relaxed(dev->base + offset + 2) << 16);
        else
-               value = readl(dev->base + offset);
+               value = readl_relaxed(dev->base + offset);
 
        if (dev->accessor_flags & ACCESS_SWAP)
                return swab32(value);
@@ -187,10 +187,10 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
                b = swab32(b);
 
        if (dev->accessor_flags & ACCESS_16BIT) {
-               writew((u16)b, dev->base + offset);
-               writew((u16)(b >> 16), dev->base + offset + 2);
+               writew_relaxed((u16)b, dev->base + offset);
+               writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
        } else {
-               writel(b, dev->base + offset);
+               writel_relaxed(b, dev->base + offset);
        }
 }
 
@@ -285,6 +285,15 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        u32 hcnt, lcnt;
        u32 reg;
        u32 sda_falling_time, scl_falling_time;
+       int ret;
+
+       if (dev->acquire_lock) {
+               ret = dev->acquire_lock(dev);
+               if (ret) {
+                       dev_err(dev->dev, "couldn't acquire bus ownership\n");
+                       return ret;
+               }
+       }
 
        input_clock_khz = dev->get_clk_rate_khz(dev);
 
@@ -298,6 +307,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        } else if (reg != DW_IC_COMP_TYPE_VALUE) {
                dev_err(dev->dev, "Unknown Synopsys component type: "
                        "0x%08x\n", reg);
+               if (dev->release_lock)
+                       dev->release_lock(dev);
                return -ENODEV;
        }
 
@@ -309,40 +320,39 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
        scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
 
-       /* Standard-mode */
-       hcnt = i2c_dw_scl_hcnt(input_clock_khz,
-                               4000,   /* tHD;STA = tHIGH = 4.0 us */
-                               sda_falling_time,
-                               0,      /* 0: DW default, 1: Ideal */
-                               0);     /* No offset */
-       lcnt = i2c_dw_scl_lcnt(input_clock_khz,
-                               4700,   /* tLOW = 4.7 us */
-                               scl_falling_time,
-                               0);     /* No offset */
-
-       /* Allow platforms to specify the ideal HCNT and LCNT values */
+       /* Set SCL timing parameters for standard-mode */
        if (dev->ss_hcnt && dev->ss_lcnt) {
                hcnt = dev->ss_hcnt;
                lcnt = dev->ss_lcnt;
+       } else {
+               hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+                                       4000,   /* tHD;STA = tHIGH = 4.0 us */
+                                       sda_falling_time,
+                                       0,      /* 0: DW default, 1: Ideal */
+                                       0);     /* No offset */
+               lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+                                       4700,   /* tLOW = 4.7 us */
+                                       scl_falling_time,
+                                       0);     /* No offset */
        }
        dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
        dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
        dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
 
-       /* Fast-mode */
-       hcnt = i2c_dw_scl_hcnt(input_clock_khz,
-                               600,    /* tHD;STA = tHIGH = 0.6 us */
-                               sda_falling_time,
-                               0,      /* 0: DW default, 1: Ideal */
-                               0);     /* No offset */
-       lcnt = i2c_dw_scl_lcnt(input_clock_khz,
-                               1300,   /* tLOW = 1.3 us */
-                               scl_falling_time,
-                               0);     /* No offset */
-
+       /* Set SCL timing parameters for fast-mode */
        if (dev->fs_hcnt && dev->fs_lcnt) {
                hcnt = dev->fs_hcnt;
                lcnt = dev->fs_lcnt;
+       } else {
+               hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+                                       600,    /* tHD;STA = tHIGH = 0.6 us */
+                                       sda_falling_time,
+                                       0,      /* 0: DW default, 1: Ideal */
+                                       0);     /* No offset */
+               lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+                                       1300,   /* tLOW = 1.3 us */
+                                       scl_falling_time,
+                                       0);     /* No offset */
        }
        dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
        dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
@@ -364,6 +374,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
        /* configure the i2c master */
        dw_writel(dev, dev->master_cfg , DW_IC_CON);
+
+       if (dev->release_lock)
+               dev->release_lock(dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(i2c_dw_init);
@@ -627,6 +640,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        dev->abort_source = 0;
        dev->rx_outstanding = 0;
 
+       if (dev->acquire_lock) {
+               ret = dev->acquire_lock(dev);
+               if (ret) {
+                       dev_err(dev->dev, "couldn't acquire bus ownership\n");
+                       goto done_nolock;
+               }
+       }
+
        ret = i2c_dw_wait_bus_not_busy(dev);
        if (ret < 0)
                goto done;
@@ -672,6 +693,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        ret = -EIO;
 
 done:
+       if (dev->release_lock)
+               dev->release_lock(dev);
+
+done_nolock:
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
        mutex_unlock(&dev->lock);
index 5a410ef17abd40c0ab7c7ece3ab3fa539adf1f95..9630222abf32197f48d580e43a14b049821f570f 100644 (file)
@@ -61,6 +61,9 @@
  * @ss_lcnt: standard speed LCNT value
  * @fs_hcnt: fast speed HCNT value
  * @fs_lcnt: fast speed LCNT value
+ * @acquire_lock: function to acquire a hardware lock on the bus
+ * @release_lock: function to release a hardware lock on the bus
+ * @pm_runtime_disabled: true if pm runtime is disabled
  *
  * HCNT and LCNT parameters can be used if the platform knows more accurate
  * values than the one computed based only on the input clock frequency.
@@ -101,6 +104,9 @@ struct dw_i2c_dev {
        u16                     ss_lcnt;
        u16                     fs_hcnt;
        u16                     fs_lcnt;
+       int                     (*acquire_lock)(struct dw_i2c_dev *dev);
+       void                    (*release_lock)(struct dw_i2c_dev *dev);
+       bool                    pm_runtime_disabled;
 };
 
 #define ACCESS_SWAP            0x00000001
@@ -119,3 +125,9 @@ 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);
+
+#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
+extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
+#else
+static inline int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) { return 0; }
+#endif
index acb40f95db78f512c561f6d4d2b5b67479844811..6643d2dc0b250ddbf022c669db4fd2b4b4f848e7 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2006 Texas Instruments.
  * Copyright (C) 2007 MontaVista Software Inc.
  * Copyright (C) 2009 Provigent Ltd.
- * Copyright (C) 2011 Intel corporation.
+ * Copyright (C) 2011, 2015 Intel Corporation.
  *
  * ----------------------------------------------------------------------------
  *
 #define DRIVER_NAME "i2c-designware-pci"
 
 enum dw_pci_ctl_id_t {
-       moorestown_0,
-       moorestown_1,
-       moorestown_2,
-
        medfield_0,
        medfield_1,
        medfield_2,
@@ -101,28 +97,7 @@ static struct dw_scl_sda_cfg hsw_config = {
        .sda_hold = 0x9,
 };
 
-static struct  dw_pci_controller  dw_pci_controllers[] = {
-       [moorestown_0] = {
-               .bus_num     = 0,
-               .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
-               .tx_fifo_depth = 32,
-               .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
-       },
-       [moorestown_1] = {
-               .bus_num     = 1,
-               .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
-               .tx_fifo_depth = 32,
-               .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
-       },
-       [moorestown_2] = {
-               .bus_num     = 2,
-               .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
-               .tx_fifo_depth = 32,
-               .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
-       },
+static struct dw_pci_controller dw_pci_controllers[] = {
        [medfield_0] = {
                .bus_num     = 0,
                .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
@@ -170,7 +145,6 @@ static struct  dw_pci_controller  dw_pci_controllers[] = {
                .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz = 100000,
                .functionality = I2C_FUNC_10BIT_ADDR,
                .scl_sda_cfg = &byt_config,
        },
@@ -179,7 +153,6 @@ static struct  dw_pci_controller  dw_pci_controllers[] = {
                .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz = 100000,
                .functionality = I2C_FUNC_10BIT_ADDR,
                .scl_sda_cfg = &hsw_config,
        },
@@ -259,7 +232,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
        dev->functionality = controller->functionality |
                                DW_DEFAULT_FUNCTIONALITY;
 
-       dev->master_cfg =  controller->bus_cfg;
+       dev->master_cfg = controller->bus_cfg;
        if (controller->scl_sda_cfg) {
                cfg = controller->scl_sda_cfg;
                dev->ss_hcnt = cfg->ss_hcnt;
@@ -325,12 +298,8 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
 MODULE_ALIAS("i2c_designware-pci");
 
 static const struct pci_device_id i2_designware_pci_ids[] = {
-       /* Moorestown */
-       { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
-       { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
-       { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
        /* Medfield */
-       { PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
+       { PCI_VDEVICE(INTEL, 0x0817), medfield_3 },
        { PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
        { PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
        { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
@@ -348,7 +317,7 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x9c61), haswell },
        { PCI_VDEVICE(INTEL, 0x9c62), haswell },
        /* Braswell / Cherrytrail */
-       { PCI_VDEVICE(INTEL, 0x22C1), baytrail,},
+       { PCI_VDEVICE(INTEL, 0x22C1), baytrail },
        { PCI_VDEVICE(INTEL, 0x22C2), baytrail },
        { PCI_VDEVICE(INTEL, 0x22C3), baytrail },
        { PCI_VDEVICE(INTEL, 0x22C4), baytrail },
index 2b463c313e4e03305282b76c5fdefa8f90a48874..c270f5f9a8f9af3d3712bbd0f99874708875aa18 100644 (file)
@@ -195,6 +195,10 @@ static int dw_i2c_probe(struct platform_device *pdev)
                        clk_freq = pdata->i2c_scl_freq;
        }
 
+       r = i2c_dw_eval_lock_support(dev);
+       if (r)
+               return r;
+
        dev->functionality =
                I2C_FUNC_I2C |
                I2C_FUNC_10BIT_ADDR |
@@ -257,10 +261,14 @@ static int dw_i2c_probe(struct platform_device *pdev)
                return r;
        }
 
-       pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
-       pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_set_active(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
+       if (dev->pm_runtime_disabled) {
+               pm_runtime_forbid(&pdev->dev);
+       } else {
+               pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+               pm_runtime_use_autosuspend(&pdev->dev);
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_enable(&pdev->dev);
+       }
 
        return 0;
 }
@@ -310,7 +318,9 @@ static int dw_i2c_resume(struct device *dev)
        struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
 
        clk_prepare_enable(i_dev->clk);
-       i2c_dw_init(i_dev);
+
+       if (!i_dev->pm_runtime_disabled)
+               i2c_dw_init(i_dev);
 
        return 0;
 }
index 7f3a9fe9bf4e729a2c446ba905a117a325f17621..d7b26fc6f432005bb02a2394fd4bfb6720271ab1 100644 (file)
@@ -201,7 +201,7 @@ struct imx_i2c_struct {
        void __iomem            *base;
        wait_queue_head_t       queue;
        unsigned long           i2csr;
-       unsigned int            disable_delay;
+       unsigned int            disable_delay;
        int                     stopped;
        unsigned int            ifdr; /* IMX_I2C_IFDR */
        unsigned int            cur_clk;
@@ -295,7 +295,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
        dma->chan_tx = dma_request_slave_channel(dev, "tx");
        if (!dma->chan_tx) {
                dev_dbg(dev, "can't request DMA tx channel\n");
-               ret = -ENODEV;
                goto fail_al;
        }
 
@@ -313,7 +312,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
        dma->chan_rx = dma_request_slave_channel(dev, "rx");
        if (!dma->chan_rx) {
                dev_dbg(dev, "can't request DMA rx channel\n");
-               ret = -ENODEV;
                goto fail_tx;
        }
 
@@ -481,8 +479,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
        i2c_clk_rate = clk_get_rate(i2c_imx->clk);
        if (i2c_imx->cur_clk == i2c_clk_rate)
                return;
-       else
-               i2c_imx->cur_clk = i2c_clk_rate;
+
+       i2c_imx->cur_clk = i2c_clk_rate;
 
        div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
        if (div < i2c_clk_div[0].div)
@@ -490,7 +488,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
        else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
                i = i2c_imx->hwdata->ndivs - 1;
        else
-               for (i = 0; i2c_clk_div[i].div < div; i++);
+               for (i = 0; i2c_clk_div[i].div < div; i++)
+                       ;
 
        /* Store divider value */
        i2c_imx->ifdr = i2c_clk_div[i].val;
@@ -628,9 +627,9 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
        result = wait_for_completion_timeout(
                                &i2c_imx->dma->cmd_complete,
                                msecs_to_jiffies(DMA_TIMEOUT));
-       if (result <= 0) {
+       if (result == 0) {
                dmaengine_terminate_all(dma->chan_using);
-               return result ?: -ETIMEDOUT;
+               return -ETIMEDOUT;
        }
 
        /* Waiting for transfer complete. */
@@ -686,9 +685,9 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
        result = wait_for_completion_timeout(
                                &i2c_imx->dma->cmd_complete,
                                msecs_to_jiffies(DMA_TIMEOUT));
-       if (result <= 0) {
+       if (result == 0) {
                dmaengine_terminate_all(dma->chan_using);
-               return result ?: -ETIMEDOUT;
+               return -ETIMEDOUT;
        }
 
        /* waiting for transfer complete. */
@@ -822,6 +821,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
        /* read data */
        for (i = 0; i < msgs->len; i++) {
                u8 len = 0;
+
                result = i2c_imx_trx_complete(i2c_imx);
                if (result)
                        return result;
@@ -917,15 +917,16 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
                /* write/read data */
 #ifdef CONFIG_I2C_DEBUG_BUS
                temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
-               dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, "
-                       "MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__,
+               dev_dbg(&i2c_imx->adapter.dev,
+                       "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
+                       __func__,
                        (temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
                        (temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
                        (temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
                temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
                dev_dbg(&i2c_imx->adapter.dev,
-                       "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
-                       "IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__,
+                       "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
+                       __func__,
                        (temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
                        (temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
                        (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
@@ -1004,7 +1005,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
        i2c_imx->adapter.owner          = THIS_MODULE;
        i2c_imx->adapter.algo           = &i2c_imx_algo;
        i2c_imx->adapter.dev.parent     = &pdev->dev;
-       i2c_imx->adapter.nr             = pdev->id;
+       i2c_imx->adapter.nr             = pdev->id;
        i2c_imx->adapter.dev.of_node    = pdev->dev.of_node;
        i2c_imx->base                   = base;
 
@@ -1063,7 +1064,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
                i2c_imx->adapter.name);
        dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
 
-       /* Init DMA config if support*/
+       /* Init DMA config if supported */
        i2c_imx_dma_request(i2c_imx, phy_addr);
 
        return 0;   /* Return OK */
index 7249b5b1e5d091bbd9d906d4bc16cd89fbd36d82..abf5db7e441ebab65fc7c8ad99b5f9bca6218b15 100644 (file)
@@ -12,6 +12,7 @@
  * kind, whether express or implied.
  */
 
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -35,7 +36,9 @@ struct ocores_i2c {
        int pos;
        int nmsgs;
        int state; /* see STATE_ */
-       int clock_khz;
+       struct clk *clk;
+       int ip_clock_khz;
+       int bus_clock_khz;
        void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value);
        u8 (*getreg)(struct ocores_i2c *i2c, int reg);
 };
@@ -215,21 +218,34 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                return -ETIMEDOUT;
 }
 
-static void ocores_init(struct ocores_i2c *i2c)
+static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
 {
        int prescale;
+       int diff;
        u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
 
        /* make sure the device is disabled */
        oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
 
-       prescale = (i2c->clock_khz / (5*100)) - 1;
+       prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;
+       prescale = clamp(prescale, 0, 0xffff);
+
+       diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz;
+       if (abs(diff) > i2c->bus_clock_khz / 10) {
+               dev_err(dev,
+                       "Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
+                       i2c->ip_clock_khz, i2c->bus_clock_khz);
+               return -EINVAL;
+       }
+
        oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
        oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
 
        /* Init the device */
        oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
        oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+
+       return 0;
 }
 
 
@@ -304,6 +320,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *match;
        u32 val;
+       u32 clock_frequency;
+       bool clock_frequency_present;
 
        if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
                /* no 'reg-shift', check for deprecated 'regstep' */
@@ -319,12 +337,42 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
                }
        }
 
-       if (of_property_read_u32(np, "clock-frequency", &val)) {
-               dev_err(&pdev->dev,
-                       "Missing required parameter 'clock-frequency'\n");
-               return -ENODEV;
+       clock_frequency_present = !of_property_read_u32(np, "clock-frequency",
+                                                       &clock_frequency);
+       i2c->bus_clock_khz = 100;
+
+       i2c->clk = devm_clk_get(&pdev->dev, NULL);
+
+       if (!IS_ERR(i2c->clk)) {
+               int ret = clk_prepare_enable(i2c->clk);
+
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "clk_prepare_enable failed: %d\n", ret);
+                       return ret;
+               }
+               i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000;
+               if (clock_frequency_present)
+                       i2c->bus_clock_khz = clock_frequency / 1000;
+       }
+
+       if (i2c->ip_clock_khz == 0) {
+               if (of_property_read_u32(np, "opencores,ip-clock-frequency",
+                                               &val)) {
+                       if (!clock_frequency_present) {
+                               dev_err(&pdev->dev,
+                                       "Missing required parameter 'opencores,ip-clock-frequency'\n");
+                               return -ENODEV;
+                       }
+                       i2c->ip_clock_khz = clock_frequency / 1000;
+                       dev_warn(&pdev->dev,
+                                "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");
+               } else {
+                       i2c->ip_clock_khz = val / 1000;
+                       if (clock_frequency_present)
+                               i2c->bus_clock_khz = clock_frequency / 1000;
+               }
        }
-       i2c->clock_khz = val / 1000;
 
        of_property_read_u32(pdev->dev.of_node, "reg-io-width",
                                &i2c->reg_io_width);
@@ -368,7 +416,8 @@ static int ocores_i2c_probe(struct platform_device *pdev)
        if (pdata) {
                i2c->reg_shift = pdata->reg_shift;
                i2c->reg_io_width = pdata->reg_io_width;
-               i2c->clock_khz = pdata->clock_khz;
+               i2c->ip_clock_khz = pdata->clock_khz;
+               i2c->bus_clock_khz = 100;
        } else {
                ret = ocores_i2c_of_probe(pdev, i2c);
                if (ret)
@@ -402,7 +451,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
                }
        }
 
-       ocores_init(i2c);
+       ret = ocores_init(&pdev->dev, i2c);
+       if (ret)
+               return ret;
 
        init_waitqueue_head(&i2c->wait);
        ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
@@ -446,6 +497,9 @@ static int ocores_i2c_remove(struct platform_device *pdev)
        /* remove adapter & data */
        i2c_del_adapter(&i2c->adap);
 
+       if (!IS_ERR(i2c->clk))
+               clk_disable_unprepare(i2c->clk);
+
        return 0;
 }
 
@@ -458,6 +512,8 @@ static int ocores_i2c_suspend(struct device *dev)
        /* make sure the device is disabled */
        oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
 
+       if (!IS_ERR(i2c->clk))
+               clk_disable_unprepare(i2c->clk);
        return 0;
 }
 
@@ -465,9 +521,20 @@ static int ocores_i2c_resume(struct device *dev)
 {
        struct ocores_i2c *i2c = dev_get_drvdata(dev);
 
-       ocores_init(i2c);
+       if (!IS_ERR(i2c->clk)) {
+               unsigned long rate;
+               int ret = clk_prepare_enable(i2c->clk);
 
-       return 0;
+               if (ret) {
+                       dev_err(dev,
+                               "clk_prepare_enable failed: %d\n", ret);
+                       return ret;
+               }
+               rate = clk_get_rate(i2c->clk) / 1000;
+               if (rate)
+                       i2c->ip_clock_khz = rate;
+       }
+       return ocores_init(dev, i2c);
 }
 
 static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
index 44f03eed00dd4f36ae655df26315699556a576a8..d37d9db6681e7b5745a45331ae60737a9b36f99a 100644 (file)
@@ -148,13 +148,6 @@ static inline u32 pmcmsptwi_clock_to_reg(
        return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
 }
 
-static inline void pmcmsptwi_reg_to_clock(
-                       u32 reg, struct pmcmsptwi_clock *clock)
-{
-       clock->filter = (reg >> 12) & 0xf;
-       clock->clock = reg & 0x03ff;
-}
-
 static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
 {
        return ((cfg->arbf & 0xf) << 12) |
index 92462843db663d09b1106468603b1b9eb65243d2..5f96b1b3e3a5a30e2163098e4afe94fc4a06deeb 100644 (file)
@@ -102,6 +102,9 @@ struct rk3x_i2c {
 
        /* Settings */
        unsigned int scl_frequency;
+       unsigned int scl_rise_ns;
+       unsigned int scl_fall_ns;
+       unsigned int sda_fall_ns;
 
        /* Synchronization & notification */
        spinlock_t lock;
@@ -435,6 +438,9 @@ out:
  *
  * @clk_rate: I2C input clock rate
  * @scl_rate: Desired SCL rate
+ * @scl_rise_ns: How many ns it takes for SCL to rise.
+ * @scl_fall_ns: How many ns it takes for SCL to fall.
+ * @sda_fall_ns: How many ns it takes for SDA to fall.
  * @div_low: Divider output for low
  * @div_high: Divider output for high
  *
@@ -443,11 +449,16 @@ out:
  * too high, we silently use the highest possible rate.
  */
 static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
+                             unsigned long scl_rise_ns,
+                             unsigned long scl_fall_ns,
+                             unsigned long sda_fall_ns,
                              unsigned long *div_low, unsigned long *div_high)
 {
-       unsigned long min_low_ns, min_high_ns;
-       unsigned long max_data_hold_ns;
+       unsigned long spec_min_low_ns, spec_min_high_ns;
+       unsigned long spec_setup_start, spec_max_data_hold_ns;
        unsigned long data_hold_buffer_ns;
+
+       unsigned long min_low_ns, min_high_ns;
        unsigned long max_low_ns, min_total_ns;
 
        unsigned long clk_rate_khz, scl_rate_khz;
@@ -469,29 +480,50 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
                scl_rate = 1000;
 
        /*
-        * min_low_ns:  The minimum number of ns we need to hold low
-        *              to meet i2c spec
-        * min_high_ns: The minimum number of ns we need to hold high
-        *              to meet i2c spec
-        * max_low_ns:  The maximum number of ns we can hold low
-        *              to meet i2c spec
+        * min_low_ns:  The minimum number of ns we need to hold low to
+        *              meet I2C specification, should include fall time.
+        * min_high_ns: The minimum number of ns we need to hold high to
+        *              meet I2C specification, should include rise time.
+        * max_low_ns:  The maximum number of ns we can hold low to meet
+        *              I2C specification.
         *
-        * Note: max_low_ns should be (max data hold time * 2 - buffer)
+        * Note: max_low_ns should be (maximum data hold time * 2 - buffer)
         *       This is because the i2c host on Rockchip holds the data line
         *       for half the low time.
         */
        if (scl_rate <= 100000) {
-               min_low_ns = 4700;
-               min_high_ns = 4000;
-               max_data_hold_ns = 3450;
+               /* Standard-mode */
+               spec_min_low_ns = 4700;
+               spec_setup_start = 4700;
+               spec_min_high_ns = 4000;
+               spec_max_data_hold_ns = 3450;
                data_hold_buffer_ns = 50;
        } else {
-               min_low_ns = 1300;
-               min_high_ns = 600;
-               max_data_hold_ns = 900;
+               /* Fast-mode */
+               spec_min_low_ns = 1300;
+               spec_setup_start = 600;
+               spec_min_high_ns = 600;
+               spec_max_data_hold_ns = 900;
                data_hold_buffer_ns = 50;
        }
-       max_low_ns = max_data_hold_ns * 2 - data_hold_buffer_ns;
+       min_high_ns = scl_rise_ns + spec_min_high_ns;
+
+       /*
+        * Timings for repeated start:
+        * - controller appears to drop SDA at .875x (7/8) programmed clk high.
+        * - controller appears to keep SCL high for 2x programmed clk high.
+        *
+        * We need to account for those rules in picking our "high" time so
+        * we meet tSU;STA and tHD;STA times.
+        */
+       min_high_ns = max(min_high_ns,
+               DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
+       min_high_ns = max(min_high_ns,
+               DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
+                             sda_fall_ns + spec_min_high_ns), 2));
+
+       min_low_ns = scl_fall_ns + spec_min_low_ns;
+       max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
        min_total_ns = min_low_ns + min_high_ns;
 
        /* Adjust to avoid overflow */
@@ -510,8 +542,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
        min_div_for_hold = (min_low_div + min_high_div);
 
        /*
-        * This is the maximum divider so we don't go over the max.
-        * We don't round up here (we round down) since this is a max.
+        * This is the maximum divider so we don't go over the maximum.
+        * We don't round up here (we round down) since this is a maximum.
         */
        max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
 
@@ -544,7 +576,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
                ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
                                             scl_rate_khz * 8 * min_total_ns);
 
-               /* Don't allow it to go over the max */
+               /* Don't allow it to go over the maximum */
                if (ideal_low_div > max_low_div)
                        ideal_low_div = max_low_div;
 
@@ -588,9 +620,9 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
        u64 t_low_ns, t_high_ns;
        int ret;
 
-       ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, &div_low,
-                                &div_high);
-
+       ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
+                                i2c->scl_fall_ns, i2c->sda_fall_ns,
+                                &div_low, &div_high);
        WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
 
        clk_enable(i2c->clk);
@@ -633,9 +665,10 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
        switch (event) {
        case PRE_RATE_CHANGE:
                if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
-                                     &div_low, &div_high) != 0) {
+                                      i2c->scl_rise_ns, i2c->scl_fall_ns,
+                                      i2c->sda_fall_ns,
+                                      &div_low, &div_high) != 0)
                        return NOTIFY_STOP;
-               }
 
                /* scale up */
                if (ndata->new_rate > ndata->old_rate)
@@ -859,6 +892,24 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
                i2c->scl_frequency = DEFAULT_SCL_RATE;
        }
 
+       /*
+        * Read rise and fall time from device tree. If not available use
+        * the default maximum timing from the specification.
+        */
+       if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
+                                &i2c->scl_rise_ns)) {
+               if (i2c->scl_frequency <= 100000)
+                       i2c->scl_rise_ns = 1000;
+               else
+                       i2c->scl_rise_ns = 300;
+       }
+       if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
+                                &i2c->scl_fall_ns))
+               i2c->scl_fall_ns = 300;
+       if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
+                                &i2c->scl_fall_ns))
+               i2c->sda_fall_ns = i2c->scl_fall_ns;
+
        strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
        i2c->adap.owner = THIS_MODULE;
        i2c->adap.algo = &rk3x_i2c_algorithm;
index 28b87e683503df42c2bc11ee36c95b505e04f884..29f14331dd9d01fcb5d66f1e74602b61da9593cf 100644 (file)
@@ -286,6 +286,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
        if (rx_fifo_avail > 0 && buf_remaining > 0) {
                BUG_ON(buf_remaining > 3);
                val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+               val = cpu_to_le32(val);
                memcpy(buf, &val, buf_remaining);
                buf_remaining = 0;
                rx_fifo_avail--;
@@ -344,6 +345,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
        if (tx_fifo_avail > 0 && buf_remaining > 0) {
                BUG_ON(buf_remaining > 3);
                memcpy(&val, buf, buf_remaining);
+               val = le32_to_cpu(val);
 
                /* Again update before writing to FIFO to make sure isr sees. */
                i2c_dev->msg_buf_remaining = 0;
index e9eae57a2b50f77e3d25c4d9fcfa003728464740..210cf4874cb7ea2415df5fb3e1d30ec8065de5d4 100644 (file)
@@ -102,7 +102,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
                struct acpi_resource_i2c_serialbus *sb;
 
                sb = &ares->data.i2c_serial_bus;
-               if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+               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;
@@ -698,101 +698,6 @@ static void i2c_device_shutdown(struct device *dev)
                driver->shutdown(client);
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
-{
-       struct i2c_client *client = i2c_verify_client(dev);
-       struct i2c_driver *driver;
-
-       if (!client || !dev->driver)
-               return 0;
-       driver = to_i2c_driver(dev->driver);
-       if (!driver->suspend)
-               return 0;
-       return driver->suspend(client, mesg);
-}
-
-static int i2c_legacy_resume(struct device *dev)
-{
-       struct i2c_client *client = i2c_verify_client(dev);
-       struct i2c_driver *driver;
-
-       if (!client || !dev->driver)
-               return 0;
-       driver = to_i2c_driver(dev->driver);
-       if (!driver->resume)
-               return 0;
-       return driver->resume(client);
-}
-
-static int i2c_device_pm_suspend(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_suspend(dev);
-       else
-               return i2c_legacy_suspend(dev, PMSG_SUSPEND);
-}
-
-static int i2c_device_pm_resume(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_resume(dev);
-       else
-               return i2c_legacy_resume(dev);
-}
-
-static int i2c_device_pm_freeze(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_freeze(dev);
-       else
-               return i2c_legacy_suspend(dev, PMSG_FREEZE);
-}
-
-static int i2c_device_pm_thaw(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_thaw(dev);
-       else
-               return i2c_legacy_resume(dev);
-}
-
-static int i2c_device_pm_poweroff(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_poweroff(dev);
-       else
-               return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
-}
-
-static int i2c_device_pm_restore(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm)
-               return pm_generic_restore(dev);
-       else
-               return i2c_legacy_resume(dev);
-}
-#else /* !CONFIG_PM_SLEEP */
-#define i2c_device_pm_suspend  NULL
-#define i2c_device_pm_resume   NULL
-#define i2c_device_pm_freeze   NULL
-#define i2c_device_pm_thaw     NULL
-#define i2c_device_pm_poweroff NULL
-#define i2c_device_pm_restore  NULL
-#endif /* !CONFIG_PM_SLEEP */
-
 static void i2c_client_dev_release(struct device *dev)
 {
        kfree(to_i2c_client(dev));
@@ -804,6 +709,7 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
                       to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
 }
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 static ssize_t
 show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
@@ -817,8 +723,6 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
 
        return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
 }
-
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
 static struct attribute *i2c_dev_attrs[] = {
@@ -827,29 +731,7 @@ static struct attribute *i2c_dev_attrs[] = {
        &dev_attr_modalias.attr,
        NULL
 };
-
-static struct attribute_group i2c_dev_attr_group = {
-       .attrs          = i2c_dev_attrs,
-};
-
-static const struct attribute_group *i2c_dev_attr_groups[] = {
-       &i2c_dev_attr_group,
-       NULL
-};
-
-static const struct dev_pm_ops i2c_device_pm_ops = {
-       .suspend = i2c_device_pm_suspend,
-       .resume = i2c_device_pm_resume,
-       .freeze = i2c_device_pm_freeze,
-       .thaw = i2c_device_pm_thaw,
-       .poweroff = i2c_device_pm_poweroff,
-       .restore = i2c_device_pm_restore,
-       SET_RUNTIME_PM_OPS(
-               pm_generic_runtime_suspend,
-               pm_generic_runtime_resume,
-               NULL
-       )
-};
+ATTRIBUTE_GROUPS(i2c_dev);
 
 struct bus_type i2c_bus_type = {
        .name           = "i2c",
@@ -857,12 +739,11 @@ struct bus_type i2c_bus_type = {
        .probe          = i2c_device_probe,
        .remove         = i2c_device_remove,
        .shutdown       = i2c_device_shutdown,
-       .pm             = &i2c_device_pm_ops,
 };
 EXPORT_SYMBOL_GPL(i2c_bus_type);
 
 static struct device_type i2c_client_type = {
-       .groups         = i2c_dev_attr_groups,
+       .groups         = i2c_dev_groups,
        .uevent         = i2c_device_uevent,
        .release        = i2c_client_dev_release,
 };
@@ -1261,6 +1142,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
 
        return count;
 }
+static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
 
 /*
  * And of course let the users delete the devices they instantiated, if
@@ -1315,8 +1197,6 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
                        "delete_device");
        return res;
 }
-
-static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
 static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
                                   i2c_sysfs_delete_device);
 
@@ -1326,18 +1206,10 @@ static struct attribute *i2c_adapter_attrs[] = {
        &dev_attr_delete_device.attr,
        NULL
 };
-
-static struct attribute_group i2c_adapter_attr_group = {
-       .attrs          = i2c_adapter_attrs,
-};
-
-static const struct attribute_group *i2c_adapter_attr_groups[] = {
-       &i2c_adapter_attr_group,
-       NULL
-};
+ATTRIBUTE_GROUPS(i2c_adapter);
 
 struct device_type i2c_adapter_type = {
-       .groups         = i2c_adapter_attr_groups,
+       .groups         = i2c_adapter_groups,
        .release        = i2c_adapter_dev_release,
 };
 EXPORT_SYMBOL_GPL(i2c_adapter_type);
@@ -1419,8 +1291,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
        if (of_get_property(node, "wakeup-source", NULL))
                info.flags |= I2C_CLIENT_WAKE;
 
-       request_module("%s%s", I2C_MODULE_PREFIX, info.type);
-
        result = i2c_new_device(adap, &info);
        if (result == NULL) {
                dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
@@ -1796,11 +1666,15 @@ void i2c_del_adapter(struct i2c_adapter *adap)
        /* device name is gone after device_unregister */
        dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
-       /* clean up the sysfs representation */
+       /* wait until all references to the device are gone
+        *
+        * FIXME: This is old code and should ideally be replaced by an
+        * alternative which results in decoupling the lifetime of the struct
+        * device from the i2c_adapter, like spi or netdev do. Any solution
+        * should be throughly tested with DEBUG_KOBJECT_RELEASE enabled!
+        */
        init_completion(&adap->dev_released);
        device_unregister(&adap->dev);
-
-       /* wait for sysfs to drop all references */
        wait_for_completion(&adap->dev_released);
 
        /* free bus id */
@@ -1859,14 +1733,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        if (res)
                return res;
 
-       /* Drivers should switch to dev_pm_ops instead. */
-       if (driver->suspend)
-               pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
-                       driver->driver.name);
-       if (driver->resume)
-               pr_warn("i2c-core: driver [%s] using legacy resume method\n",
-                       driver->driver.name);
-
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
        INIT_LIST_HEAD(&driver->clients);
index ec11b404b433737657957ef9dd0e559a955b45aa..3d8f4fe2e47e52eefff7da7967fe41bf0fafe801 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/i2c-mux.h>
 #include <linux/i2c/pca954x.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 
@@ -186,6 +187,8 @@ static int pca954x_probe(struct i2c_client *client,
 {
        struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
        struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct device_node *of_node = client->dev.of_node;
+       bool idle_disconnect_dt;
        struct gpio_desc *gpio;
        int num, force, class;
        struct pca954x *data;
@@ -217,8 +220,13 @@ static int pca954x_probe(struct i2c_client *client,
        data->type = id->driver_data;
        data->last_chan = 0;               /* force the first selection */
 
+       idle_disconnect_dt = of_node &&
+               of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
+
        /* Now create an adapter for each channel */
        for (num = 0; num < chips[data->type].nchans; num++) {
+               bool idle_disconnect_pd = false;
+
                force = 0;                        /* dynamic adap number */
                class = 0;                        /* no class by default */
                if (pdata) {
@@ -229,12 +237,13 @@ static int pca954x_probe(struct i2c_client *client,
                        } else
                                /* discard unconfigured channels */
                                break;
+                       idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
                }
 
                data->virt_adaps[num] =
                        i2c_add_mux_adapter(adap, &client->dev, client,
                                force, num, class, pca954x_select_chan,
-                               (pdata && pdata->modes[num].deselect_on_exit)
+                               (idle_disconnect_pd || idle_disconnect_dt)
                                        ? pca954x_deselect_mux : NULL);
 
                if (data->virt_adaps[num] == NULL) {
index 7c7695940dddeae9d3d22129ce4a14eaf70e1a5e..f17da50402a4dad6bf4d4aa907a32e8df1d7dea7 100644 (file)
@@ -130,8 +130,6 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
  * @probe: Callback for device binding
  * @remove: Callback for device unbinding
  * @shutdown: Callback for device shutdown
- * @suspend: Callback for device suspend
- * @resume: Callback for device resume
  * @alert: Alert callback, for example for the SMBus alert protocol
  * @command: Callback for bus-wide signaling (optional)
  * @driver: Device driver model driver
@@ -174,8 +172,6 @@ struct i2c_driver {
 
        /* driver model interfaces that don't relate to enumeration  */
        void (*shutdown)(struct i2c_client *);
-       int (*suspend)(struct i2c_client *, pm_message_t mesg);
-       int (*resume)(struct i2c_client *);
 
        /* Alert callback, for example for the SMBus alert protocol.
         * The format and meaning of the data value depends on the protocol.