Merge branch 'i2c-embedded/for-next' of git://git.pengutronix.de/git/wsa/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Oct 2012 01:27:51 +0000 (10:27 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Oct 2012 01:27:51 +0000 (10:27 +0900)
Pull i2c-embedded changes from Wolfram Sang:
 "The changes for i2c-embedded include:

   - massive rework of the omap driver
   - massive rework of the at91 driver.  In fact, the old driver gets
     removed; I am okay with this approach since the old driver was
     depending on BROKEN and its limitations made it practically
     unusable, so people used bitbanging instead.  But even if there are
     users, there is no platform_data or module parameter which would
     need to be converted.  It is just another driver doing I2C
     transfers, just way better.  Modifications of arch/arm/at91 related
     files have proper acks from the maintainer.
   - new driver for R-Car I2C
   - devicetree and generic_clock conversions and fixes
   - usual driver fixes and changes.

  The rework patches have come a long way and lots of people have been
  involved in creating/testing them.  Most patches have been in
  linux-next at least since 3.6-rc5.  A few have been added in the last
  week, I have to admit.

  An unexpected (but welcome :)) peak in private life is the cause for
  that.  The "late" patches shouldn't cause any merge conflicts and I
  will have a special eye on them during the stabilization phase.  This
  is an exception and I want to have the patches in place properly in
  time again for the next kernels."

* 'i2c-embedded/for-next' of git://git.pengutronix.de/git/wsa/linux: (44 commits)
  MXS: Implement DMA support into mxs-i2c
  i2c: add Renesas R-Car I2C driver
  i2c: s3c2410: use clk_prepare_enable and clk_disable_unprepare
  ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints
  i2c: nomadik: Add Device Tree support to the Nomadik I2C driver
  i2c: algo: pca: Fix chip reset function for PCA9665
  i2c: mpc: Wait for STOP to hit the bus
  i2c: davinci: preparation for switch to common clock framework
  omap-i2c: fix incorrect log message when using a device tree
  i2c: omap: sanitize exit path
  i2c: omap: switch over to autosuspend API
  i2c: omap: remove unnecessary pm_runtime_suspended check
  i2c: omap: switch to threaded IRQ support
  i2c: omap: remove redundant status read
  i2c: omap: get rid of the "complete" label
  i2c: omap: resize fifos before each message
  i2c: omap: simplify IRQ exit path
  i2c: omap: always return IRQ_HANDLED
  i2c: omap: simplify errata check
  i2c: omap: bus: add a receiver flag
  ...

46 files changed:
Documentation/devicetree/bindings/i2c/atmel-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/davinci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-mxs.txt
Documentation/devicetree/bindings/i2c/nomadik.txt [new file with mode: 0644]
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g20.dtsi
arch/arm/boot/dts/at91sam9g25ek.dts
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9n12ek.dts
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/imx28.dtsi
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9n12.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91sam9x5.c
arch/arm/mach-at91/include/mach/at91_twi.h [deleted file]
arch/arm/plat-omap/i2c.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-rcar.c [new file with mode: 0644]
drivers/i2c/busses/i2c-s3c2410.c
include/linux/i2c-algo-pca.h
include/linux/i2c-omap.h
include/linux/i2c/i2c-rcar.h [new file with mode: 0644]
include/linux/platform_data/i2c-nomadik.h

diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
new file mode 100644 (file)
index 0000000..b689a0d
--- /dev/null
@@ -0,0 +1,30 @@
+I2C for Atmel platforms
+
+Required properties :
+- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
+     "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c"
+     or "atmel,at91sam9x5-i2c"
+- reg: physical base address of the controller and length of memory mapped
+     region.
+- interrupts: interrupt number to the cpu.
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
+
+Examples :
+
+i2c0: i2c@fff84000 {
+       compatible = "atmel,at91sam9g20-i2c";
+       reg = <0xfff84000 0x100>;
+       interrupts = <12 4 6>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       24c512@50 {
+               compatible = "24c512";
+               reg = <0x50>;
+               pagesize = <128>;
+       }
+}
diff --git a/Documentation/devicetree/bindings/i2c/davinci.txt b/Documentation/devicetree/bindings/i2c/davinci.txt
new file mode 100644 (file)
index 0000000..2dc935b
--- /dev/null
@@ -0,0 +1,28 @@
+* Texas Instruments Davinci I2C
+
+This file provides information, what the device node for the
+davinci i2c interface contain.
+
+Required properties:
+- compatible: "ti,davinci-i2c";
+- reg : Offset and length of the register set for the device
+
+Recommended properties :
+- interrupts : standard interrupt property.
+- clock-frequency : desired I2C bus clock frequency in Hz.
+
+Example (enbw_cmc board):
+       i2c@1c22000 {
+               compatible = "ti,davinci-i2c";
+               reg = <0x22000 0x1000>;
+               clock-frequency = <100000>;
+               interrupts = <15>;
+               interrupt-parent = <&intc>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               dtt@48 {
+                       compatible = "national,lm75";
+                       reg = <0x48>;
+               };
+       };
index 30ac3a0557f7d8c99a3660cbaf6ef2d718f3f3a9..7a3fe9e5f4cbb1a95cd23f2241f649afb4e3df87 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
 - interrupts: Should contain ERROR and DMA interrupts
 - clock-frequency: Desired I2C bus clock frequency in Hz.
                    Only 100000Hz and 400000Hz modes are supported.
+- fsl,i2c-dma-channel: APBX DMA channel for the I2C
 
 Examples:
 
@@ -16,4 +17,5 @@ i2c0: i2c@80058000 {
        reg = <0x80058000 2000>;
        interrupts = <111 68>;
        clock-frequency = <100000>;
+       fsl,i2c-dma-channel = <6>;
 };
diff --git a/Documentation/devicetree/bindings/i2c/nomadik.txt b/Documentation/devicetree/bindings/i2c/nomadik.txt
new file mode 100644 (file)
index 0000000..72065b0
--- /dev/null
@@ -0,0 +1,23 @@
+I2C for Nomadik based systems
+
+Required (non-standard) properties:
+ - Nil
+
+Recommended (non-standard) properties:
+ - clock-frequency : Maximum bus clock frequency for the device
+
+Optional (non-standard) properties:
+ - Nil
+
+Example :
+
+i2c@80004000 {
+        compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
+        reg = <0x80004000 0x1000>;
+        interrupts = <0 21 0x4>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        v-i2c-supply = <&db8500_vape_reg>;
+
+        clock-frequency = <400000>;
+};
index 7c95f76398de401ac166af8f32d4a34a6b918e79..d410581a5a859901b32a49a1f037356c9f22e294 100644 (file)
@@ -28,6 +28,7 @@
                gpio2 = &pioC;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
        };
        cpus {
                cpu@0 {
                                status = "disabled";
                        };
 
+                       i2c0: i2c@fffac000 {
+                               compatible = "atmel,at91sam9260-i2c";
+                               reg = <0xfffac000 0x100>;
+                               interrupts = <11 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
                        adc0: adc@fffe0000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xfffe0000 0x100>;
index 195019b7ca0e046073361a587862c885c8fbfb7e..3e6e5c1abbf37184a44237e464080a52f4312e9f 100644 (file)
@@ -24,6 +24,7 @@
                gpio3 = &pioD;
                gpio4 = &pioE;
                tcb0 = &tcb0;
+               i2c0 = &i2c0;
        };
        cpus {
                cpu@0 {
                                interrupts = <24 4 2>;
                                status = "disabled";
                        };
+
+                       i2c0: i2c@fff88000 {
+                               compatible = "atmel,at91sam9263-i2c";
+                               reg = <0xfff88000 0x100>;
+                               interrupts = <13 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
                };
 
                nand0: nand@40000000 {
index 2a1d1ca8bd86636426bddfb77cf2ef8610bb8b16..75ce6e760016455cd1695ab1de148eabd807ca4b 100644 (file)
 
        ahb {
                apb {
+                       i2c0: i2c@fffac000 {
+                               compatible = "atmel,at91sam9g20-i2c";
+                       };
+
                        adc0: adc@fffe0000 {
                                atmel,adc-startup-time = <40>;
                        };
index 96514c134e54bafd1540c5f55524411b09f1e7a8..877c08f06763c643362eb41b8ebd058ac85abf7d 100644 (file)
                                phy-mode = "rmii";
                                status = "okay";
                        };
+
+                       i2c0: i2c@f8010000 {
+                               status = "okay";
+                       };
+
+                       i2c1: i2c@f8014000 {
+                               status = "okay";
+                       };
+
+                       i2c2: i2c@f8018000 {
+                               status = "okay";
+                       };
                };
 
                usb0: ohci@00600000 {
index 63751b1e744b42611f8e74d17738ccd69dd1efe1..3add030d61f8651fcf5a0476b11423897de71560 100644 (file)
@@ -29,6 +29,8 @@
                gpio4 = &pioE;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
        };
        cpus {
                cpu@0 {
                                status = "disabled";
                        };
 
+                       i2c0: i2c@fff84000 {
+                               compatible = "atmel,at91sam9g10-i2c";
+                               reg = <0xfff84000 0x100>;
+                               interrupts = <12 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       i2c1: i2c@fff88000 {
+                               compatible = "atmel,at91sam9g10-i2c";
+                               reg = <0xfff88000 0x100>;
+                               interrupts = <13 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
                        adc0: adc@fffb0000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xfffb0000 0x100>;
index a3633bd1311145168f36278afbed6dfe9e6bce76..15e1dd43f625aee627438c302e9a4a13f7002031 100644 (file)
                                phy-mode = "rmii";
                                status = "okay";
                        };
+
+                       i2c0: i2c@fff84000 {
+                               status = "okay";
+                       };
+
+                       i2c1: i2c@fff88000 {
+                               status = "okay";
+                       };
                };
 
                nand0: nand@40000000 {
index ef9336ae9614f85ffb0ce2348b69fc06b0f756e5..82508d68aa7edb0cdc98c5245d7872d47720dfd9 100644 (file)
@@ -26,6 +26,8 @@
                gpio3 = &pioD;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
        };
        cpus {
                cpu@0 {
                                atmel,use-dma-tx;
                                status = "disabled";
                        };
+
+                       i2c0: i2c@f8010000 {
+                               compatible = "atmel,at91sam9x5-i2c";
+                               reg = <0xf8010000 0x100>;
+                               interrupts = <9 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       i2c1: i2c@f8014000 {
+                               compatible = "atmel,at91sam9x5-i2c";
+                               reg = <0xf8014000 0x100>;
+                               interrupts = <10 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
                };
 
                nand0: nand@40000000 {
index f4e43e38f3a19e202fe07d88efb227b4e1d622ef..912b2c283d6f8d34ac7ac8273b8130360547ef81 100644 (file)
                        dbgu: serial@fffff200 {
                                status = "okay";
                        };
+
+                       i2c0: i2c@f8010000 {
+                               status = "okay";
+                       };
+
+                       i2c1: i2c@f8014000 {
+                               status = "okay";
+                       };
                };
 
                nand0: nand@40000000 {
index 8a387a8d61b745fc763c9e13f015896bc3e2bff7..03fc136421c5e31b01649c9caacdaf134bef4560 100644 (file)
@@ -27,6 +27,9 @@
                gpio3 = &pioD;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
        };
        cpus {
                cpu@0 {
                                status = "disabled";
                        };
 
+                       i2c0: i2c@f8010000 {
+                               compatible = "atmel,at91sam9x5-i2c";
+                               reg = <0xf8010000 0x100>;
+                               interrupts = <9 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       i2c1: i2c@f8014000 {
+                               compatible = "atmel,at91sam9x5-i2c";
+                               reg = <0xf8014000 0x100>;
+                               interrupts = <10 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       i2c2: i2c@f8018000 {
+                               compatible = "atmel,at91sam9x5-i2c";
+                               reg = <0xf8018000 0x100>;
+                               interrupts = <11 4 6>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
                        adc0: adc@f804c000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xf804c000 0x100>;
index 59fbfba23df8b237c6e775ef109106227a802903..e16d631554802f73227de6bcab58368d9e049227 100644 (file)
                                reg = <0x80058000 0x2000>;
                                interrupts = <111 68>;
                                clock-frequency = <100000>;
+                               fsl,i2c-dma-channel = <6>;
                                status = "disabled";
                        };
 
                                reg = <0x8005a000 0x2000>;
                                interrupts = <110 69>;
                                clock-frequency = <100000>;
+                               fsl,i2c-dma-channel = <7>;
                                status = "disabled";
                        };
 
index 6f50c6722276dcc73f8607b51132bfe40dd077b9..b4f0565aff638af135c7797b430bbfeb2a29b439 100644 (file)
@@ -187,6 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
index 9ac427a702da3d5cc25f380ededa12dcbcd73ed9..a563189cdfc3e1bfd4bdc2e71049073de01cd712 100644 (file)
@@ -511,7 +511,7 @@ static struct resource twi_resources[] = {
 };
 
 static struct platform_device at91rm9200_twi_device = {
-       .name           = "at91_i2c",
+       .name           = "i2c-at91rm9200",
        .id             = -1,
        .resource       = twi_resources,
        .num_resources  = ARRAY_SIZE(twi_resources),
index 30c7f26a4668c34e3739955a782ef3ec2befb978..ad29f93f20cab175555cd2a8c2974deff0fe31fd 100644 (file)
@@ -211,6 +211,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
        CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
        /* more usart lookup table for DT entries */
        CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
        CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
@@ -219,6 +221,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
        CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
        CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
        /* more tc lookup table for DT entries */
        CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
        CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
index af50ff3281c7153b46ec054d3aa2c14488ea2fbb..a76b8684f52d07328fcfe2f4a08726124b643f5a 100644 (file)
@@ -421,7 +421,6 @@ static struct resource twi_resources[] = {
 };
 
 static struct platform_device at91sam9260_twi_device = {
-       .name           = "at91_i2c",
        .id             = -1,
        .resource       = twi_resources,
        .num_resources  = ARRAY_SIZE(twi_resources),
@@ -429,6 +428,13 @@ static struct platform_device at91sam9260_twi_device = {
 
 void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
 {
+       /* IP version is not the same on 9260 and g20 */
+       if (cpu_is_at91sam9g20()) {
+               at91sam9260_twi_device.name = "i2c-at91sam9g20";
+       } else {
+               at91sam9260_twi_device.name = "i2c-at91sam9260";
+       }
+
        /* pins used for TWI interface */
        at91_set_A_periph(AT91_PIN_PA23, 0);            /* TWD */
        at91_set_multi_drive(AT91_PIN_PA23, 1);
index f40762c5fedee898fb836b24556f50499ee2858e..8d999eb1a137f1ed72529d296774c084d17da1a4 100644 (file)
@@ -178,6 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
        CLKDEV_CON_ID("pioB", &pioB_clk),
        CLKDEV_CON_ID("pioC", &pioC_clk),
index 11e9fa835cde2e296f5c585a43fc8f1aecf48cff..9752f17efba9926501a23b8e5209fbabcdfedc6d 100644 (file)
@@ -317,7 +317,6 @@ static struct resource twi_resources[] = {
 };
 
 static struct platform_device at91sam9261_twi_device = {
-       .name           = "at91_i2c",
        .id             = -1,
        .resource       = twi_resources,
        .num_resources  = ARRAY_SIZE(twi_resources),
@@ -325,12 +324,19 @@ static struct platform_device at91sam9261_twi_device = {
 
 void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
 {
+       /* IP version is not the same on 9261 and g10 */
+       if (cpu_is_at91sam9g10()) {
+               at91sam9261_twi_device.name = "i2c-at91sam9g10";
+               /* I2C PIO must not be configured as open-drain on this chip */
+       } else {
+               at91sam9261_twi_device.name = "i2c-at91sam9261";
+               at91_set_multi_drive(AT91_PIN_PA7, 1);
+               at91_set_multi_drive(AT91_PIN_PA8, 1);
+       }
+
        /* pins used for TWI interface */
        at91_set_A_periph(AT91_PIN_PA7, 0);             /* TWD */
-       at91_set_multi_drive(AT91_PIN_PA7, 1);
-
        at91_set_A_periph(AT91_PIN_PA8, 0);             /* TWCK */
-       at91_set_multi_drive(AT91_PIN_PA8, 1);
 
        i2c_register_board_info(0, devices, nr_devices);
        platform_device_register(&at91sam9261_twi_device);
index 144ef5de51b6beaf3b989801277aabe94aefe97b..6a01d0360dfb8940cbaaa2affc9bb58f88d702d9 100644 (file)
@@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
@@ -210,6 +211,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
index 7c0898fe20fa5850d174f69b2d43f48c645a6a30..8dde220b42b69c785c70118a16e48a1aa20acb95 100644 (file)
@@ -599,7 +599,7 @@ static struct resource twi_resources[] = {
 };
 
 static struct platform_device at91sam9263_twi_device = {
-       .name           = "at91_i2c",
+       .name           = "i2c-at91sam9260",
        .id             = -1,
        .resource       = twi_resources,
        .num_resources  = ARRAY_SIZE(twi_resources),
index ef6cedd52e3c2e71fdfb6dd8e68158b8ef622420..84af1b506d92a0b1e9e88c885b1d57be95fbf40b 100644 (file)
@@ -237,6 +237,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
        CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
@@ -254,6 +256,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
        CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
        CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
index e4c3b3709204256297f6887ed89ab74847159841..b1596072dcc23cd1414a8449eb4c25a35ed11222 100644 (file)
@@ -653,7 +653,7 @@ static struct resource twi0_resources[] = {
 };
 
 static struct platform_device at91sam9g45_twi0_device = {
-       .name           = "at91_i2c",
+       .name           = "i2c-at91sam9g10",
        .id             = 0,
        .resource       = twi0_resources,
        .num_resources  = ARRAY_SIZE(twi0_resources),
@@ -673,7 +673,7 @@ static struct resource twi1_resources[] = {
 };
 
 static struct platform_device at91sam9g45_twi1_device = {
-       .name           = "at91_i2c",
+       .name           = "i2c-at91sam9g10",
        .id             = 1,
        .resource       = twi1_resources,
        .num_resources  = ARRAY_SIZE(twi1_resources),
@@ -686,18 +686,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in
        /* pins used for TWI interface */
        if (i2c_id == 0) {
                at91_set_A_periph(AT91_PIN_PA20, 0);            /* TWD */
-               at91_set_multi_drive(AT91_PIN_PA20, 1);
-
                at91_set_A_periph(AT91_PIN_PA21, 0);            /* TWCK */
-               at91_set_multi_drive(AT91_PIN_PA21, 1);
 
                platform_device_register(&at91sam9g45_twi0_device);
        } else {
                at91_set_A_periph(AT91_PIN_PB10, 0);            /* TWD */
-               at91_set_multi_drive(AT91_PIN_PB10, 1);
-
                at91_set_A_periph(AT91_PIN_PB11, 0);            /* TWCK */
-               at91_set_multi_drive(AT91_PIN_PB11, 1);
 
                platform_device_register(&at91sam9g45_twi1_device);
        }
index 08494664ab78d362fcc3b62878cff83ce2cd3921..732d3d3f4ec5f7f93430839330d0e473a8063c20 100644 (file)
@@ -169,6 +169,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
        CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
        CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
        CLKDEV_CON_ID("pioA", &pioAB_clk),
        CLKDEV_CON_ID("pioB", &pioAB_clk),
        CLKDEV_CON_ID("pioC", &pioCD_clk),
index 72ce50a50de5a278e21535422c1572bb95837a36..72e908412222615134fc0530cc339348093f76be 100644 (file)
@@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
        CLKDEV_CON_ID("pioB", &pioB_clk),
        CLKDEV_CON_ID("pioC", &pioC_clk),
index deafea0e493dd41c9a20e52acab75baca1badbf0..d6ca0543ce8d7f1054d8f25614cd17369efe283d 100644 (file)
@@ -346,7 +346,7 @@ static struct resource twi_resources[] = {
 };
 
 static struct platform_device at91sam9rl_twi_device = {
-       .name           = "at91_i2c",
+       .name           = "i2c-at91sam9g20",
        .id             = -1,
        .resource       = twi_resources,
        .num_resources  = ARRAY_SIZE(twi_resources),
index 477cf9d06672c7259cca0dab641bcb099de8e6b5..e5035380dcbce16e806fb460625fd73d9a3c1153 100644 (file)
@@ -231,6 +231,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
        CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
        CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
        CLKDEV_CON_ID("pioA", &pioAB_clk),
        CLKDEV_CON_ID("pioB", &pioAB_clk),
        CLKDEV_CON_ID("pioC", &pioCD_clk),
diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h
deleted file mode 100644 (file)
index bb2880f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_twi.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Two-wire Interface (TWI) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_TWI_H
-#define AT91_TWI_H
-
-#define        AT91_TWI_CR             0x00            /* Control Register */
-#define                AT91_TWI_START          (1 <<  0)       /* Send a Start Condition */
-#define                AT91_TWI_STOP           (1 <<  1)       /* Send a Stop Condition */
-#define                AT91_TWI_MSEN           (1 <<  2)       /* Master Transfer Enable */
-#define                AT91_TWI_MSDIS          (1 <<  3)       /* Master Transfer Disable */
-#define                AT91_TWI_SVEN           (1 <<  4)       /* Slave Transfer Enable [SAM9260 only] */
-#define                AT91_TWI_SVDIS          (1 <<  5)       /* Slave Transfer Disable [SAM9260 only] */
-#define                AT91_TWI_SWRST          (1 <<  7)       /* Software Reset */
-
-#define        AT91_TWI_MMR            0x04            /* Master Mode Register */
-#define                AT91_TWI_IADRSZ         (3    <<  8)    /* Internal Device Address Size */
-#define                        AT91_TWI_IADRSZ_NO              (0 << 8)
-#define                        AT91_TWI_IADRSZ_1               (1 << 8)
-#define                        AT91_TWI_IADRSZ_2               (2 << 8)
-#define                        AT91_TWI_IADRSZ_3               (3 << 8)
-#define                AT91_TWI_MREAD          (1    << 12)    /* Master Read Direction */
-#define                AT91_TWI_DADR           (0x7f << 16)    /* Device Address */
-
-#define        AT91_TWI_SMR            0x08            /* Slave Mode Register [SAM9260 only] */
-#define                AT91_TWI_SADR           (0x7f << 16)    /* Slave Address */
-
-#define        AT91_TWI_IADR           0x0c            /* Internal Address Register */
-
-#define        AT91_TWI_CWGR           0x10            /* Clock Waveform Generator Register */
-#define                AT91_TWI_CLDIV          (0xff <<  0)    /* Clock Low Divisor */
-#define                AT91_TWI_CHDIV          (0xff <<  8)    /* Clock High Divisor */
-#define                AT91_TWI_CKDIV          (7    << 16)    /* Clock Divider */
-
-#define        AT91_TWI_SR             0x20            /* Status Register */
-#define                AT91_TWI_TXCOMP         (1 <<  0)       /* Transmission Complete */
-#define                AT91_TWI_RXRDY          (1 <<  1)       /* Receive Holding Register Ready */
-#define                AT91_TWI_TXRDY          (1 <<  2)       /* Transmit Holding Register Ready */
-#define                AT91_TWI_SVREAD         (1 <<  3)       /* Slave Read [SAM9260 only] */
-#define                AT91_TWI_SVACC          (1 <<  4)       /* Slave Access [SAM9260 only] */
-#define                AT91_TWI_GACC           (1 <<  5)       /* General Call Access [SAM9260 only] */
-#define                AT91_TWI_OVRE           (1 <<  6)       /* Overrun Error [AT91RM9200 only] */
-#define                AT91_TWI_UNRE           (1 <<  7)       /* Underrun Error [AT91RM9200 only] */
-#define                AT91_TWI_NACK           (1 <<  8)       /* Not Acknowledged */
-#define                AT91_TWI_ARBLST         (1 <<  9)       /* Arbitration Lost [SAM9260 only] */
-#define                AT91_TWI_SCLWS          (1 << 10)       /* Clock Wait State [SAM9260 only] */
-#define                AT91_TWI_EOSACC         (1 << 11)       /* End of Slave Address [SAM9260 only] */
-
-#define        AT91_TWI_IER            0x24            /* Interrupt Enable Register */
-#define        AT91_TWI_IDR            0x28            /* Interrupt Disable Register */
-#define        AT91_TWI_IMR            0x2c            /* Interrupt Mask Register */
-#define        AT91_TWI_RHR            0x30            /* Receive Holding Register */
-#define        AT91_TWI_THR            0x34            /* Transmit Holding Register */
-
-#endif
-
index 6013831a043e320fafd5e718a558d422fa67a624..a5683a84c6ee0e313cb8f9daeeb7c72106952a4e 100644 (file)
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
-#include <linux/i2c-omap.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 
 #include <mach/irqs.h>
 #include <plat/i2c.h>
-#include <plat/omap-pm.h>
 #include <plat/omap_device.h>
 
 #define OMAP_I2C_SIZE          0x3f
@@ -129,16 +127,6 @@ static inline int omap1_i2c_add_bus(int bus_id)
 
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
-/*
- * XXX This function is a temporary compatibility wrapper - only
- * needed until the I2C driver can be converted to call
- * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
- */
-static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
-{
-       omap_pm_set_max_mpu_wakeup_lat(dev, t);
-}
-
 static inline int omap2_i2c_add_bus(int bus_id)
 {
        int l;
@@ -170,15 +158,6 @@ static inline int omap2_i2c_add_bus(int bus_id)
        dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
        pdata->flags = dev_attr->flags;
 
-       /*
-        * When waiting for completion of a i2c transfer, we need to
-        * set a wake up latency constraint for the MPU. This is to
-        * ensure quick enough wakeup from idle, when transfer
-        * completes.
-        * Only omap3 has support for constraints
-        */
-       if (cpu_is_omap34xx())
-               pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
        pdev = omap_device_build(name, bus_id, oh, pdata,
                        sizeof(struct omap_i2c_bus_platform_data),
                        NULL, 0, 0);
index 6f5f98d69af7c26b2fd7b895106e11745ce7d155..f892a424009b8123c3cb0ceb3dae75359cceaef9 100644 (file)
@@ -46,14 +46,19 @@ static int i2c_debug;
 #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
 #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
 #define pca_wait(adap) adap->wait_for_completion(adap->data)
-#define pca_reset(adap) adap->reset_chip(adap->data)
 
-static void pca9665_reset(void *pd)
+static void pca_reset(struct i2c_algo_pca_data *adap)
 {
-       struct i2c_algo_pca_data *adap = pd;
-       pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
-       pca_outw(adap, I2C_PCA_IND, 0xA5);
-       pca_outw(adap, I2C_PCA_IND, 0x5A);
+       if (adap->chip == I2C_PCA_CHIP_9665) {
+               /* Ignore the reset function from the module,
+                * we can use the parallel bus reset.
+                */
+               pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
+               pca_outw(adap, I2C_PCA_IND, 0xA5);
+               pca_outw(adap, I2C_PCA_IND, 0x5A);
+       } else {
+               adap->reset_chip(adap->data);
+       }
 }
 
 /*
@@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap)
        pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
        if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {
                printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name);
-               return I2C_PCA_CHIP_9665;
+               pca_data->chip = I2C_PCA_CHIP_9665;
        } else {
                printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name);
-               return I2C_PCA_CHIP_9564;
+               pca_data->chip = I2C_PCA_CHIP_9564;
        }
+       return pca_data->chip;
 }
 
 static int pca_init(struct i2c_adapter *adap)
@@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap)
                 */
                int raise_fall_time;
 
-               /* Ignore the reset function from the module,
-                * we can use the parallel bus reset
-                */
-               pca_data->reset_chip = pca9665_reset;
-
                if (pca_data->i2c_clock > 1265800) {
                        printk(KERN_WARNING "%s: I2C clock speed too high."
                                " Using 1265.8kHz.\n", adap->name);
index ff01c389e2dacc984cf9ac5afb16407ad81dfbe4..65dd599a02620211b8db7a1ef6bfd1d8f9cdda30 100644 (file)
@@ -294,18 +294,21 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
 
 config I2C_AT91
        tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
-       depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+       depends on ARCH_AT91 && EXPERIMENTAL
        help
          This supports the use of the I2C interface on Atmel AT91
          processors.
 
-         This driver is BROKEN because the controller which it uses
-         will easily trigger RX overrun and TX underrun errors.  Using
-         low I2C clock rates may partially work around those issues
-         on some systems.  Another serious problem is that there is no
-         documented way to issue repeated START conditions, as needed
+         A serious problem is that there is no documented way to issue
+         repeated START conditions for more than two messages, as needed
          to support combined I2C messages.  Use the i2c-gpio driver
-         unless your system can cope with those limitations.
+         unless your system can cope with this limitation.
+
+         Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices
+         don't have clock stretching in transmission mode. For that reason,
+         you can encounter underrun issues causing premature stop sendings if
+         the latency to fill the transmission register is too long. If you
+         are facing this situation, use the i2c-gpio driver.
 
 config I2C_AU1550
        tristate "Au1550/Au1200/Au1300 SMBus interface"
@@ -718,6 +721,16 @@ config I2C_XLR
          This driver can also be built as a module.  If so, the module
          will be called i2c-xlr.
 
+config I2C_RCAR
+       tristate "Renesas R-Car I2C Controller"
+       depends on ARCH_SHMOBILE && I2C
+       help
+         If you say yes to this option, support will be included for the
+         R-Car I2C controller.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-rcar.
+
 comment "External I2C/SMBus adapter drivers"
 
 config I2C_DIOLAN_U2C
index 37c4182cc98bb28520eeb1ce579bb3b601cffc01..2d33d62952c112adfb62bde5f08a342a37466c78 100644 (file)
@@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_VERSATILE)   += i2c-versatile.o
 obj-$(CONFIG_I2C_OCTEON)       += i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)       += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)          += i2c-xlr.o
+obj-$(CONFIG_I2C_RCAR)         += i2c-rcar.o
 
 # External I2C/SMBus adapter drivers
 obj-$(CONFIG_I2C_DIOLAN_U2C)   += i2c-diolan-u2c.o
index e24484beef078d9e3069b32066cd9c865ed25f22..aa59a254be2c3e3755a377d0c0c1f02dfa6c797d 100644 (file)
 /*
-    i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
-
-    Copyright (C) 2004 Rick Bronson
-    Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
-
-    Borrowed heavily from original work by:
-    Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-*/
+ *  i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ *  Copyright (C) 2011 Weinmann Medical GmbH
+ *  Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ *  Evolved from original work by:
+ *  Copyright (C) 2004 Rick Bronson
+ *  Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+ *
+ *  Borrowed heavily from original work by:
+ *  Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
 #include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define TWI_CLK_HZ             100000                  /* max 400 Kbits/s */
+#define AT91_I2C_TIMEOUT       msecs_to_jiffies(100)   /* transfer timeout */
+
+/* AT91 TWI register definitions */
+#define        AT91_TWI_CR             0x0000  /* Control Register */
+#define        AT91_TWI_START          0x0001  /* Send a Start Condition */
+#define        AT91_TWI_STOP           0x0002  /* Send a Stop Condition */
+#define        AT91_TWI_MSEN           0x0004  /* Master Transfer Enable */
+#define        AT91_TWI_SVDIS          0x0020  /* Slave Transfer Disable */
+#define        AT91_TWI_SWRST          0x0080  /* Software Reset */
+
+#define        AT91_TWI_MMR            0x0004  /* Master Mode Register */
+#define        AT91_TWI_IADRSZ_1       0x0100  /* Internal Device Address Size */
+#define        AT91_TWI_MREAD          0x1000  /* Master Read Direction */
+
+#define        AT91_TWI_IADR           0x000c  /* Internal Address Register */
+
+#define        AT91_TWI_CWGR           0x0010  /* Clock Waveform Generator Reg */
+
+#define        AT91_TWI_SR             0x0020  /* Status Register */
+#define        AT91_TWI_TXCOMP         0x0001  /* Transmission Complete */
+#define        AT91_TWI_RXRDY          0x0002  /* Receive Holding Register Ready */
+#define        AT91_TWI_TXRDY          0x0004  /* Transmit Holding Register Ready */
 
-#include <mach/at91_twi.h>
-#include <mach/board.h>
-#include <mach/cpu.h>
+#define        AT91_TWI_OVRE           0x0040  /* Overrun Error */
+#define        AT91_TWI_UNRE           0x0080  /* Underrun Error */
+#define        AT91_TWI_NACK           0x0100  /* Not Acknowledged */
 
-#define TWI_CLOCK              100000          /* Hz. max 400 Kbits/sec */
+#define        AT91_TWI_IER            0x0024  /* Interrupt Enable Register */
+#define        AT91_TWI_IDR            0x0028  /* Interrupt Disable Register */
+#define        AT91_TWI_IMR            0x002c  /* Interrupt Mask Register */
+#define        AT91_TWI_RHR            0x0030  /* Receive Holding Register */
+#define        AT91_TWI_THR            0x0034  /* Transmit Holding Register */
 
+struct at91_twi_pdata {
+       unsigned        clk_max_div;
+       unsigned        clk_offset;
+       bool            has_unre_flag;
+};
+
+struct at91_twi_dev {
+       struct device           *dev;
+       void __iomem            *base;
+       struct completion       cmd_complete;
+       struct clk              *clk;
+       u8                      *buf;
+       size_t                  buf_len;
+       struct i2c_msg          *msg;
+       int                     irq;
+       unsigned                transfer_status;
+       struct i2c_adapter      adapter;
+       unsigned                twi_cwgr_reg;
+       struct at91_twi_pdata   *pdata;
+};
 
-static struct clk *twi_clk;
-static void __iomem *twi_base;
+static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
+{
+       return readl_relaxed(dev->base + reg);
+}
+
+static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
+{
+       writel_relaxed(val, dev->base + reg);
+}
 
-#define at91_twi_read(reg)             __raw_readl(twi_base + (reg))
-#define at91_twi_write(reg, val)       __raw_writel((val), twi_base + (reg))
+static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
+{
+       at91_twi_write(dev, AT91_TWI_IDR,
+                      AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
+}
 
+static void at91_init_twi_bus(struct at91_twi_dev *dev)
+{
+       at91_disable_twi_interrupts(dev);
+       at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
+       at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
+       at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
+       at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
+}
 
 /*
- * Initialize the TWI hardware registers.
+ * Calculate symmetric clock as stated in datasheet:
+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
  */
-static void __devinit at91_twi_hwinit(void)
+static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
 {
-       unsigned long cdiv, ckdiv;
-
-       at91_twi_write(AT91_TWI_IDR, 0xffffffff);       /* Disable all interrupts */
-       at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST);    /* Reset peripheral */
-       at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);     /* Set Master mode */
-
-       /* Calcuate clock dividers */
-       cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
-       cdiv = cdiv + 1;        /* round up */
-       ckdiv = 0;
-       while (cdiv > 255) {
-               ckdiv++;
-               cdiv = cdiv >> 1;
+       int ckdiv, cdiv, div;
+       struct at91_twi_pdata *pdata = dev->pdata;
+       int offset = pdata->clk_offset;
+       int max_ckdiv = pdata->clk_max_div;
+
+       div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
+                                      2 * twi_clk) - offset);
+       ckdiv = fls(div >> 8);
+       cdiv = div >> ckdiv;
+
+       if (ckdiv > max_ckdiv) {
+               dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
+                        ckdiv, max_ckdiv);
+               ckdiv = max_ckdiv;
+               cdiv = 255;
        }
 
-       if (cpu_is_at91rm9200()) {                      /* AT91RM9200 Errata #22 */
-               if (ckdiv > 5) {
-                       printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
-                       ckdiv = 5;
-               }
-       }
+       dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
+       dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+}
 
-       at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+{
+       if (dev->buf_len <= 0)
+               return;
+
+       at91_twi_write(dev, AT91_TWI_THR, *dev->buf);
+
+       /* send stop when last byte has been written */
+       if (--dev->buf_len == 0)
+               at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+
+       dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
+
+       ++dev->buf;
 }
 
-/*
- * Poll the i2c status register until the specified bit is set.
- * Returns 0 if timed out (100 msec).
- */
-static short at91_poll_status(unsigned long bit)
+static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
 {
-       int loop_cntr = 10000;
+       if (dev->buf_len <= 0)
+               return;
+
+       *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
+       --dev->buf_len;
+
+       /* handle I2C_SMBUS_BLOCK_DATA */
+       if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
+               dev->msg->flags &= ~I2C_M_RECV_LEN;
+               dev->buf_len += *dev->buf;
+               dev->msg->len = dev->buf_len + 1;
+               dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
+       }
+
+       /* send stop if second but last byte has been read */
+       if (dev->buf_len == 1)
+               at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
 
-       do {
-               udelay(10);
-       } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+       dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
 
-       return (loop_cntr > 0);
+       ++dev->buf;
 }
 
-static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
 {
-       /* Send Start */
-       at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
-
-       /* Read data */
-       while (length--) {
-               if (!length)    /* need to send Stop before reading last byte */
-                       at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
-               if (!at91_poll_status(AT91_TWI_RXRDY)) {
-                       dev_dbg(&adap->dev, "RXRDY timeout\n");
-                       return -ETIMEDOUT;
-               }
-               *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+       struct at91_twi_dev *dev = dev_id;
+       const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
+       const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
+
+       if (!irqstatus)
+               return IRQ_NONE;
+       else if (irqstatus & AT91_TWI_RXRDY)
+               at91_twi_read_next_byte(dev);
+       else if (irqstatus & AT91_TWI_TXRDY)
+               at91_twi_write_next_byte(dev);
+
+       /* catch error flags */
+       dev->transfer_status |= status;
+
+       if (irqstatus & AT91_TWI_TXCOMP) {
+               at91_disable_twi_interrupts(dev);
+               complete(&dev->cmd_complete);
        }
 
-       return 0;
+       return IRQ_HANDLED;
 }
 
-static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+static int at91_do_twi_transfer(struct at91_twi_dev *dev)
 {
-       /* Load first byte into transmitter */
-       at91_twi_write(AT91_TWI_THR, *buf++);
+       int ret;
+       bool has_unre_flag = dev->pdata->has_unre_flag;
 
-       /* Send Start */
-       at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+       dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
+               (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
 
-       do {
-               if (!at91_poll_status(AT91_TWI_TXRDY)) {
-                       dev_dbg(&adap->dev, "TXRDY timeout\n");
-                       return -ETIMEDOUT;
-               }
+       INIT_COMPLETION(dev->cmd_complete);
+       dev->transfer_status = 0;
+       if (dev->msg->flags & I2C_M_RD) {
+               unsigned start_flags = AT91_TWI_START;
 
-               length--;       /* byte was transmitted */
+               if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
+                       dev_err(dev->dev, "RXRDY still set!");
+                       at91_twi_read(dev, AT91_TWI_RHR);
+               }
 
-               if (length > 0)         /* more data to send? */
-                       at91_twi_write(AT91_TWI_THR, *buf++);
-       } while (length);
+               /* if only one byte is to be read, immediately stop transfer */
+               if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
+                       start_flags |= AT91_TWI_STOP;
+               at91_twi_write(dev, AT91_TWI_CR, start_flags);
+               at91_twi_write(dev, AT91_TWI_IER,
+                              AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
+       } else {
+               at91_twi_write_next_byte(dev);
+               at91_twi_write(dev, AT91_TWI_IER,
+                              AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
+       }
 
-       /* Send Stop */
-       at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+       ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+                                                       dev->adapter.timeout);
+       if (ret == 0) {
+               dev_err(dev->dev, "controller timed out\n");
+               at91_init_twi_bus(dev);
+               return -ETIMEDOUT;
+       }
+       if (dev->transfer_status & AT91_TWI_NACK) {
+               dev_dbg(dev->dev, "received nack\n");
+               return -EREMOTEIO;
+       }
+       if (dev->transfer_status & AT91_TWI_OVRE) {
+               dev_err(dev->dev, "overrun while reading\n");
+               return -EIO;
+       }
+       if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
+               dev_err(dev->dev, "underrun while writing\n");
+               return -EIO;
+       }
+       dev_dbg(dev->dev, "transfer complete\n");
 
        return 0;
 }
 
-/*
- * Generic i2c master transfer entrypoint.
- *
- * Note: We do not use Atmel's feature of storing the "internal device address".
- * Instead the "internal device address" has to be written using a separate
- * i2c message.
- * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
- */
-static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
 {
-       int i, ret;
+       struct at91_twi_dev *dev = i2c_get_adapdata(adap);
+       int ret;
+       unsigned int_addr_flag = 0;
+       struct i2c_msg *m_start = msg;
 
        dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
 
-       for (i = 0; i < num; i++) {
-               dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
-                       pmsg->flags & I2C_M_RD ? "read" : "writ",
-                       pmsg->len, pmsg->len > 1 ? "s" : "",
-                       pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
-
-               at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
-                       | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
-
-               if (pmsg->len && pmsg->buf) {   /* sanity check */
-                       if (pmsg->flags & I2C_M_RD)
-                               ret = xfer_read(adap, pmsg->buf, pmsg->len);
-                       else
-                               ret = xfer_write(adap, pmsg->buf, pmsg->len);
-
-                       if (ret)
-                               return ret;
-
-                       /* Wait until transfer is finished */
-                       if (!at91_poll_status(AT91_TWI_TXCOMP)) {
-                               dev_dbg(&adap->dev, "TXCOMP timeout\n");
-                               return -ETIMEDOUT;
-                       }
+       /*
+        * The hardware can handle at most two messages concatenated by a
+        * repeated start via it's internal address feature.
+        */
+       if (num > 2) {
+               dev_err(dev->dev,
+                       "cannot handle more than two concatenated messages.\n");
+               return 0;
+       } else if (num == 2) {
+               int internal_address = 0;
+               int i;
+
+               if (msg->flags & I2C_M_RD) {
+                       dev_err(dev->dev, "first transfer must be write.\n");
+                       return -EINVAL;
                }
-               dev_dbg(&adap->dev, "transfer complete\n");
-               pmsg++;         /* next message */
+               if (msg->len > 3) {
+                       dev_err(dev->dev, "first message size must be <= 3.\n");
+                       return -EINVAL;
+               }
+
+               /* 1st msg is put into the internal address, start with 2nd */
+               m_start = &msg[1];
+               for (i = 0; i < msg->len; ++i) {
+                       const unsigned addr = msg->buf[msg->len - 1 - i];
+
+                       internal_address |= addr << (8 * i);
+                       int_addr_flag += AT91_TWI_IADRSZ_1;
+               }
+               at91_twi_write(dev, AT91_TWI_IADR, internal_address);
        }
-       return i;
+
+       at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag
+                      | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+       dev->buf_len = m_start->len;
+       dev->buf = m_start->buf;
+       dev->msg = m_start;
+
+       ret = at91_do_twi_transfer(dev);
+
+       return (ret < 0) ? ret : num;
 }
 
-/*
- * Return list of supported functionality.
- */
-static u32 at91_func(struct i2c_adapter *adapter)
+static u32 at91_twi_func(struct i2c_adapter *adapter)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+               | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
 }
 
-static struct i2c_algorithm at91_algorithm = {
-       .master_xfer    = at91_xfer,
-       .functionality  = at91_func,
+static struct i2c_algorithm at91_twi_algorithm = {
+       .master_xfer    = at91_twi_xfer,
+       .functionality  = at91_twi_func,
 };
 
-/*
- * Main initialization routine.
- */
-static int __devinit at91_i2c_probe(struct platform_device *pdev)
-{
-       struct i2c_adapter *adapter;
-       struct resource *res;
-       int rc;
+static struct at91_twi_pdata at91rm9200_config = {
+       .clk_max_div = 5,
+       .clk_offset = 3,
+       .has_unre_flag = true,
+};
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
+static struct at91_twi_pdata at91sam9261_config = {
+       .clk_max_div = 5,
+       .clk_offset = 4,
+       .has_unre_flag = false,
+};
 
-       if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
-               return -EBUSY;
+static struct at91_twi_pdata at91sam9260_config = {
+       .clk_max_div = 7,
+       .clk_offset = 4,
+       .has_unre_flag = false,
+};
+
+static struct at91_twi_pdata at91sam9g20_config = {
+       .clk_max_div = 7,
+       .clk_offset = 4,
+       .has_unre_flag = false,
+};
+
+static struct at91_twi_pdata at91sam9g10_config = {
+       .clk_max_div = 7,
+       .clk_offset = 4,
+       .has_unre_flag = false,
+};
 
-       twi_base = ioremap(res->start, resource_size(res));
-       if (!twi_base) {
-               rc = -ENOMEM;
-               goto fail0;
+static struct at91_twi_pdata at91sam9x5_config = {
+       .clk_max_div = 7,
+       .clk_offset = 4,
+       .has_unre_flag = false,
+};
+
+static const struct platform_device_id at91_twi_devtypes[] = {
+       {
+               .name = "i2c-at91rm9200",
+               .driver_data = (unsigned long) &at91rm9200_config,
+       }, {
+               .name = "i2c-at91sam9261",
+               .driver_data = (unsigned long) &at91sam9261_config,
+       }, {
+               .name = "i2c-at91sam9260",
+               .driver_data = (unsigned long) &at91sam9260_config,
+       }, {
+               .name = "i2c-at91sam9g20",
+               .driver_data = (unsigned long) &at91sam9g20_config,
+       }, {
+               .name = "i2c-at91sam9g10",
+               .driver_data = (unsigned long) &at91sam9g10_config,
+       }, {
+               /* sentinel */
        }
+};
 
-       twi_clk = clk_get(NULL, "twi_clk");
-       if (IS_ERR(twi_clk)) {
-               dev_err(&pdev->dev, "no clock defined\n");
-               rc = -ENODEV;
-               goto fail1;
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_twi_dt_ids[] = {
+       {
+               .compatible = "atmel,at91sam9260-i2c",
+               .data = &at91sam9260_config,
+       } , {
+               .compatible = "atmel,at91sam9g20-i2c",
+               .data = &at91sam9g20_config,
+       } , {
+               .compatible = "atmel,at91sam9g10-i2c",
+               .data = &at91sam9g10_config,
+       }, {
+               .compatible = "atmel,at91sam9x5-i2c",
+               .data = &at91sam9x5_config,
+       }, {
+               /* sentinel */
        }
+};
+MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+#else
+#define atmel_twi_dt_ids NULL
+#endif
 
-       adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-       if (adapter == NULL) {
-               dev_err(&pdev->dev, "can't allocate inteface!\n");
-               rc = -ENOMEM;
-               goto fail2;
+static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
+                                       struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
+               if (!match)
+                       return NULL;
+               return match->data;
        }
-       snprintf(adapter->name, sizeof(adapter->name), "AT91");
-       adapter->algo = &at91_algorithm;
-       adapter->class = I2C_CLASS_HWMON;
-       adapter->dev.parent = &pdev->dev;
-       /* adapter->id == 0 ... only one TWI controller for now */
+       return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit at91_twi_probe(struct platform_device *pdev)
+{
+       struct at91_twi_dev *dev;
+       struct resource *mem;
+       int rc;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       init_completion(&dev->cmd_complete);
+       dev->dev = &pdev->dev;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+               return -ENODEV;
+
+       dev->pdata = at91_twi_get_driver_data(pdev);
+       if (!dev->pdata)
+               return -ENODEV;
 
-       platform_set_drvdata(pdev, adapter);
+       dev->base = devm_request_and_ioremap(&pdev->dev, mem);
+       if (!dev->base)
+               return -EBUSY;
 
-       clk_enable(twi_clk);            /* enable peripheral clock */
-       at91_twi_hwinit();              /* initialize TWI controller */
+       dev->irq = platform_get_irq(pdev, 0);
+       if (dev->irq < 0)
+               return dev->irq;
 
-       rc = i2c_add_numbered_adapter(adapter);
+       rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0,
+                        dev_name(dev->dev), dev);
        if (rc) {
-               dev_err(&pdev->dev, "Adapter %s registration failed\n",
-                               adapter->name);
-               goto fail3;
+               dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
+               return rc;
        }
 
-       dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
-       return 0;
+       platform_set_drvdata(pdev, dev);
 
-fail3:
-       platform_set_drvdata(pdev, NULL);
-       kfree(adapter);
-       clk_disable(twi_clk);
-fail2:
-       clk_put(twi_clk);
-fail1:
-       iounmap(twi_base);
-fail0:
-       release_mem_region(res->start, resource_size(res));
+       dev->clk = devm_clk_get(dev->dev, NULL);
+       if (IS_ERR(dev->clk)) {
+               dev_err(dev->dev, "no clock defined\n");
+               return -ENODEV;
+       }
+       clk_prepare_enable(dev->clk);
+
+       at91_calc_twi_clock(dev, TWI_CLK_HZ);
+       at91_init_twi_bus(dev);
+
+       snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
+       i2c_set_adapdata(&dev->adapter, dev);
+       dev->adapter.owner = THIS_MODULE;
+       dev->adapter.class = I2C_CLASS_HWMON;
+       dev->adapter.algo = &at91_twi_algorithm;
+       dev->adapter.dev.parent = dev->dev;
+       dev->adapter.nr = pdev->id;
+       dev->adapter.timeout = AT91_I2C_TIMEOUT;
+       dev->adapter.dev.of_node = pdev->dev.of_node;
+
+       rc = i2c_add_numbered_adapter(&dev->adapter);
+       if (rc) {
+               dev_err(dev->dev, "Adapter %s registration failed\n",
+                       dev->adapter.name);
+               clk_disable_unprepare(dev->clk);
+               return rc;
+       }
 
-       return rc;
+       of_i2c_register_devices(&dev->adapter);
+
+       dev_info(dev->dev, "AT91 i2c bus driver.\n");
+       return 0;
 }
 
-static int __devexit at91_i2c_remove(struct platform_device *pdev)
+static int __devexit at91_twi_remove(struct platform_device *pdev)
 {
-       struct i2c_adapter *adapter = platform_get_drvdata(pdev);
-       struct resource *res;
+       struct at91_twi_dev *dev = platform_get_drvdata(pdev);
        int rc;
 
-       rc = i2c_del_adapter(adapter);
-       platform_set_drvdata(pdev, NULL);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       iounmap(twi_base);
-       release_mem_region(res->start, resource_size(res));
-
-       clk_disable(twi_clk);           /* disable peripheral clock */
-       clk_put(twi_clk);
+       rc = i2c_del_adapter(&dev->adapter);
+       clk_disable_unprepare(dev->clk);
 
        return rc;
 }
 
 #ifdef CONFIG_PM
 
-/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
-
-static int at91_i2c_suspend(struct device *dev)
+static int at91_twi_runtime_suspend(struct device *dev)
 {
-       clk_disable(twi_clk);
+       struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+       clk_disable(twi_dev->clk);
+
        return 0;
 }
 
-static int at91_i2c_resume(struct device *dev)
+static int at91_twi_runtime_resume(struct device *dev)
 {
-       return clk_enable(twi_clk);
+       struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+       return clk_enable(twi_dev->clk);
 }
 
-static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume);
-#define AT91_I2C_PM    (&at91_i2c_pm)
+static const struct dev_pm_ops at91_twi_pm = {
+       .runtime_suspend        = at91_twi_runtime_suspend,
+       .runtime_resume         = at91_twi_runtime_resume,
+};
 
+#define at91_twi_pm_ops (&at91_twi_pm)
 #else
-#define AT91_I2C_PM    NULL
+#define at91_twi_pm_ops NULL
 #endif
 
-static struct platform_driver at91_i2c_driver = {
-       .probe          = at91_i2c_probe,
-       .remove         = __devexit_p(at91_i2c_remove),
+static struct platform_driver at91_twi_driver = {
+       .probe          = at91_twi_probe,
+       .remove         = __devexit_p(at91_twi_remove),
+       .id_table       = at91_twi_devtypes,
        .driver         = {
                .name   = "at91_i2c",
                .owner  = THIS_MODULE,
-               .pm     = AT91_I2C_PM,
+               .of_match_table = atmel_twi_dt_ids,
+               .pm     = at91_twi_pm_ops,
        },
 };
 
-module_platform_driver(at91_i2c_driver);
+static int __init at91_twi_init(void)
+{
+       return platform_driver_register(&at91_twi_driver);
+}
+
+static void __exit at91_twi_exit(void)
+{
+       platform_driver_unregister(&at91_twi_driver);
+}
+
+subsys_initcall(at91_twi_init);
+module_exit(at91_twi_exit);
 
-MODULE_AUTHOR("Rick Bronson");
+MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
 MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:at91_i2c");
index 79a2542d8c41564b1c2b7a337e23a8a0282cda4f..6a0a5531944994803b94cbbe95b8badf7bdbb42c 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/slab.h>
 #include <linux/cpufreq.h>
 #include <linux/gpio.h>
+#include <linux/of_i2c.h>
+#include <linux/of_device.h>
 
 #include <mach/hardware.h>
 #include <linux/platform_data/i2c-davinci.h>
@@ -114,6 +116,7 @@ struct davinci_i2c_dev {
        struct completion       xfr_complete;
        struct notifier_block   freq_transition;
 #endif
+       struct davinci_i2c_platform_data *pdata;
 };
 
 /* default platform data to use if not supplied in the platform_device */
@@ -155,7 +158,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin)
 static void i2c_recover_bus(struct davinci_i2c_dev *dev)
 {
        u32 flag = 0;
-       struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+       struct davinci_i2c_platform_data *pdata = dev->pdata;
 
        dev_err(dev->dev, "initiating i2c bus recovery\n");
        /* Send NACK to the slave */
@@ -163,8 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev)
        flag |=  DAVINCI_I2C_MDR_NACK;
        /* write the data into mode register */
        davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
-       if (pdata)
-               generic_i2c_clock_pulse(pdata->scl_pin);
+       generic_i2c_clock_pulse(pdata->scl_pin);
        /* Send STOP */
        flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
        flag |= DAVINCI_I2C_MDR_STP;
@@ -187,7 +189,7 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
 
 static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 {
-       struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+       struct davinci_i2c_platform_data *pdata = dev->pdata;
        u16 psc;
        u32 clk;
        u32 d;
@@ -235,10 +237,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
  */
 static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 {
-       struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
-
-       if (!pdata)
-               pdata = &davinci_i2c_platform_data_default;
+       struct davinci_i2c_platform_data *pdata = dev->pdata;
 
        /* put I2C into reset */
        davinci_i2c_reset_ctrl(dev, 0);
@@ -260,6 +259,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
        dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",
                pdata->bus_freq, pdata->bus_delay);
 
+
        /* Take the I2C module out of reset: */
        davinci_i2c_reset_ctrl(dev, 1);
 
@@ -308,13 +308,11 @@ static int
 i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
 {
        struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
-       struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+       struct davinci_i2c_platform_data *pdata = dev->pdata;
        u32 flag;
        u16 w;
        int r;
 
-       if (!pdata)
-               pdata = &davinci_i2c_platform_data_default;
        /* Introduce a delay, required for some boards (e.g Davinci EVM) */
        if (pdata->bus_delay)
                udelay(pdata->bus_delay);
@@ -635,6 +633,12 @@ static struct i2c_algorithm i2c_davinci_algo = {
        .functionality  = i2c_davinci_func,
 };
 
+static const struct of_device_id davinci_i2c_of_match[] = {
+       {.compatible = "ti,davinci-i2c", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, davinci_i2c_of_match);
+
 static int davinci_i2c_probe(struct platform_device *pdev)
 {
        struct davinci_i2c_dev *dev;
@@ -674,14 +678,33 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 #endif
        dev->dev = get_device(&pdev->dev);
        dev->irq = irq->start;
+       dev->pdata = dev->dev->platform_data;
        platform_set_drvdata(pdev, dev);
 
+       if (!dev->pdata && pdev->dev.of_node) {
+               u32 prop;
+
+               dev->pdata = devm_kzalloc(&pdev->dev,
+                       sizeof(struct davinci_i2c_platform_data), GFP_KERNEL);
+               if (!dev->pdata) {
+                       r = -ENOMEM;
+                       goto err_free_mem;
+               }
+               memcpy(dev->pdata, &davinci_i2c_platform_data_default,
+                       sizeof(struct davinci_i2c_platform_data));
+               if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                       &prop))
+                       dev->pdata->bus_freq = prop / 1000;
+       } else if (!dev->pdata) {
+               dev->pdata = &davinci_i2c_platform_data_default;
+       }
+
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                r = -ENODEV;
                goto err_free_mem;
        }
-       clk_enable(dev->clk);
+       clk_prepare_enable(dev->clk);
 
        dev->base = ioremap(mem->start, resource_size(mem));
        if (!dev->base) {
@@ -711,6 +734,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
        adap->algo = &i2c_davinci_algo;
        adap->dev.parent = &pdev->dev;
        adap->timeout = DAVINCI_I2C_TIMEOUT;
+       adap->dev.of_node = pdev->dev.of_node;
 
        adap->nr = pdev->id;
        r = i2c_add_numbered_adapter(adap);
@@ -718,6 +742,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failure adding adapter\n");
                goto err_free_irq;
        }
+       of_i2c_register_devices(adap);
 
        return 0;
 
@@ -726,7 +751,7 @@ err_free_irq:
 err_unuse_clocks:
        iounmap(dev->base);
 err_mem_ioremap:
-       clk_disable(dev->clk);
+       clk_disable_unprepare(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
 err_free_mem:
@@ -750,7 +775,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)
        i2c_del_adapter(&dev->adapter);
        put_device(&pdev->dev);
 
-       clk_disable(dev->clk);
+       clk_disable_unprepare(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
 
@@ -772,7 +797,7 @@ static int davinci_i2c_suspend(struct device *dev)
 
        /* put I2C into reset */
        davinci_i2c_reset_ctrl(i2c_dev, 0);
-       clk_disable(i2c_dev->clk);
+       clk_disable_unprepare(i2c_dev->clk);
 
        return 0;
 }
@@ -782,7 +807,7 @@ static int davinci_i2c_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 
-       clk_enable(i2c_dev->clk);
+       clk_prepare_enable(i2c_dev->clk);
        /* take I2C out of reset */
        davinci_i2c_reset_ctrl(i2c_dev, 1);
 
@@ -809,6 +834,7 @@ static struct platform_driver davinci_i2c_driver = {
                .name   = "i2c_davinci",
                .owner  = THIS_MODULE,
                .pm     = davinci_i2c_pm_ops,
+               .of_match_table = of_match_ptr(davinci_i2c_of_match),
        },
 };
 
index b7907ba7448aad13ccaa399ffc8cd34b05e3f48d..2ef162d148cbacbc63269bf89774c81aba34983c 100644 (file)
@@ -272,9 +272,9 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
 
        /* dev_dbg() can't be used, because adapter is not yet registered */
 #ifdef CONFIG_I2C_DEBUG_BUS
-       printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n",
+       dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
                __func__, i2c_clk_rate, div);
-       printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+       dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
                __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
 #endif
 }
@@ -564,7 +564,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
                resource_size(res), res->start);
        dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
                i2c_imx->adapter.name);
-       dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
+       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
 
        return 0;   /* Return OK */
 }
index 57f7703ce2e8cfbba6af7665b8cfde11e8d0fb9e..ca86430cb4a27e1374841f454d5bb5e70ad18b79 100644 (file)
@@ -576,7 +576,23 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                            mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
                }
        }
-       mpc_i2c_stop(i2c);
+       mpc_i2c_stop(i2c); /* Initiate STOP */
+       orig_jiffies = jiffies;
+       /* Wait until STOP is seen, allow up to 1 s */
+       while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+               if (time_after(jiffies, orig_jiffies + HZ)) {
+                       u8 status = readb(i2c->base + MPC_I2C_SR);
+
+                       dev_dbg(i2c->dev, "timeout\n");
+                       if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+                               writeb(status & ~CSR_MAL,
+                                      i2c->base + MPC_I2C_SR);
+                               mpc_i2c_fixup(i2c);
+                       }
+                       return -EIO;
+               }
+               cond_resched();
+       }
        return (ret < 0) ? ret : num;
 }
 
index 51f05b8520edb3f95b983d5002859afd386586e4..1f58197062cfe120b8987236044afbeec5e397df 100644 (file)
@@ -7,8 +7,6 @@
  *
  * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  *
- * TODO: add dma-support if platform-support for it is available
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_i2c.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/fsl/mxs-dma.h>
 
 #define DRIVER_NAME "mxs-i2c"
 
+static bool use_pioqueue;
+module_param(use_pioqueue, bool, 0);
+MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA");
+
 #define MXS_I2C_CTRL0          (0x00)
 #define MXS_I2C_CTRL0_SET      (0x04)
 
@@ -146,6 +151,16 @@ struct mxs_i2c_dev {
        u32 cmd_err;
        struct i2c_adapter adapter;
        const struct mxs_i2c_speed_config *speed;
+
+       /* DMA support components */
+       bool                            dma_mode;
+       int                             dma_channel;
+       struct dma_chan                 *dmach;
+       struct mxs_dma_data             dma_data;
+       uint32_t                        pio_data[2];
+       uint32_t                        addr_data;
+       struct scatterlist              sg_io[2];
+       bool                            dma_read;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
@@ -157,7 +172,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
        writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
 
        writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
-       writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+       if (i2c->dma_mode)
+               writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+                       i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+       else
+               writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
                        i2c->regs + MXS_I2C_QUEUECTRL_SET);
 }
 
@@ -248,6 +267,150 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
        return 0;
 }
 
+static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
+{
+       if (i2c->dma_read) {
+               dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+               dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+       } else {
+               dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+       }
+}
+
+static void mxs_i2c_dma_irq_callback(void *param)
+{
+       struct mxs_i2c_dev *i2c = param;
+
+       complete(&i2c->cmd_complete);
+       mxs_i2c_dma_finish(i2c);
+}
+
+static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
+                       struct i2c_msg *msg, uint32_t flags)
+{
+       struct dma_async_tx_descriptor *desc;
+       struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+
+       if (msg->flags & I2C_M_RD) {
+               i2c->dma_read = 1;
+               i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
+
+               /*
+                * SELECT command.
+                */
+
+               /* Queue the PIO register write transfer. */
+               i2c->pio_data[0] = MXS_CMD_I2C_SELECT;
+               desc = dmaengine_prep_slave_sg(i2c->dmach,
+                                       (struct scatterlist *)&i2c->pio_data[0],
+                                       1, DMA_TRANS_NONE, 0);
+               if (!desc) {
+                       dev_err(i2c->dev,
+                               "Failed to get PIO reg. write descriptor.\n");
+                       goto select_init_pio_fail;
+               }
+
+               /* Queue the DMA data transfer. */
+               sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1);
+               dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+               desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
+                                       DMA_MEM_TO_DEV,
+                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc) {
+                       dev_err(i2c->dev,
+                               "Failed to get DMA data write descriptor.\n");
+                       goto select_init_dma_fail;
+               }
+
+               /*
+                * READ command.
+                */
+
+               /* Queue the PIO register write transfer. */
+               i2c->pio_data[1] = flags | MXS_CMD_I2C_READ |
+                               MXS_I2C_CTRL0_XFER_COUNT(msg->len);
+               desc = dmaengine_prep_slave_sg(i2c->dmach,
+                                       (struct scatterlist *)&i2c->pio_data[1],
+                                       1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT);
+               if (!desc) {
+                       dev_err(i2c->dev,
+                               "Failed to get PIO reg. write descriptor.\n");
+                       goto select_init_dma_fail;
+               }
+
+               /* Queue the DMA data transfer. */
+               sg_init_one(&i2c->sg_io[1], msg->buf, msg->len);
+               dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+               desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
+                                       DMA_DEV_TO_MEM,
+                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc) {
+                       dev_err(i2c->dev,
+                               "Failed to get DMA data write descriptor.\n");
+                       goto read_init_dma_fail;
+               }
+       } else {
+               i2c->dma_read = 0;
+               i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
+
+               /*
+                * WRITE command.
+                */
+
+               /* Queue the PIO register write transfer. */
+               i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE |
+                               MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1);
+               desc = dmaengine_prep_slave_sg(i2c->dmach,
+                                       (struct scatterlist *)&i2c->pio_data[0],
+                                       1, DMA_TRANS_NONE, 0);
+               if (!desc) {
+                       dev_err(i2c->dev,
+                               "Failed to get PIO reg. write descriptor.\n");
+                       goto write_init_pio_fail;
+               }
+
+               /* Queue the DMA data transfer. */
+               sg_init_table(i2c->sg_io, 2);
+               sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1);
+               sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len);
+               dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+               desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
+                                       DMA_MEM_TO_DEV,
+                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc) {
+                       dev_err(i2c->dev,
+                               "Failed to get DMA data write descriptor.\n");
+                       goto write_init_dma_fail;
+               }
+       }
+
+       /*
+        * The last descriptor must have this callback,
+        * to finish the DMA transaction.
+        */
+       desc->callback = mxs_i2c_dma_irq_callback;
+       desc->callback_param = i2c;
+
+       /* Start the transfer. */
+       dmaengine_submit(desc);
+       dma_async_issue_pending(i2c->dmach);
+       return 0;
+
+/* Read failpath. */
+read_init_dma_fail:
+       dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+select_init_dma_fail:
+       dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+select_init_pio_fail:
+       return -EINVAL;
+
+/* Write failpath. */
+write_init_dma_fail:
+       dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+write_init_pio_fail:
+       return -EINVAL;
+}
+
 /*
  * Low level master read/write transaction.
  */
@@ -258,6 +421,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
        int ret;
        int flags;
 
+       flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
        dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
                msg->addr, msg->len, msg->flags, stop);
 
@@ -267,23 +432,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
        init_completion(&i2c->cmd_complete);
        i2c->cmd_err = 0;
 
-       flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
-
-       if (msg->flags & I2C_M_RD)
-               mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
-       else
-               mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
-                                       flags);
+       if (i2c->dma_mode) {
+               ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
+               if (ret)
+                       return ret;
+       } else {
+               if (msg->flags & I2C_M_RD) {
+                       mxs_i2c_pioq_setup_read(i2c, msg->addr,
+                                               msg->len, flags);
+               } else {
+                       mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf,
+                                               msg->len, flags);
+               }
 
-       writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+               writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
                        i2c->regs + MXS_I2C_QUEUECTRL_SET);
+       }
 
        ret = wait_for_completion_timeout(&i2c->cmd_complete,
                                                msecs_to_jiffies(1000));
        if (ret == 0)
                goto timeout;
 
-       if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+       if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) {
                ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
                if (ret)
                        goto timeout;
@@ -301,6 +472,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 
 timeout:
        dev_dbg(i2c->dev, "Timeout!\n");
+       if (i2c->dma_mode)
+               mxs_i2c_dma_finish(i2c);
        mxs_i2c_reset(i2c);
        return -ETIMEDOUT;
 }
@@ -342,11 +515,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
                /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
                i2c->cmd_err = -EIO;
 
-       is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
-               MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+       if (!i2c->dma_mode) {
+               is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+                       MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
 
-       if (is_last_cmd || i2c->cmd_err)
-               complete(&i2c->cmd_complete);
+               if (is_last_cmd || i2c->cmd_err)
+                       complete(&i2c->cmd_complete);
+       }
 
        writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
 
@@ -358,6 +533,21 @@ static const struct i2c_algorithm mxs_i2c_algo = {
        .functionality = mxs_i2c_func,
 };
 
+static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param)
+{
+       struct mxs_i2c_dev *i2c = param;
+
+       if (!mxs_dma_is_apbx(chan))
+               return false;
+
+       if (chan->chan_id != i2c->dma_channel)
+               return false;
+
+       chan->private = &i2c->dma_data;
+
+       return true;
+}
+
 static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
 {
        uint32_t speed;
@@ -365,6 +555,26 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
        struct device_node *node = dev->of_node;
        int ret;
 
+       /*
+        * The MXS I2C DMA mode is prefered and enabled by default.
+        * The PIO mode is still supported, but should be used only
+        * for debuging purposes etc.
+        */
+       i2c->dma_mode = !use_pioqueue;
+       if (!i2c->dma_mode)
+               dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n");
+
+       /*
+        * TODO: This is a temporary solution and should be changed
+        * to use generic DMA binding later when the helpers get in.
+        */
+       ret = of_property_read_u32(node, "fsl,i2c-dma-channel",
+                                  &i2c->dma_channel);
+       if (ret) {
+               dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n");
+               i2c->dma_mode = 0;
+       }
+
        ret = of_property_read_u32(node, "clock-frequency", &speed);
        if (ret)
                dev_warn(dev, "No I2C speed selected, using 100kHz\n");
@@ -384,7 +594,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
        struct pinctrl *pinctrl;
        struct resource *res;
        resource_size_t res_size;
-       int err, irq;
+       int err, irq, dmairq;
+       dma_cap_mask_t mask;
 
        pinctrl = devm_pinctrl_get_select_default(dev);
        if (IS_ERR(pinctrl))
@@ -395,7 +606,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
+       irq = platform_get_irq(pdev, 0);
+       dmairq = platform_get_irq(pdev, 1);
+
+       if (!res || irq < 0 || dmairq < 0)
                return -ENOENT;
 
        res_size = resource_size(res);
@@ -406,10 +620,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
        if (!i2c->regs)
                return -EBUSY;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
        err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
        if (err)
                return err;
@@ -423,6 +633,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
                        return err;
        }
 
+       /* Setup the DMA */
+       if (i2c->dma_mode) {
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               i2c->dma_data.chan_irq = dmairq;
+               i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
+               if (!i2c->dmach) {
+                       dev_err(dev, "Failed to request dma\n");
+                       return -ENODEV;
+               }
+       }
+
        platform_set_drvdata(pdev, i2c);
 
        /* Do reset to enforce correct startup after pinmuxing */
@@ -458,6 +680,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev)
        if (ret)
                return -EBUSY;
 
+       if (i2c->dmach)
+               dma_release_channel(i2c->dmach);
+
        writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
 
        platform_set_drvdata(pdev, NULL);
index 61b00edacb08179894c83b91d1f0cbe39a768b37..698d7acb0f083c10ea2028ad895e58043105f44e 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/i2c-nomadik.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
 
 #define DRIVER_NAME "nmk-i2c"
 
@@ -146,7 +147,6 @@ struct i2c_nmk_client {
  * @stop: stop condition.
  * @xfer_complete: acknowledge completion for a I2C message.
  * @result: controller propogated result.
- * @regulator: pointer to i2c regulator.
  * @busy: Busy doing transfer.
  */
 struct nmk_i2c_dev {
@@ -160,7 +160,6 @@ struct nmk_i2c_dev {
        int                             stop;
        struct completion               xfer_complete;
        int                             result;
-       struct regulator                *regulator;
        bool                            busy;
 };
 
@@ -643,8 +642,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 
        dev->busy = true;
 
-       if (dev->regulator)
-               regulator_enable(dev->regulator);
        pm_runtime_get_sync(&dev->adev->dev);
 
        clk_enable(dev->clk);
@@ -676,8 +673,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 out:
        clk_disable(dev->clk);
        pm_runtime_put_sync(&dev->adev->dev);
-       if (dev->regulator)
-               regulator_disable(dev->regulator);
 
        dev->busy = false;
 
@@ -920,18 +915,42 @@ static struct nmk_i2c_controller u8500_i2c = {
        .sm             = I2C_FREQ_MODE_FAST,
 };
 
+static void nmk_i2c_of_probe(struct device_node *np,
+                       struct nmk_i2c_controller *pdata)
+{
+       of_property_read_u32(np, "clock-frequency", &pdata->clk_freq);
+
+       /* This driver only supports 'standard' and 'fast' modes of operation. */
+       if (pdata->clk_freq <= 100000)
+               pdata->sm = I2C_FREQ_MODE_STANDARD;
+       else
+               pdata->sm = I2C_FREQ_MODE_FAST;
+}
+
 static atomic_t adapter_id = ATOMIC_INIT(0);
 
 static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
        struct nmk_i2c_controller *pdata = adev->dev.platform_data;
+       struct device_node *np = adev->dev.of_node;
        struct nmk_i2c_dev      *dev;
        struct i2c_adapter *adap;
 
-       if (!pdata)
-               /* No i2c configuration found, using the default. */
-               pdata = &u8500_i2c;
+       if (!pdata) {
+               if (np) {
+                       pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL);
+                       if (!pdata) {
+                               ret = -ENOMEM;
+                               goto err_no_mem;
+                       }
+                       /* Provide the default configuration as a base. */
+                       memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller));
+                       nmk_i2c_of_probe(np, pdata);
+               } else
+                       /* No i2c configuration found, using the default. */
+                       pdata = &u8500_i2c;
+       }
 
        dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
        if (!dev) {
@@ -957,12 +976,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
                goto err_irq;
        }
 
-       dev->regulator = regulator_get(&adev->dev, "v-i2c");
-       if (IS_ERR(dev->regulator)) {
-               dev_warn(&adev->dev, "could not get i2c regulator\n");
-               dev->regulator = NULL;
-       }
-
        pm_suspend_ignore_children(&adev->dev, true);
 
        dev->clk = clk_get(&adev->dev, NULL);
@@ -973,6 +986,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        adap = &dev->adap;
+       adap->dev.of_node = np;
        adap->dev.parent = &adev->dev;
        adap->owner     = THIS_MODULE;
        adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
@@ -1002,6 +1016,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
                goto err_add_adap;
        }
 
+       of_i2c_register_devices(adap);
+
        pm_runtime_put(&adev->dev);
 
        return 0;
@@ -1009,8 +1025,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
  err_add_adap:
        clk_put(dev->clk);
  err_no_clk:
-       if (dev->regulator)
-               regulator_put(dev->regulator);
        free_irq(dev->irq, dev);
  err_irq:
        iounmap(dev->virtbase);
@@ -1038,8 +1052,6 @@ static int nmk_i2c_remove(struct amba_device *adev)
        if (res)
                release_mem_region(res->start, resource_size(res));
        clk_put(dev->clk);
-       if (dev->regulator)
-               regulator_put(dev->regulator);
        pm_runtime_disable(&adev->dev);
        amba_set_drvdata(adev, NULL);
        kfree(dev);
index a0e49f6aaf96eaa81ac712a4a279fafbdf13af95..db31eaed6ea59b32083df49f757c1fc949c60303 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_OMAP1_REV_2           0x20
@@ -55,6 +56,9 @@
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
 
+/* timeout for pm runtime autosuspend */
+#define OMAP_I2C_PM_TIMEOUT            1000    /* ms */
+
 /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
 enum {
        OMAP_I2C_REV_REG = 0,
@@ -176,15 +180,15 @@ enum {
 #define I2C_OMAP_ERRATA_I462           (1 << 1)
 
 struct omap_i2c_dev {
+       spinlock_t              lock;           /* IRQ synchronization */
        struct device           *dev;
        void __iomem            *base;          /* virtual */
        int                     irq;
        int                     reg_shift;      /* bit shift for I2C register addresses */
        struct completion       cmd_complete;
        struct resource         *ioarea;
-       u32                     latency;        /* maximum mpu wkup latency */
-       void                    (*set_mpu_wkup_lat)(struct device *dev,
-                                                   long latency);
+       u32                     latency;        /* maximum MPU wkup latency */
+       struct pm_qos_request   pm_qos_request;
        u32                     speed;          /* Speed of bus in kHz */
        u32                     dtrev;          /* extra revision from DT */
        u32                     flags;
@@ -193,12 +197,14 @@ struct omap_i2c_dev {
        u8                      *regs;
        size_t                  buf_len;
        struct i2c_adapter      adapter;
+       u8                      threshold;
        u8                      fifo_size;      /* use as flag and value
                                                 * fifo_size==0 implies no fifo
                                                 * if set, should be trsh+1
                                                 */
        u8                      rev;
        unsigned                b_hw:1;         /* bad h/w fixes */
+       unsigned                receiver:1;     /* true when we're in receiver mode */
        u16                     iestate;        /* Saved interrupt register */
        u16                     pscstate;
        u16                     scllstate;
@@ -417,13 +423,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
        omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
 
-       if (dev->fifo_size) {
-               /* Note: setup required fifo size - 1. RTRSH and XTRSH */
-               buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR |
-                       (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR;
-               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
-       }
-
        /* Take the I2C module out of reset: */
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
@@ -461,6 +460,43 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
        return 0;
 }
 
+static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
+{
+       u16             buf;
+
+       if (dev->flags & OMAP_I2C_FLAG_NO_FIFO)
+               return;
+
+       /*
+        * Set up notification threshold based on message size. We're doing
+        * this to try and avoid draining feature as much as possible. Whenever
+        * we have big messages to transfer (bigger than our total fifo size)
+        * then we might use draining feature to transfer the remaining bytes.
+        */
+
+       dev->threshold = clamp(size, (u8) 1, dev->fifo_size);
+
+       buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+
+       if (is_rx) {
+               /* Clear RX Threshold */
+               buf &= ~(0x3f << 8);
+               buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR;
+       } else {
+               /* Clear TX Threshold */
+               buf &= ~0x3f;
+               buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR;
+       }
+
+       omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
+
+       if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
+               dev->b_hw = 1; /* Enable hardware fixes */
+
+       /* calculate wakeup latency constraint for MPU */
+       dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8);
+}
+
 /*
  * Low level master read/write transaction.
  */
@@ -477,6 +513,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        if (msg->len == 0)
                return -EINVAL;
 
+       dev->receiver = !!(msg->flags & I2C_M_RD);
+       omap_i2c_resize_fifo(dev, msg->len, dev->receiver);
+
        omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
 
        /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
@@ -590,8 +629,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        if (r < 0)
                goto out;
 
-       if (dev->set_mpu_wkup_lat != NULL)
-               dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+       /*
+        * When waiting for completion of a i2c transfer, we need to
+        * set a wake up latency constraint for the MPU. This is to
+        * ensure quick enough wakeup from idle, when transfer
+        * completes.
+        */
+       if (dev->latency)
+               pm_qos_add_request(&dev->pm_qos_request,
+                                  PM_QOS_CPU_DMA_LATENCY,
+                                  dev->latency);
 
        for (i = 0; i < num; i++) {
                r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
@@ -599,15 +646,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
                        break;
        }
 
-       if (dev->set_mpu_wkup_lat != NULL)
-               dev->set_mpu_wkup_lat(dev->dev, -1);
+       if (dev->latency)
+               pm_qos_remove_request(&dev->pm_qos_request);
 
        if (r == 0)
                r = num;
 
        omap_i2c_wait_for_bb(dev);
 out:
-       pm_runtime_put(dev->dev);
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
        return r;
 }
 
@@ -725,186 +773,252 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
  * data to DATA_REG. Otherwise some data bytes can be lost while transferring
  * them from the memory to the I2C interface.
  */
-static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
+static int errata_omap3_i462(struct omap_i2c_dev *dev)
 {
        unsigned long timeout = 10000;
+       u16 stat;
 
-       while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
-               if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
-                       omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
+       do {
+               stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+               if (stat & OMAP_I2C_STAT_XUDF)
+                       break;
+
+               if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+                       omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY |
                                                        OMAP_I2C_STAT_XDR));
-                       return -ETIMEDOUT;
+                       if (stat & OMAP_I2C_STAT_NACK) {
+                               dev->cmd_err |= OMAP_I2C_STAT_NACK;
+                               omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                       }
+
+                       if (stat & OMAP_I2C_STAT_AL) {
+                               dev_err(dev->dev, "Arbitration lost\n");
+                               dev->cmd_err |= OMAP_I2C_STAT_AL;
+                               omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                       }
+
+                       return -EIO;
                }
 
                cpu_relax();
-               *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-       }
+       } while (--timeout);
 
        if (!timeout) {
                dev_err(dev->dev, "timeout waiting on XUDF bit\n");
                return 0;
        }
 
-       *err |= OMAP_I2C_STAT_XUDF;
        return 0;
 }
 
+static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes,
+               bool is_rdr)
+{
+       u16             w;
+
+       while (num_bytes--) {
+               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+               *dev->buf++ = w;
+               dev->buf_len--;
+
+               /*
+                * Data reg in 2430, omap3 and
+                * omap4 is 8 bit wide
+                */
+               if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+                       *dev->buf++ = w >> 8;
+                       dev->buf_len--;
+               }
+       }
+}
+
+static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes,
+               bool is_xdr)
+{
+       u16             w;
+
+       while (num_bytes--) {
+               w = *dev->buf++;
+               dev->buf_len--;
+
+               /*
+                * Data reg in 2430, omap3 and
+                * omap4 is 8 bit wide
+                */
+               if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+                       w |= *dev->buf++ << 8;
+                       dev->buf_len--;
+               }
+
+               if (dev->errata & I2C_OMAP_ERRATA_I462) {
+                       int ret;
+
+                       ret = errata_omap3_i462(dev);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+       }
+
+       return 0;
+}
+
+static irqreturn_t
+omap_i2c_isr(int irq, void *dev_id)
+{
+       struct omap_i2c_dev *dev = dev_id;
+       irqreturn_t ret = IRQ_HANDLED;
+       u16 mask;
+       u16 stat;
+
+       spin_lock(&dev->lock);
+       mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+       stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+
+       if (stat & mask)
+               ret = IRQ_WAKE_THREAD;
+
+       spin_unlock(&dev->lock);
+
+       return ret;
+}
+
 static irqreturn_t
-omap_i2c_isr(int this_irq, void *dev_id)
+omap_i2c_isr_thread(int this_irq, void *dev_id)
 {
        struct omap_i2c_dev *dev = dev_id;
+       unsigned long flags;
        u16 bits;
-       u16 stat, w;
-       int err, count = 0;
+       u16 stat;
+       int err = 0, count = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       do {
+               bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+               stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+               stat &= bits;
+
+               /* If we're in receiver mode, ignore XDR/XRDY */
+               if (dev->receiver)
+                       stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY);
+               else
+                       stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY);
 
-       if (pm_runtime_suspended(dev->dev))
-               return IRQ_NONE;
+               if (!stat) {
+                       /* my work here is done */
+                       goto out;
+               }
 
-       bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
-       while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
                dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
                if (count++ == 100) {
                        dev_warn(dev->dev, "Too much work in one IRQ\n");
                        break;
                }
 
-               err = 0;
-complete:
-               /*
-                * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
-                * acked after the data operation is complete.
-                * Ref: TRM SWPU114Q Figure 18-31
-                */
-               omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
-                               ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
-                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
-
-               if (stat & OMAP_I2C_STAT_NACK)
+               if (stat & OMAP_I2C_STAT_NACK) {
                        err |= OMAP_I2C_STAT_NACK;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                       break;
+               }
 
                if (stat & OMAP_I2C_STAT_AL) {
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL);
+                       break;
                }
+
                /*
                 * ProDB0017052: Clear ARDY bit twice
                 */
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
                                        OMAP_I2C_STAT_AL)) {
-                       omap_i2c_ack_stat(dev, stat &
-                               (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
-                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
-                               OMAP_I2C_STAT_ARDY));
-                       omap_i2c_complete_cmd(dev, err);
-                       return IRQ_HANDLED;
+                       omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
+                                               OMAP_I2C_STAT_RDR |
+                                               OMAP_I2C_STAT_XRDY |
+                                               OMAP_I2C_STAT_XDR |
+                                               OMAP_I2C_STAT_ARDY));
+                       break;
                }
-               if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+
+               if (stat & OMAP_I2C_STAT_RDR) {
                        u8 num_bytes = 1;
 
+                       if (dev->fifo_size)
+                               num_bytes = dev->buf_len;
+
+                       omap_i2c_receive_data(dev, num_bytes, true);
+
                        if (dev->errata & I2C_OMAP_ERRATA_I207)
                                i2c_omap_errata_i207(dev, stat);
 
-                       if (dev->fifo_size) {
-                               if (stat & OMAP_I2C_STAT_RRDY)
-                                       num_bytes = dev->fifo_size;
-                               else    /* read RXSTAT on RDR interrupt */
-                                       num_bytes = (omap_i2c_read_reg(dev,
-                                                       OMAP_I2C_BUFSTAT_REG)
-                                                       >> 8) & 0x3F;
-                       }
-                       while (num_bytes) {
-                               num_bytes--;
-                               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
-                               if (dev->buf_len) {
-                                       *dev->buf++ = w;
-                                       dev->buf_len--;
-                                       /*
-                                        * Data reg in 2430, omap3 and
-                                        * omap4 is 8 bit wide
-                                        */
-                                       if (dev->flags &
-                                                OMAP_I2C_FLAG_16BIT_DATA_REG) {
-                                               if (dev->buf_len) {
-                                                       *dev->buf++ = w >> 8;
-                                                       dev->buf_len--;
-                                               }
-                                       }
-                               } else {
-                                       if (stat & OMAP_I2C_STAT_RRDY)
-                                               dev_err(dev->dev,
-                                                       "RRDY IRQ while no data"
-                                                               " requested\n");
-                                       if (stat & OMAP_I2C_STAT_RDR)
-                                               dev_err(dev->dev,
-                                                       "RDR IRQ while no data"
-                                                               " requested\n");
-                                       break;
-                               }
-                       }
-                       omap_i2c_ack_stat(dev,
-                               stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+                       break;
+               }
+
+               if (stat & OMAP_I2C_STAT_RRDY) {
+                       u8 num_bytes = 1;
+
+                       if (dev->threshold)
+                               num_bytes = dev->threshold;
+
+                       omap_i2c_receive_data(dev, num_bytes, false);
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
                        continue;
                }
-               if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+
+               if (stat & OMAP_I2C_STAT_XDR) {
                        u8 num_bytes = 1;
-                       if (dev->fifo_size) {
-                               if (stat & OMAP_I2C_STAT_XRDY)
-                                       num_bytes = dev->fifo_size;
-                               else    /* read TXSTAT on XDR interrupt */
-                                       num_bytes = omap_i2c_read_reg(dev,
-                                                       OMAP_I2C_BUFSTAT_REG)
-                                                       & 0x3F;
-                       }
-                       while (num_bytes) {
-                               num_bytes--;
-                               w = 0;
-                               if (dev->buf_len) {
-                                       w = *dev->buf++;
-                                       dev->buf_len--;
-                                       /*
-                                        * Data reg in 2430, omap3 and
-                                        * omap4 is 8 bit wide
-                                        */
-                                       if (dev->flags &
-                                                OMAP_I2C_FLAG_16BIT_DATA_REG) {
-                                               if (dev->buf_len) {
-                                                       w |= *dev->buf++ << 8;
-                                                       dev->buf_len--;
-                                               }
-                                       }
-                               } else {
-                                       if (stat & OMAP_I2C_STAT_XRDY)
-                                               dev_err(dev->dev,
-                                                       "XRDY IRQ while no "
-                                                       "data to send\n");
-                                       if (stat & OMAP_I2C_STAT_XDR)
-                                               dev_err(dev->dev,
-                                                       "XDR IRQ while no "
-                                                       "data to send\n");
-                                       break;
-                               }
-
-                               if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
-                                   errata_omap3_i462(dev, &stat, &err))
-                                       goto complete;
-
-                               omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
-                       }
-                       omap_i2c_ack_stat(dev,
-                               stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                       int ret;
+
+                       if (dev->fifo_size)
+                               num_bytes = dev->buf_len;
+
+                       ret = omap_i2c_transmit_data(dev, num_bytes, true);
+                       if (ret < 0)
+                               break;
+
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR);
+                       break;
+               }
+
+               if (stat & OMAP_I2C_STAT_XRDY) {
+                       u8 num_bytes = 1;
+                       int ret;
+
+                       if (dev->threshold)
+                               num_bytes = dev->threshold;
+
+                       ret = omap_i2c_transmit_data(dev, num_bytes, false);
+                       if (ret < 0)
+                               break;
+
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
                        continue;
                }
+
                if (stat & OMAP_I2C_STAT_ROVR) {
                        dev_err(dev->dev, "Receive overrun\n");
-                       dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+                       err |= OMAP_I2C_STAT_ROVR;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR);
+                       break;
                }
+
                if (stat & OMAP_I2C_STAT_XUDF) {
                        dev_err(dev->dev, "Transmit underflow\n");
-                       dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+                       err |= OMAP_I2C_STAT_XUDF;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF);
+                       break;
                }
-       }
+       } while (stat);
+
+       omap_i2c_complete_cmd(dev, err);
+
+out:
+       spin_unlock_irqrestore(&dev->lock, flags);
 
-       return count ? IRQ_HANDLED : IRQ_NONE;
+       return IRQ_HANDLED;
 }
 
 static const struct i2c_algorithm omap_i2c_algo = {
@@ -943,12 +1057,12 @@ omap_i2c_probe(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev;
        struct i2c_adapter      *adap;
-       struct resource         *mem, *irq, *ioarea;
+       struct resource         *mem;
        const struct omap_i2c_bus_platform_data *pdata =
                pdev->dev.platform_data;
        struct device_node      *node = pdev->dev.of_node;
        const struct of_device_id *match;
-       irq_handler_t isr;
+       int irq;
        int r;
 
        /* NOTE: driver uses the static register mapping */
@@ -957,23 +1071,23 @@ omap_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "no mem resource?\n");
                return -ENODEV;
        }
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq) {
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
                dev_err(&pdev->dev, "no irq resource?\n");
-               return -ENODEV;
+               return irq;
        }
 
-       ioarea = request_mem_region(mem->start, resource_size(mem),
-                       pdev->name);
-       if (!ioarea) {
-               dev_err(&pdev->dev, "I2C region already claimed\n");
-               return -EBUSY;
+       dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Menory allocation failed\n");
+               return -ENOMEM;
        }
 
-       dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
-       if (!dev) {
-               r = -ENOMEM;
-               goto err_release_region;
+       dev->base = devm_request_and_ioremap(&pdev->dev, mem);
+       if (!dev->base) {
+               dev_err(&pdev->dev, "I2C region already claimed\n");
+               return -ENOMEM;
        }
 
        match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
@@ -990,17 +1104,13 @@ omap_i2c_probe(struct platform_device *pdev)
        } else if (pdata != NULL) {
                dev->speed = pdata->clkrate;
                dev->flags = pdata->flags;
-               dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
                dev->dtrev = pdata->rev;
        }
 
        dev->dev = &pdev->dev;
-       dev->irq = irq->start;
-       dev->base = ioremap(mem->start, resource_size(mem));
-       if (!dev->base) {
-               r = -ENOMEM;
-               goto err_free_mem;
-       }
+       dev->irq = irq;
+
+       spin_lock_init(&dev->lock);
 
        platform_set_drvdata(pdev, dev);
        init_completion(&dev->cmd_complete);
@@ -1013,6 +1123,9 @@ omap_i2c_probe(struct platform_device *pdev)
                dev->regs = (u8 *)reg_map_ip_v1;
 
        pm_runtime_enable(dev->dev);
+       pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT);
+       pm_runtime_use_autosuspend(dev->dev);
+
        r = pm_runtime_get_sync(dev->dev);
        if (IS_ERR_VALUE(r))
                goto err_free_mem;
@@ -1042,32 +1155,31 @@ omap_i2c_probe(struct platform_device *pdev)
 
                dev->fifo_size = (dev->fifo_size / 2);
 
-               if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
-                       dev->b_hw = 0; /* Disable hardware fixes */
-               else
+               if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
                        dev->b_hw = 1; /* Enable hardware fixes */
 
                /* calculate wakeup latency constraint for MPU */
-               if (dev->set_mpu_wkup_lat != NULL)
-                       dev->latency = (1000000 * dev->fifo_size) /
-                                      (1000 * dev->speed / 8);
+               dev->latency = (1000000 * dev->fifo_size) /
+                              (1000 * dev->speed / 8);
        }
 
        /* reset ASAP, clearing any IRQs */
        omap_i2c_init(dev);
 
-       isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
-                                                                  omap_i2c_isr;
-       r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
+       if (dev->rev < OMAP_I2C_OMAP1_REV_2)
+               r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr,
+                               IRQF_NO_SUSPEND, pdev->name, dev);
+       else
+               r = devm_request_threaded_irq(&pdev->dev, dev->irq,
+                               omap_i2c_isr, omap_i2c_isr_thread,
+                               IRQF_NO_SUSPEND | IRQF_ONESHOT,
+                               pdev->name, dev);
 
        if (r) {
                dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
                goto err_unuse_clocks;
        }
 
-       dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
-                dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
-
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
@@ -1082,27 +1194,25 @@ omap_i2c_probe(struct platform_device *pdev)
        r = i2c_add_numbered_adapter(adap);
        if (r) {
                dev_err(dev->dev, "failure adding adapter\n");
-               goto err_free_irq;
+               goto err_unuse_clocks;
        }
 
+       dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr,
+                dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
        of_i2c_register_devices(adap);
 
-       pm_runtime_put(dev->dev);
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
 
        return 0;
 
-err_free_irq:
-       free_irq(dev->irq, dev);
 err_unuse_clocks:
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        pm_runtime_put(dev->dev);
-       iounmap(dev->base);
        pm_runtime_disable(&pdev->dev);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
-       kfree(dev);
-err_release_region:
-       release_mem_region(mem->start, resource_size(mem));
 
        return r;
 }
@@ -1110,12 +1220,10 @@ err_release_region:
 static int __devexit omap_i2c_remove(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev = platform_get_drvdata(pdev);
-       struct resource         *mem;
        int ret;
 
        platform_set_drvdata(pdev, NULL);
 
-       free_irq(dev->irq, dev);
        i2c_del_adapter(&dev->adapter);
        ret = pm_runtime_get_sync(&pdev->dev);
        if (IS_ERR_VALUE(ret))
@@ -1124,10 +1232,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev)
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       iounmap(dev->base);
-       kfree(dev);
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, resource_size(mem));
        return 0;
 }
 
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
new file mode 100644 (file)
index 0000000..f9399d1
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ *  drivers/i2c/busses/i2c-rcar.c
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is based on the drivers/i2c/busses/i2c-sh7760.c
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *
+ * This file used out-of-tree driver i2c-rcar.c
+ * Copyright (C) 2011-2012 Renesas Electronics 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; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c/i2c-rcar.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/* register offsets */
+#define ICSCR  0x00    /* slave ctrl */
+#define ICMCR  0x04    /* master ctrl */
+#define ICSSR  0x08    /* slave status */
+#define ICMSR  0x0C    /* master status */
+#define ICSIER 0x10    /* slave irq enable */
+#define ICMIER 0x14    /* master irq enable */
+#define ICCCR  0x18    /* clock dividers */
+#define ICSAR  0x1C    /* slave address */
+#define ICMAR  0x20    /* master address */
+#define ICRXTX 0x24    /* data port */
+
+/* ICMCR */
+#define MDBS   (1 << 7)        /* non-fifo mode switch */
+#define FSCL   (1 << 6)        /* override SCL pin */
+#define FSDA   (1 << 5)        /* override SDA pin */
+#define OBPC   (1 << 4)        /* override pins */
+#define MIE    (1 << 3)        /* master if enable */
+#define TSBE   (1 << 2)
+#define FSB    (1 << 1)        /* force stop bit */
+#define ESG    (1 << 0)        /* en startbit gen */
+
+/* ICMSR */
+#define MNR    (1 << 6)        /* nack received */
+#define MAL    (1 << 5)        /* arbitration lost */
+#define MST    (1 << 4)        /* sent a stop */
+#define MDE    (1 << 3)
+#define MDT    (1 << 2)
+#define MDR    (1 << 1)
+#define MAT    (1 << 0)        /* slave addr xfer done */
+
+/* ICMIE */
+#define MNRE   (1 << 6)        /* nack irq en */
+#define MALE   (1 << 5)        /* arblos irq en */
+#define MSTE   (1 << 4)        /* stop irq en */
+#define MDEE   (1 << 3)
+#define MDTE   (1 << 2)
+#define MDRE   (1 << 1)
+#define MATE   (1 << 0)        /* address sent irq en */
+
+
+enum {
+       RCAR_BUS_PHASE_ADDR,
+       RCAR_BUS_PHASE_DATA,
+       RCAR_BUS_PHASE_STOP,
+};
+
+enum {
+       RCAR_IRQ_CLOSE,
+       RCAR_IRQ_OPEN_FOR_SEND,
+       RCAR_IRQ_OPEN_FOR_RECV,
+       RCAR_IRQ_OPEN_FOR_STOP,
+};
+
+/*
+ * flags
+ */
+#define ID_LAST_MSG    (1 << 0)
+#define ID_IOERROR     (1 << 1)
+#define ID_DONE                (1 << 2)
+#define ID_ARBLOST     (1 << 3)
+#define ID_NACK                (1 << 4)
+
+struct rcar_i2c_priv {
+       void __iomem *io;
+       struct i2c_adapter adap;
+       struct i2c_msg  *msg;
+
+       spinlock_t lock;
+       wait_queue_head_t wait;
+
+       int pos;
+       int irq;
+       u32 icccr;
+       u32 flags;
+};
+
+#define rcar_i2c_priv_to_dev(p)                ((p)->adap.dev.parent)
+#define rcar_i2c_is_recv(p)            ((p)->msg->flags & I2C_M_RD)
+
+#define rcar_i2c_flags_set(p, f)       ((p)->flags |= (f))
+#define rcar_i2c_flags_has(p, f)       ((p)->flags & (f))
+
+#define LOOP_TIMEOUT   1024
+
+/*
+ *             basic functions
+ */
+static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
+{
+       writel(val, priv->io + reg);
+}
+
+static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
+{
+       return readl(priv->io + reg);
+}
+
+static void rcar_i2c_init(struct rcar_i2c_priv *priv)
+{
+       /*
+        * reset slave mode.
+        * slave mode is not used on this driver
+        */
+       rcar_i2c_write(priv, ICSIER, 0);
+       rcar_i2c_write(priv, ICSAR, 0);
+       rcar_i2c_write(priv, ICSCR, 0);
+       rcar_i2c_write(priv, ICSSR, 0);
+
+       /* reset master mode */
+       rcar_i2c_write(priv, ICMIER, 0);
+       rcar_i2c_write(priv, ICMCR, 0);
+       rcar_i2c_write(priv, ICMSR, 0);
+       rcar_i2c_write(priv, ICMAR, 0);
+}
+
+static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open)
+{
+       u32 val = MNRE | MALE | MSTE | MATE; /* default */
+
+       switch (open) {
+       case RCAR_IRQ_OPEN_FOR_SEND:
+               val |= MDEE; /* default + send */
+               break;
+       case RCAR_IRQ_OPEN_FOR_RECV:
+               val |= MDRE; /* default + read */
+               break;
+       case RCAR_IRQ_OPEN_FOR_STOP:
+               val = MSTE; /* stop irq only */
+               break;
+       case RCAR_IRQ_CLOSE:
+       default:
+               val = 0; /* all close */
+               break;
+       }
+       rcar_i2c_write(priv, ICMIER, val);
+}
+
+static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv)
+{
+       rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv);
+}
+
+/*
+ *             bus control functions
+ */
+static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
+{
+       int i;
+
+       for (i = 0; i < LOOP_TIMEOUT; i++) {
+               /* make sure that bus is not busy */
+               if (!(rcar_i2c_read(priv, ICMCR) & FSDA))
+                       return 0;
+               udelay(1);
+       }
+
+       return -EBUSY;
+}
+
+static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase)
+{
+       switch (phase) {
+       case RCAR_BUS_PHASE_ADDR:
+               rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG);
+               break;
+       case RCAR_BUS_PHASE_DATA:
+               rcar_i2c_write(priv, ICMCR, MDBS | MIE);
+               break;
+       case RCAR_BUS_PHASE_STOP:
+               rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB);
+               break;
+       }
+}
+
+/*
+ *             clock function
+ */
+static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
+                                   u32 bus_speed,
+                                   struct device *dev)
+{
+       struct clk *clkp = clk_get(NULL, "peripheral_clk");
+       u32 scgd, cdf;
+       u32 round, ick;
+       u32 scl;
+
+       if (!clkp) {
+               dev_err(dev, "there is no peripheral_clk\n");
+               return -EIO;
+       }
+
+       /*
+        * calculate SCL clock
+        * see
+        *      ICCCR
+        *
+        * ick  = clkp / (1 + CDF)
+        * SCL  = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+        *
+        * ick  : I2C internal clock < 20 MHz
+        * ticf : I2C SCL falling time  =  35 ns here
+        * tr   : I2C SCL rising  time  = 200 ns here
+        * intd : LSI internal delay    =  50 ns here
+        * clkp : peripheral_clk
+        * F[]  : integer up-valuation
+        */
+       for (cdf = 0; cdf < 4; cdf++) {
+               ick = clk_get_rate(clkp) / (1 + cdf);
+               if (ick < 20000000)
+                       goto ick_find;
+       }
+       dev_err(dev, "there is no best CDF\n");
+       return -EIO;
+
+ick_find:
+       /*
+        * it is impossible to calculate large scale
+        * number on u32. separate it
+        *
+        * F[(ticf + tr + intd) * ick]
+        *  = F[(35 + 200 + 50)ns * ick]
+        *  = F[285 * ick / 1000000000]
+        *  = F[(ick / 1000000) * 285 / 1000]
+        */
+       round = (ick + 500000) / 1000000 * 285;
+       round = (round + 500) / 1000;
+
+       /*
+        * SCL  = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+        *
+        * Calculation result (= SCL) should be less than
+        * bus_speed for hardware safety
+        */
+       for (scgd = 0; scgd < 0x40; scgd++) {
+               scl = ick / (20 + (scgd * 8) + round);
+               if (scl <= bus_speed)
+                       goto scgd_find;
+       }
+       dev_err(dev, "it is impossible to calculate best SCL\n");
+       return -EIO;
+
+scgd_find:
+       dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
+               scl, bus_speed, clk_get_rate(clkp), round, cdf, scgd);
+
+       /*
+        * keep icccr value
+        */
+       priv->icccr = (scgd << 2 | cdf);
+
+       return 0;
+}
+
+static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv)
+{
+       rcar_i2c_write(priv, ICCCR, priv->icccr);
+}
+
+/*
+ *             status functions
+ */
+static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv)
+{
+       return rcar_i2c_read(priv, ICMSR);
+}
+
+#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff)
+static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit)
+{
+       rcar_i2c_write(priv, ICMSR, ~bit);
+}
+
+/*
+ *             recv/send functions
+ */
+static int rcar_i2c_recv(struct rcar_i2c_priv *priv)
+{
+       rcar_i2c_set_addr(priv, 1);
+       rcar_i2c_status_clear(priv);
+       rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
+       rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV);
+
+       return 0;
+}
+
+static int rcar_i2c_send(struct rcar_i2c_priv *priv)
+{
+       int ret;
+
+       /*
+        * It should check bus status when send case
+        */
+       ret = rcar_i2c_bus_barrier(priv);
+       if (ret < 0)
+               return ret;
+
+       rcar_i2c_set_addr(priv, 0);
+       rcar_i2c_status_clear(priv);
+       rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
+       rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND);
+
+       return 0;
+}
+
+#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE))
+#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR))
+
+/*
+ *             interrupt functions
+ */
+static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
+{
+       struct i2c_msg *msg = priv->msg;
+
+       /*
+        * FIXME
+        * sometimes, unknown interrupt happened.
+        * Do nothing
+        */
+       if (!(msr & MDE))
+               return 0;
+
+       /*
+        * If address transfer phase finished,
+        * goto data phase.
+        */
+       if (msr & MAT)
+               rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
+
+       if (priv->pos < msg->len) {
+               /*
+                * Prepare next data to ICRXTX register.
+                * This data will go to _SHIFT_ register.
+                *
+                *    *
+                * [ICRXTX] -> [SHIFT] -> [I2C bus]
+                */
+               rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
+               priv->pos++;
+
+       } else {
+               /*
+                * The last data was pushed to ICRXTX on _PREV_ empty irq.
+                * It is on _SHIFT_ register, and will sent to I2C bus.
+                *
+                *                *
+                * [ICRXTX] -> [SHIFT] -> [I2C bus]
+                */
+
+               if (priv->flags & ID_LAST_MSG)
+                       /*
+                        * If current msg is the _LAST_ msg,
+                        * prepare stop condition here.
+                        * ID_DONE will be set on STOP irq.
+                        */
+                       rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+               else
+                       /*
+                        * If current msg is _NOT_ last msg,
+                        * it doesn't call stop phase.
+                        * thus, there is no STOP irq.
+                        * return ID_DONE here.
+                        */
+                       return ID_DONE;
+       }
+
+       rcar_i2c_send_restart(priv);
+
+       return 0;
+}
+
+static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
+{
+       struct i2c_msg *msg = priv->msg;
+
+       /*
+        * FIXME
+        * sometimes, unknown interrupt happened.
+        * Do nothing
+        */
+       if (!(msr & MDR))
+               return 0;
+
+       if (msr & MAT) {
+               /*
+                * Address transfer phase finished,
+                * but, there is no data at this point.
+                * Do nothing.
+                */
+       } else if (priv->pos < msg->len) {
+               /*
+                * get received data
+                */
+               msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
+               priv->pos++;
+       }
+
+       /*
+        * If next received data is the _LAST_,
+        * go to STOP phase,
+        * otherwise, go to DATA phase.
+        */
+       if (priv->pos + 1 >= msg->len)
+               rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+       else
+               rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
+
+       rcar_i2c_recv_restart(priv);
+
+       return 0;
+}
+
+static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
+{
+       struct rcar_i2c_priv *priv = ptr;
+       struct device *dev = rcar_i2c_priv_to_dev(priv);
+       u32 msr;
+
+       /*-------------- spin lock -----------------*/
+       spin_lock(&priv->lock);
+
+       msr = rcar_i2c_status_get(priv);
+
+       /*
+        * Arbitration lost
+        */
+       if (msr & MAL) {
+               /*
+                * CAUTION
+                *
+                * When arbitration lost, device become _slave_ mode.
+                */
+               dev_dbg(dev, "Arbitration Lost\n");
+               rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
+               goto out;
+       }
+
+       /*
+        * Stop
+        */
+       if (msr & MST) {
+               dev_dbg(dev, "Stop\n");
+               rcar_i2c_flags_set(priv, ID_DONE);
+               goto out;
+       }
+
+       /*
+        * Nack
+        */
+       if (msr & MNR) {
+               dev_dbg(dev, "Nack\n");
+
+               /* go to stop phase */
+               rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+               rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP);
+               rcar_i2c_flags_set(priv, ID_NACK);
+               goto out;
+       }
+
+       /*
+        * recv/send
+        */
+       if (rcar_i2c_is_recv(priv))
+               rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
+       else
+               rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr));
+
+out:
+       if (rcar_i2c_flags_has(priv, ID_DONE)) {
+               rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE);
+               rcar_i2c_status_clear(priv);
+               wake_up(&priv->wait);
+       }
+
+       spin_unlock(&priv->lock);
+       /*-------------- spin unlock -----------------*/
+
+       return IRQ_HANDLED;
+}
+
+static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
+                               struct i2c_msg *msgs,
+                               int num)
+{
+       struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+       struct device *dev = rcar_i2c_priv_to_dev(priv);
+       unsigned long flags;
+       int i, ret, timeout;
+
+       pm_runtime_get_sync(dev);
+
+       /*-------------- spin lock -----------------*/
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rcar_i2c_init(priv);
+       rcar_i2c_clock_start(priv);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       /*-------------- spin unlock -----------------*/
+
+       ret = -EINVAL;
+       for (i = 0; i < num; i++) {
+               /*-------------- spin lock -----------------*/
+               spin_lock_irqsave(&priv->lock, flags);
+
+               /* init each data */
+               priv->msg       = &msgs[i];
+               priv->pos       = 0;
+               priv->flags     = 0;
+               if (priv->msg == &msgs[num - 1])
+                       rcar_i2c_flags_set(priv, ID_LAST_MSG);
+
+               /* start send/recv */
+               if (rcar_i2c_is_recv(priv))
+                       ret = rcar_i2c_recv(priv);
+               else
+                       ret = rcar_i2c_send(priv);
+
+               spin_unlock_irqrestore(&priv->lock, flags);
+               /*-------------- spin unlock -----------------*/
+
+               if (ret < 0)
+                       break;
+
+               /*
+                * wait result
+                */
+               timeout = wait_event_timeout(priv->wait,
+                                            rcar_i2c_flags_has(priv, ID_DONE),
+                                            5 * HZ);
+               if (!timeout) {
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+
+               /*
+                * error handling
+                */
+               if (rcar_i2c_flags_has(priv, ID_NACK)) {
+                       ret = -EREMOTEIO;
+                       break;
+               }
+
+               if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
+                       ret = -EAGAIN;
+                       break;
+               }
+
+               if (rcar_i2c_flags_has(priv, ID_IOERROR)) {
+                       ret = -EIO;
+                       break;
+               }
+
+               ret = i + 1; /* The number of transfer */
+       }
+
+       pm_runtime_put(dev);
+
+       if (ret < 0)
+               dev_err(dev, "error %d : %x\n", ret, priv->flags);
+
+       return ret;
+}
+
+static u32 rcar_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm rcar_i2c_algo = {
+       .master_xfer    = rcar_i2c_master_xfer,
+       .functionality  = rcar_i2c_func,
+};
+
+static int __devinit rcar_i2c_probe(struct platform_device *pdev)
+{
+       struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data;
+       struct rcar_i2c_priv *priv;
+       struct i2c_adapter *adap;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       u32 bus_speed;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no mmio resources\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev, "no mem for private data\n");
+               return -ENOMEM;
+       }
+
+       bus_speed = 100000; /* default 100 kHz */
+       if (pdata && pdata->bus_speed)
+               bus_speed = pdata->bus_speed;
+       ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
+       if (ret < 0)
+               return ret;
+
+       priv->io = devm_ioremap(dev, res->start, resource_size(res));
+       if (!priv->io) {
+               dev_err(dev, "cannot ioremap\n");
+               return -ENODEV;
+       }
+
+       priv->irq = platform_get_irq(pdev, 0);
+       init_waitqueue_head(&priv->wait);
+       spin_lock_init(&priv->lock);
+
+       adap                    = &priv->adap;
+       adap->nr                = pdev->id;
+       adap->algo              = &rcar_i2c_algo;
+       adap->class             = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       adap->retries           = 3;
+       adap->dev.parent        = dev;
+       i2c_set_adapdata(adap, priv);
+       strlcpy(adap->name, pdev->name, sizeof(adap->name));
+
+       ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0,
+                              dev_name(dev), priv);
+       if (ret < 0) {
+               dev_err(dev, "cannot get irq %d\n", priv->irq);
+               return ret;
+       }
+
+       ret = i2c_add_numbered_adapter(adap);
+       if (ret < 0) {
+               dev_err(dev, "reg adap failed: %d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_enable(dev);
+       platform_set_drvdata(pdev, priv);
+
+       dev_info(dev, "probed\n");
+
+       return 0;
+}
+
+static int __devexit rcar_i2c_remove(struct platform_device *pdev)
+{
+       struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+
+       i2c_del_adapter(&priv->adap);
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+static struct platform_driver rcar_i2c_drv = {
+       .driver = {
+               .name   = "i2c-rcar",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = rcar_i2c_probe,
+       .remove         = __devexit_p(rcar_i2c_remove),
+};
+
+module_platform_driver(rcar_i2c_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 4d07dea9bca9db1ad13305f3d7b44615b3e8ed6b..3e0335f1fc60df8b78ce50c7a4e5284e82ad432f 100644 (file)
@@ -601,14 +601,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
        int ret;
 
        pm_runtime_get_sync(&adap->dev);
-       clk_enable(i2c->clk);
+       clk_prepare_enable(i2c->clk);
 
        for (retry = 0; retry < adap->retries; retry++) {
 
                ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
 
                if (ret != -EAGAIN) {
-                       clk_disable(i2c->clk);
+                       clk_disable_unprepare(i2c->clk);
                        pm_runtime_put(&adap->dev);
                        return ret;
                }
@@ -618,7 +618,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
                udelay(100);
        }
 
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
        pm_runtime_put(&adap->dev);
        return -EREMOTEIO;
 }
@@ -977,7 +977,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
 
-       clk_enable(i2c->clk);
+       clk_prepare_enable(i2c->clk);
 
        /* map the registers */
 
@@ -1065,7 +1065,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        pm_runtime_enable(&i2c->adap.dev);
 
        dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
        return 0;
 
  err_cpufreq:
@@ -1082,7 +1082,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        kfree(i2c->ioarea);
 
  err_clk:
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
        clk_put(i2c->clk);
 
  err_noclk:
@@ -1106,7 +1106,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
        i2c_del_adapter(&i2c->adap);
        free_irq(i2c->irq, i2c);
 
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
        clk_put(i2c->clk);
 
        iounmap(i2c->regs);
@@ -1135,9 +1135,9 @@ static int s3c24xx_i2c_resume(struct device *dev)
        struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
        i2c->suspended = 0;
-       clk_enable(i2c->clk);
+       clk_prepare_enable(i2c->clk);
        s3c24xx_i2c_init(i2c);
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
 
        return 0;
 }
index 1364d62e2fbe4c171d3146313bb767ffab421fe3..a3c3ecd59f08cf5ab801cd890edad28eb117340c 100644 (file)
@@ -62,6 +62,7 @@ struct i2c_algo_pca_data {
         * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000
         * For PCA9665, use the frequency you want here. */
        unsigned int                    i2c_clock;
+       unsigned int                    chip;
 };
 
 int i2c_pca_add_bus(struct i2c_adapter *);
index 92a0dc75bc74661541e5b5c15f4cdd095c922b38..df804ba73e0b2ae97d935ba2c3797cd36b1499de 100644 (file)
@@ -34,7 +34,6 @@ struct omap_i2c_bus_platform_data {
        u32             clkrate;
        u32             rev;
        u32             flags;
-       void            (*set_mpu_wkup_lat)(struct device *dev, long set);
 };
 
 #endif
diff --git a/include/linux/i2c/i2c-rcar.h b/include/linux/i2c/i2c-rcar.h
new file mode 100644 (file)
index 0000000..496f5c2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __I2C_R_CAR_H__
+#define __I2C_R_CAR_H__
+
+#include <linux/platform_device.h>
+
+struct i2c_rcar_platform_data {
+       u32 bus_speed;
+};
+
+#endif /* __I2C_R_CAR_H__ */
index c2303c3e4803577d4d0b2fb7533e4ddb1638a0e7..3a8be9cdc95c1424434e1532d981ca4787c39dc6 100644 (file)
@@ -28,7 +28,7 @@ enum i2c_freq_mode {
  * @sm:                speed mode
  */
 struct nmk_i2c_controller {
-       unsigned long   clk_freq;
+       u32             clk_freq;
        unsigned short  slsu;
        unsigned char   tft;
        unsigned char   rft;