add i2c drivers
authorkfx <kfx@rock-chips.com>
Thu, 11 Nov 2010 08:51:12 +0000 (16:51 +0800)
committerkfx <kfx@rock-chips.com>
Thu, 11 Nov 2010 08:51:12 +0000 (16:51 +0800)
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/devices.c
arch/arm/mach-rk29/devices.h
arch/arm/mach-rk29/include/mach/board.h
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-rk2818.c
drivers/i2c/busses/i2c-rk29.c [new file with mode: 0755]
drivers/i2c/busses/i2c-rk29.h [new file with mode: 0755]
drivers/i2c/i2c-core.c
include/linux/i2c.h

index 26201e6ab342511dac8dc39f6e4b971ab908280a..8ba184163f5bfdf53562df454eb2684b9f258f3e 100755 (executable)
@@ -332,6 +332,90 @@ static struct platform_device android_pmem_vpu_device = {
                .platform_data = &android_pmem_vpu_pdata,\r
        },\r
 };\r
+/*****************************************************************************************\r
+ * i2c devices\r
+ * author: kfx@rock-chips.com\r
+*****************************************************************************************/\r
+static int rk29_i2c0_io_init(void)\r
+{\r
+       rk29_mux_api_set(GPIO2B7_I2C0SCL_NAME, GPIO2L_I2C0_SCL);\r
+       rk29_mux_api_set(GPIO2B6_I2C0SDA_NAME, GPIO2L_I2C0_SDA);\r
+       return 0;\r
+}\r
+\r
+static int rk29_i2c1_io_init(void)\r
+{\r
+       rk29_mux_api_set(GPIO1A7_I2C1SCL_NAME, GPIO1L_I2C1_SCL);\r
+       rk29_mux_api_set(GPIO1A6_I2C1SDA_NAME, GPIO1L_I2C1_SDA);\r
+       return 0;\r
+}\r
+static int rk29_i2c2_io_init(void)\r
+{\r
+       rk29_mux_api_set(GPIO5D4_I2C2SCL_NAME, GPIO5H_I2C2_SCL);\r
+       rk29_mux_api_set(GPIO5D3_I2C2SDA_NAME, GPIO5H_I2C2_SDA);\r
+       return 0;\r
+}\r
+\r
+static int rk29_i2c3_io_init(void)\r
+{\r
+       rk29_mux_api_set(GPIO2B5_UART3RTSN_I2C3SCL_NAME, GPIO2L_I2C3_SCL);\r
+       rk29_mux_api_set(GPIO2B4_UART3CTSN_I2C3SDA_NAME, GPIO2L_I2C3_SDA);\r
+       return 0;\r
+}\r
+\r
+struct rk29_i2c_platform_data default_i2c0_data = { \r
+       .bus_num    = 0,\r
+       .flags      = 0,\r
+       .slave_addr = 0xff,\r
+       .scl_rate  = 400*1000,\r
+       .mode           = I2C_MODE_IRQ,\r
+       .io_init = rk29_i2c0_io_init,\r
+};\r
+struct rk29_i2c_platform_data default_i2c1_data = { \r
+       .bus_num    = 1,\r
+       .flags      = 0,\r
+       .slave_addr = 0xff,\r
+       .scl_rate  = 400*1000,\r
+       .mode           = I2C_MODE_POLL,\r
+       .io_init = rk29_i2c1_io_init,\r
+};\r
+struct rk29_i2c_platform_data default_i2c2_data = { \r
+       .bus_num    = 2,\r
+       .flags      = 0,\r
+       .slave_addr = 0xff,\r
+       .scl_rate  = 400*1000,\r
+       .mode           = I2C_MODE_IRQ,\r
+       .io_init = rk29_i2c2_io_init,\r
+};\r
+struct rk29_i2c_platform_data default_i2c3_data = { \r
+       .bus_num    = 3,\r
+       .flags      = 0,\r
+       .slave_addr = 0xff,\r
+       .scl_rate  = 400*1000,\r
+       .mode           = I2C_MODE_POLL,\r
+       .io_init = rk29_i2c3_io_init,\r
+};\r
+\r
+\r
+static struct i2c_board_info __initdata board_i2c0_devices[] = {\r
+#if defined (CONFIG_RK1000_CONTROL)\r
+       {\r
+               .type                   = "rk1000_control",\r
+               .addr           = 0x40,\r
+               .flags                  = 0,\r
+       },\r
+#endif\r
+};\r
+static struct i2c_board_info __initdata board_i2c1_devices[] = {\r
+\r
+};\r
+static struct i2c_board_info __initdata board_i2c2_devices[] = {\r
+\r
+};\r
+static struct i2c_board_info __initdata board_i2c3_devices[] = {\r
+\r
+};\r
+\r
 \r
 /*****************************************************************************************\r
  * SDMMC devices\r
@@ -345,7 +429,7 @@ void rk29_sdmmc0_cfg_gpio(struct platform_device *dev)
        rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1);\r
        rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2);\r
        rk29_mux_api_set(GPIO1D5_SDMMC0DATA3_NAME, GPIO1H_SDMMC0_DATA3);\r
-       rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N);\r
+       rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); \r
 }\r
 \r
 #define CONFIG_SDMMC0_USE_DMA\r
@@ -373,7 +457,7 @@ void rk29_sdmmc1_cfg_gpio(struct platform_device *dev)
        rk29_mux_api_set(GPIO1C3_SDMMC1DATA0_NAME, GPIO1H_SDMMC1_DATA0);\r
        rk29_mux_api_set(GPIO1C4_SDMMC1DATA1_NAME, GPIO1H_SDMMC1_DATA1);\r
        rk29_mux_api_set(GPIO1C5_SDMMC1DATA2_NAME, GPIO1H_SDMMC1_DATA2);\r
-       rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3);\r
+       rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3); \r
 }\r
 \r
 struct rk29_sdmmc_platform_data default_sdmmc1_data = {\r
@@ -457,7 +541,21 @@ static void __init rk29_board_iomux_init(void)
 static struct platform_device *devices[] __initdata = {\r
 #ifdef CONFIG_UART1_RK29\r
        &rk29_device_uart1,\r
-#endif \r
+#endif\r
+\r
+#ifdef CONFIG_I2C0_RK29\r
+       &rk29_device_i2c0,\r
+#endif\r
+#ifdef CONFIG_I2C1_RK29\r
+       &rk29_device_i2c1,\r
+#endif\r
+#ifdef CONFIG_I2C2_RK29\r
+       &rk29_device_i2c2,\r
+#endif\r
+#ifdef CONFIG_I2C3_RK29\r
+       &rk29_device_i2c3,\r
+#endif\r
+\r
 #ifdef CONFIG_SDMMC0_RK29      \r
        &rk29_device_sdmmc0,\r
 #endif\r
@@ -492,7 +590,23 @@ static void __init machine_rk29_init_irq(void)
 }\r
 \r
 static void __init machine_rk29_board_init(void)\r
-{ \r
+{\r
+#ifdef CONFIG_I2C0_RK29\r
+       i2c_register_board_info(default_i2c0_data.bus_num, board_i2c0_devices,\r
+                       ARRAY_SIZE(board_i2c0_devices));\r
+#endif\r
+#ifdef CONFIG_I2C1_RK29\r
+       i2c_register_board_info(default_i2c1_data.bus_num, board_i2c1_devices,\r
+                       ARRAY_SIZE(board_i2c1_devices));\r
+#endif\r
+#ifdef CONFIG_I2C2_RK29\r
+       i2c_register_board_info(default_i2c2_data.bus_num, board_i2c2_devices,\r
+                       ARRAY_SIZE(board_i2c2_devices));\r
+#endif\r
+#ifdef CONFIG_I2C3_RK29\r
+       i2c_register_board_info(default_i2c3_data.bus_num, board_i2c3_devices,\r
+                       ARRAY_SIZE(board_i2c3_devices));\r
+#endif\r
        platform_add_devices(devices, ARRAY_SIZE(devices));     \r
        rk29_board_iomux_init();\r
 }\r
index 492fc69ea47125136c7e4899a923a48bff6f9684..521f7c4f176f3f612379d7d494e1310f96d32320 100755 (executable)
 #include <mach/irqs.h>
 #include <mach/rk29_iomap.h>
 #include "devices.h"
+#ifdef CONFIG_I2C_RK29
+static struct resource resources_i2c0[] = {
+       {
+               .start  = IRQ_I2C0,
+               .end    = IRQ_I2C0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_I2C0_PHYS,
+               .end    = RK29_I2C0_PHYS + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+static struct resource resources_i2c1[] = {
+       {
+               .start  = IRQ_I2C1,
+               .end    = IRQ_I2C1,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_I2C1_PHYS,
+               .end    = RK29_I2C1_PHYS + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+static struct resource resources_i2c2[] = {
+       {
+               .start  = IRQ_I2C2,
+               .end    = IRQ_I2C2,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_I2C2_PHYS,
+               .end    = RK29_I2C2_PHYS + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+static struct resource resources_i2c3[] = {
+       {
+               .start  = IRQ_I2C3,
+               .end    = IRQ_I2C3,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_I2C3_PHYS,
+               .end    = RK29_I2C3_PHYS + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device rk29_device_i2c0 = {
+       .name   = "rk29_i2c",
+       .id     = 0,
+       .num_resources  = ARRAY_SIZE(resources_i2c0),
+       .resource       = resources_i2c0,
+       .dev                    = {
+               .platform_data = &default_i2c0_data,
+       },
+};
+struct platform_device rk29_device_i2c1 = {
+       .name   = "rk29_i2c",
+       .id     = 1,
+       .num_resources  = ARRAY_SIZE(resources_i2c1),
+       .resource       = resources_i2c1,
+       .dev                    = {
+               .platform_data = &default_i2c1_data,
+       },
+};
+struct platform_device rk29_device_i2c2 = {
+       .name   = "rk29_i2c",
+       .id     = 2,
+       .num_resources  = ARRAY_SIZE(resources_i2c2),
+       .resource       = resources_i2c2,
+       .dev                    = {
+               .platform_data = &default_i2c2_data,
+       },
+};
+struct platform_device rk29_device_i2c3 = {
+       .name   = "rk29_i2c",
+       .id     = 3,
+       .num_resources  = ARRAY_SIZE(resources_i2c3),
+       .resource       = resources_i2c3,
+       .dev                    = {
+               .platform_data = &default_i2c3_data,
+       },
+};
+#endif
 
 #ifdef CONFIG_SDMMC0_RK29 
 static struct resource resources_sdmmc0[] = {
index fd1fe6e5d97bd8ca3bcd761406ede1bcff5fc7f4..a39938aa953ba454c40b800685392292c005d6f6 100755 (executable)
 #define __ARCH_ARM_MACH_RK29_DEVICES_H
 
 extern struct rk29_nand_platform_data rk29_nand_data;
-
+extern struct rk29_i2c_platform_data default_i2c0_data;
+extern struct rk29_i2c_platform_data default_i2c1_data;
+extern struct rk29_i2c_platform_data default_i2c2_data;
+extern struct rk29_i2c_platform_data default_i2c3_data;
+extern struct platform_device rk29_device_i2c0;
+extern struct platform_device rk29_device_i2c1;
+extern struct platform_device rk29_device_i2c2;
+extern struct platform_device rk29_device_i2c3;
 extern struct platform_device rk29_device_uart0;
 extern struct platform_device rk29_device_uart1;
 extern struct platform_device rk29_device_uart2;
index bb575a0e2311241d177eaf311a1e124ffdb5ecc1..b4772b7148b43d32e2fc0f97e43641b4163547e6 100755 (executable)
@@ -60,6 +60,17 @@ struct rk29_sdmmc_platform_data {
        int (*status)(struct device *);
        int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
 };
+struct rk29_i2c_platform_data {
+       int     bus_num;        
+       unsigned int    flags;     
+       unsigned int    slave_addr; 
+       unsigned long   scl_rate;   
+#define I2C_MODE_IRQ    0
+#define I2C_MODE_POLL   1
+       unsigned int    mode:1;
+       int (*io_init)(void);
+       int (*io_deinit)(void);
+};
 
 void __init rk29_map_common_io(void);
 void __init rk29_clock_init(void);
index 53b67a9eb07303955a9e9ce6f54d28e53eab1dd7..241ec4b3ed6f7817a3ee1d1c326a902cb4d74981 100644 (file)
@@ -7,23 +7,63 @@ menu "I2C Hardware Bus support"
 config I2C_RK2818
        tristate "RK2818 i2c interface (I2C)"
        depends on ARCH_RK2818
+       default y
        help
                This supports the use of the I2C interface on rk2818 processors.
 
 if I2C_RK2818
-       comment "Now, there are two I2C interfaces selected by developer, I2C0 and I2C1."
+       comment "Now, there are two I2C interfaces selected by developer."
        
-       menuconfig I2C0_RK2818
-               tristate "RK2818 I2C0 interface support"
+       config I2C0_RK2818
+               bool "RK2818 I2C0 interface support"
                default y
                depends on ARCH_RK2818
                help
                        This supports the use of the I2C0 interface on rk2818 processors.
-       menuconfig I2C1_RK2818
-               tristate "RK2818 I2C1 interface support"
+       config I2C1_RK2818
+               bool "RK2818 I2C1 interface support"
                default y
                depends on ARCH_RK2818
                help
                        This supports the use of the I2C1 interface on rk2818 processors.
 endif
+config I2C_RK29
+       tristate "RK29 i2c interface (I2C)"
+       depends on ARCH_RK29
+       default y
+       help
+               This supports the use of the I2C interface(i2c0 ~ i2c3) on rk29 processors.
+
+if I2C_RK29
+       comment "Now, there are four I2C interfaces selected by developer."
+       
+       config I2C0_RK29
+               bool "RK29 I2C0 interface support"
+               default y
+               depends on ARCH_RK29
+               help
+                       This supports the use of the I2C0 interface on rk29 processors.
+
+       config I2C1_RK29
+               bool "RK29 I2C1 interface support"
+               default y
+               depends on ARCH_RK29
+               help
+                       This supports the use of the I2C1 interface on rk29 processors.
+
+       config I2C2_RK29
+               bool "RK29 I2C2 interface support"
+               default y
+               depends on ARCH_RK29
+               help
+                       This supports the use of the I2C2 interface on rk29 processors.
+
+       config I2C3_RK29
+               bool "RK29 I2C3 interface support"
+               default y
+               depends on ARCH_RK29 && !UART3_CTS_RTS_RK29
+               help
+                       This supports the use of the I2C3 interface on rk29 processors.
+endif
+
 endmenu
index 479f8a8ed7148aea2f87ecceb240c7ec60703f39..98e13476d3b64dc627d1bc3e216629a46231d92f 100644 (file)
@@ -2,6 +2,7 @@
 # Makefile for the i2c bus drivers.
 #
 obj-$(CONFIG_I2C_RK2818)       += i2c-rk2818.o
+obj-$(CONFIG_I2C_RK29)         += i2c-rk29.o
 
 ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
 EXTRA_CFLAGS += -DDEBUG
index 545ebbfebfe147af038eaa9896177660fa2deb4c..4913063d7d68e11049f005126a81d498231c441b 100755 (executable)
@@ -1,4 +1,4 @@
-/* drivers/i2c/busses/i2c_rk2818.c
+/* drivers/i2c/busses/i2c_rockchip.c
  *
  * Copyright (C) 2010 ROCKCHIP, Inc.
  *
@@ -29,8 +29,8 @@
 #include <mach/board.h>
 #include <asm/io.h>
 
-#include "i2c-rk2818.h"
-#define DRV_NAME       "rk2818_i2c"
+#include "i2c-rockchip.h"
+#define DRV_NAME       "rockchip_i2c"
 
 #define RK2818_I2C_TIMEOUT             (msecs_to_jiffies(500))
 #define RK2818_DELAY_TIME              2
 #define i2c_dbg(dev, format, arg...)   
 #endif
 
-enum rk2818_error {
+enum rockchip_error {
        RK2818_ERROR_NONE = 0,
        RK2818_ERROR_ARBITR_LOSE,
        RK2818_ERROR_UNKNOWN
 };
 
-enum rk2818_event {
+enum rockchip_event {
        RK2818_EVENT_NONE = 0,
        /* master has received ack(MTX mode) 
           means that data has been sent to slave.
@@ -61,7 +61,7 @@ enum rk2818_event {
        RK2818_EVENT_MAX
 };
 
-struct rk2818_i2c_data {
+struct rockchip_i2c_data {
        struct device                   *dev;  
        struct i2c_adapter              adap;
        void __iomem                    *regs;
@@ -78,8 +78,8 @@ struct rk2818_i2c_data {
 
        spinlock_t                              cmd_lock;
        struct completion               cmd_complete;
-       enum rk2818_event               cmd_event;
-       enum rk2818_error               cmd_err;
+       enum rockchip_event             cmd_event;
+       enum rockchip_error             cmd_err;
 
        unsigned int                    msg_idx;
        unsigned int                    msg_num;
@@ -88,16 +88,16 @@ struct rk2818_i2c_data {
 #endif 
 };
 
-static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c);
+static void rockchip_i2c_init_hw(struct rockchip_i2c_data *i2c);
 
-static inline void rk2818_i2c_disable_irqs(struct rk2818_i2c_data *i2c)
+static inline void rockchip_i2c_disable_irqs(struct rockchip_i2c_data *i2c)
 {
        unsigned long tmp;
 
        tmp = readl(i2c->regs + I2C_IER);
        writel(tmp & IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
 }
-static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c)
+static inline void rockchip_i2c_enable_irqs(struct rockchip_i2c_data *i2c)
 {
        unsigned long tmp;
 
@@ -106,7 +106,7 @@ static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c)
 }
 
 /* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
-static void rk2818_i2c_calcdivisor(unsigned long pclk, 
+static void rockchip_i2c_calcdivisor(unsigned long pclk, 
                                                                unsigned long scl_rate, 
                                                                unsigned long *real_rate,
                                                                unsigned int *rem, unsigned int *exp)
@@ -131,9 +131,13 @@ static void rk2818_i2c_calcdivisor(unsigned long pclk,
        return;
 }
 /* set i2c bus scl rate */
-static void  rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
+static void  rockchip_i2c_clockrate(struct rockchip_i2c_data *i2c)
 {
+#ifdef CONFIG_ARCH_RK2818
        struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data;
+#else
+       struct rk29_i2c_platform_data *pdata = i2c->dev->platform_data;
+#endif
        unsigned int rem = 0, exp = 0;
        unsigned long scl_rate, real_rate = 0, tmp;
 
@@ -141,7 +145,7 @@ static void  rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
 
        scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000);
 
-       rk2818_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
+       rockchip_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
 
        tmp = readl(i2c->regs + I2C_OPR);
        tmp |= exp;
@@ -155,7 +159,7 @@ static void  rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
                                i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
        return;
 }
-static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
+static int rockchip_event_occurred(struct rockchip_i2c_data *i2c)
 {
        unsigned long isr;
 
@@ -195,28 +199,28 @@ static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
        return 0;
 }
 
-static irqreturn_t rk2818_i2c_irq(int irq, void *data)
+static irqreturn_t rockchip_i2c_irq(int irq, void *data)
 {
-       struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)data;
+       struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)data;
        int res;
        
-       rk2818_i2c_disable_irqs(i2c);
+       rockchip_i2c_disable_irqs(i2c);
        spin_lock(&i2c->cmd_lock);
-       res = rk2818_event_occurred(i2c);
+       res = rockchip_event_occurred(i2c);
        if(res)
        //if(res || i2c->cmd_err != RK2818_ERROR_NONE)
                complete(&i2c->cmd_complete);
        spin_unlock(&i2c->cmd_lock);
        return IRQ_HANDLED;
 }
-static int wait_for_completion_poll_timeout(struct rk2818_i2c_data *i2c, unsigned long timeout)
+static int wait_for_completion_poll_timeout(struct rockchip_i2c_data *i2c, unsigned long timeout)
 {
        unsigned int time = RK2818_DELAY_TIME;
        int res;
 
        while(!time_after(jiffies, jiffies + timeout))
        {
-               res = rk2818_event_occurred(i2c);
+               res = rockchip_event_occurred(i2c);
                if(res)
                //if(res || (i2c->cmd_err != RK2818_ERROR_NONE && i2c->cmd_err != RK2818_ERROR_UNKNOWN))
                        return 1;
@@ -226,8 +230,8 @@ static int wait_for_completion_poll_timeout(struct rk2818_i2c_data *i2c, unsigne
        return 0;
 
 }
-static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
-                                       enum rk2818_event mr_event)
+static int rockchip_wait_event(struct rockchip_i2c_data *i2c,
+                                       enum rockchip_event mr_event)
 {
        int ret = 0;
        unsigned long flags;
@@ -247,7 +251,7 @@ static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
 
        spin_unlock_irqrestore(&i2c->cmd_lock,flags);
 
-       rk2818_i2c_enable_irqs(i2c);
+       rockchip_i2c_enable_irqs(i2c);
        if(i2c->mode == I2C_MODE_IRQ)
                ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
                                                                RK2818_I2C_TIMEOUT);
@@ -266,7 +270,7 @@ static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
        return 0;
 }
 
-static int rk2818_wait_while_busy(struct rk2818_i2c_data *i2c)
+static int rockchip_wait_while_busy(struct rockchip_i2c_data *i2c)
 {
        unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
        unsigned long lsr;
@@ -282,7 +286,7 @@ static int rk2818_wait_while_busy(struct rk2818_i2c_data *i2c)
        }
        return -ETIMEDOUT;
 }
-static int rk2818_i2c_stop(struct rk2818_i2c_data *i2c)
+static int rockchip_i2c_stop(struct rockchip_i2c_data *i2c)
 {
        unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
        unsigned int time = RK2818_DELAY_TIME;
@@ -301,7 +305,7 @@ static int rk2818_i2c_stop(struct rk2818_i2c_data *i2c)
        return -ETIMEDOUT;
     
 }
-static int rk2818_send_2nd_addr(struct rk2818_i2c_data *i2c,
+static int rockchip_send_2nd_addr(struct rockchip_i2c_data *i2c,
                                                struct i2c_msg *msg, int start)
 {
        int ret = 0;
@@ -315,14 +319,14 @@ static int rk2818_send_2nd_addr(struct rk2818_i2c_data *i2c,
        i2c_dbg(i2c->dev, "i2c send addr_2nd: %lx\n", addr_2nd);        
        writel(addr_2nd, i2c->regs + I2C_MTXR);
        writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
-       if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+       if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
        {
                dev_err(i2c->dev, "after sent addr_2nd, i2c wait for ACK timeout\n");
                return ret;
        }
        return ret;
 }
-static int rk2818_send_address(struct rk2818_i2c_data *i2c,
+static int rockchip_send_address(struct rockchip_i2c_data *i2c,
                                                struct i2c_msg *msg, int start)
 {
        unsigned long addr_1st;
@@ -348,7 +352,7 @@ static int rk2818_send_address(struct rk2818_i2c_data *i2c,
        
        if (start)
        {
-               if((ret = rk2818_wait_while_busy(i2c)) != 0)
+               if((ret = rockchip_wait_while_busy(i2c)) != 0)
                {
                        dev_err(i2c->dev, "i2c is busy, when send address\n");
                        return ret;
@@ -358,17 +362,17 @@ static int rk2818_send_address(struct rk2818_i2c_data *i2c,
        else
                writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
 
-       if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+       if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
        {
                dev_err(i2c->dev, "after sent addr_1st, i2c wait for ACK timeout\n");
                return ret;
        }
        if(start && (msg->flags & I2C_M_TEN))
-               ret = rk2818_send_2nd_addr(i2c, msg, start);
+               ret = rockchip_send_2nd_addr(i2c, msg, start);
        return ret;
 }
 
-static int rk2818_i2c_send_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
+static int rockchip_i2c_send_msg(struct rockchip_i2c_data *i2c, struct i2c_msg *msg)
 {
        int i, ret = 0;
        unsigned long conr = readl(i2c->regs + I2C_CONR);
@@ -387,12 +391,12 @@ static int rk2818_i2c_send_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
                */
                writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
 
-               if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+               if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
                        return ret;
        }
        return ret;
 }
-static int rk2818_i2c_recv_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
+static int rockchip_i2c_recv_msg(struct rockchip_i2c_data *i2c, struct i2c_msg *msg)
 {
        int i, ret = 0;
        unsigned long conr = readl(i2c->regs + I2C_CONR);
@@ -404,7 +408,7 @@ static int rk2818_i2c_recv_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
        for(i = 0; i < msg->len; i++)
        {
                writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
-               if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK)) != 0)
+               if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK)) != 0)
                        return ret;
                conr = readl(i2c->regs + I2C_CONR);
                conr &= I2C_CONR_ACK;
@@ -414,10 +418,10 @@ static int rk2818_i2c_recv_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
        }
        return ret;
 }
-static int rk2818_xfer_msg(struct i2c_adapter *adap, 
+static int rockchip_xfer_msg(struct i2c_adapter *adap, 
                                                 struct i2c_msg *msg, int start, int stop)
 {
-       struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
+       struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)adap->algo_data;
        unsigned long conr = readl(i2c->regs + I2C_CONR);
        int ret = 0;
        
@@ -432,24 +436,24 @@ static int rk2818_xfer_msg(struct i2c_adapter *adap,
                goto exit;
        }
 
-       if((ret = rk2818_send_address(i2c, msg, start))!= 0)
+       if((ret = rockchip_send_address(i2c, msg, start))!= 0)
        {
-               dev_err(i2c->dev, "<error>rk2818_send_address timeout\n");
+               dev_err(i2c->dev, "<error>rockchip_send_address timeout\n");
                goto exit;
        }
        if(msg->flags & I2C_M_RD)
        {       
-               if((ret = rk2818_i2c_recv_msg(i2c, msg)) != 0)
+               if((ret = rockchip_i2c_recv_msg(i2c, msg)) != 0)
                {
-                       dev_err(i2c->dev, "<error>rk2818_i2c_recv_msg timeout\n");
+                       dev_err(i2c->dev, "<error>rockchip_i2c_recv_msg timeout\n");
                        goto exit;
                }
        }
        else
        {
-               if((ret = rk2818_i2c_send_msg(i2c, msg)) != 0)
+               if((ret = rockchip_i2c_send_msg(i2c, msg)) != 0)
                {
-                       dev_err(i2c->dev, "<error>rk2818_i2c_send_msg timeout\n");
+                       dev_err(i2c->dev, "<error>rockchip_i2c_send_msg timeout\n");
                        goto exit;
                }
        }
@@ -460,9 +464,9 @@ exit:
                conr = readl(i2c->regs + I2C_CONR);
                conr |= I2C_CONR_NAK;
                writel(conr, i2c->regs + I2C_CONR);
-               if((ret = rk2818_i2c_stop(i2c)) != 0)
+               if((ret = rockchip_i2c_stop(i2c)) != 0)
                {
-                       dev_err(i2c->dev, "<error>rk2818_i2c_stop timeout\n");
+                       dev_err(i2c->dev, "<error>rockchip_i2c_stop timeout\n");
                }
 
                //not I2C code,add by sxj,used for extend gpio intrrupt,set SCL and SDA pin.
@@ -480,12 +484,12 @@ exit:
 
 }
 
-static int rk2818_i2c_xfer(struct i2c_adapter *adap,
+static int rockchip_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
 {
        int ret = -1;
        int i;
-       struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
+       struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)adap->algo_data;
        unsigned long conr = readl(i2c->regs + I2C_CONR);
        /*
        if(i2c->suspended ==1)
@@ -499,7 +503,7 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
        conr |= I2C_CONR_MPORT_ENABLE;
        writel(conr, i2c->regs + I2C_CONR);
        
-       rk2818_i2c_init_hw(i2c);
+       rockchip_i2c_init_hw(i2c);
        
        conr = readl(i2c->regs + I2C_CONR);
        conr &= I2C_CONR_ACK;
@@ -507,11 +511,11 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
 
        for (i = 0; i < num; i++) 
        {
-               ret = rk2818_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
+               ret = rockchip_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
                if (ret != 0)
                {
                        num = ret;
-                       dev_err(i2c->dev, "rk2818_xfer_msg error, ret = %d\n", ret);
+                       dev_err(i2c->dev, "rockchip_xfer_msg error, ret = %d\n", ret);
                        break;
                }
        }
@@ -521,19 +525,19 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
        return num;
 }
 
-static u32 rk2818_i2c_func(struct i2c_adapter *adap)
+static u32 rockchip_i2c_func(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
 }
 
-static const struct i2c_algorithm rk2818_i2c_algorithm = {
-       .master_xfer            = rk2818_i2c_xfer,
-       .functionality          = rk2818_i2c_func,
+static const struct i2c_algorithm rockchip_i2c_algorithm = {
+       .master_xfer            = rockchip_i2c_xfer,
+       .functionality          = rockchip_i2c_func,
 };
 
 int i2c_suspended(struct i2c_adapter *adap)
 {
-       struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
+       struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)adap->algo_data;
        if(adap->nr > 1)
                return 1;
        if(i2c == NULL)
@@ -542,7 +546,7 @@ int i2c_suspended(struct i2c_adapter *adap)
 }
 EXPORT_SYMBOL(i2c_suspended);
        
-static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
+static void rockchip_i2c_init_hw(struct rockchip_i2c_data *i2c)
 {
        unsigned long lcmr = 0x00000000;
 
@@ -552,9 +556,9 @@ static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
        
        writel(lcmr, i2c->regs + I2C_LCMR);
 
-       rk2818_i2c_disable_irqs(i2c);
+       rockchip_i2c_disable_irqs(i2c);
 
-       rk2818_i2c_clockrate(i2c); 
+       rockchip_i2c_clockrate(i2c); 
 
        opr = readl(i2c->regs + I2C_OPR);
        opr |= I2C_OPR_CORE_ENABLE;
@@ -565,12 +569,12 @@ static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
 
 #ifdef CONFIG_CPU_FREQ
 
-#define freq_to_i2c(_n) container_of(_n, struct rk2818_i2c_data, freq_transition)
+#define freq_to_i2c(_n) container_of(_n, struct rockchip_i2c_data, freq_transition)
 
-static int rk2818_i2c_cpufreq_transition(struct notifier_block *nb,
+static int rockchip_i2c_cpufreq_transition(struct notifier_block *nb,
                                          unsigned long val, void *data)
 {
-       struct rk2818_i2c_data *i2c = freq_to_i2c(nb);
+       struct rockchip_i2c_data *i2c = freq_to_i2c(nb);
        unsigned long flags;
        int delta_f;
        delta_f = clk_get_rate(i2c->clk) - i2c->i2c_rate;
@@ -579,41 +583,45 @@ static int rk2818_i2c_cpufreq_transition(struct notifier_block *nb,
            (val == CPUFREQ_PRECHANGE && delta_f > 0)) 
        {
                spin_lock_irqsave(&i2c->cmd_lock, flags);
-               rk2818_i2c_clockrate(i2c);
+               rockchip_i2c_clockrate(i2c);
                spin_unlock_irqrestore(&i2c->cmd_lock, flags);
        }
        return 0;
 }
 
-static inline int rk2818_i2c_register_cpufreq(struct rk2818_i2c_data *i2c)
+static inline int rockchip_i2c_register_cpufreq(struct rockchip_i2c_data *i2c)
 {
-       i2c->freq_transition.notifier_call = rk2818_i2c_cpufreq_transition;
+       i2c->freq_transition.notifier_call = rockchip_i2c_cpufreq_transition;
 
        return cpufreq_register_notifier(&i2c->freq_transition,
                                         CPUFREQ_TRANSITION_NOTIFIER);
 }
 
-static inline void rk2818_i2c_unregister_cpufreq(struct rk2818_i2c_data *i2c)
+static inline void rockchip_i2c_unregister_cpufreq(struct rockchip_i2c_data *i2c)
 {
        cpufreq_unregister_notifier(&i2c->freq_transition,
                                    CPUFREQ_TRANSITION_NOTIFIER);
 }
 
 #else
-static inline int rk2818_i2c_register_cpufreq(struct rk2818_i2c_data *i2c)
+static inline int rockchip_i2c_register_cpufreq(struct rockchip_i2c_data *i2c)
 {
        return 0;
 }
 
-static inline void rk2818_i2c_unregister_cpufreq(struct rk2818_i2c_data *i2c)
+static inline void rockchip_i2c_unregister_cpufreq(struct rockchip_i2c_data *i2c)
 {
        return;
 }
 #endif
-static int rk2818_i2c_probe(struct platform_device *pdev)
+static int rockchip_i2c_probe(struct platform_device *pdev)
 {
-       struct rk2818_i2c_data *i2c;
-       struct rk2818_i2c_platform_data *pdata;
+       struct rockchip_i2c_data *i2c;
+#ifdef CONFIG_ARCH_RK2818
+       struct rk2818_i2c_platform_data *pdata = NULL;
+#else
+       struct rk29_i2c_platform_data *pdata = NULL;
+#endif
        struct resource *res;
        int ret;
 
@@ -623,7 +631,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "<error>no platform data\n");
                return -EINVAL;
        }
-       i2c = kzalloc(sizeof(struct rk2818_i2c_data), GFP_KERNEL);
+       i2c = kzalloc(sizeof(struct rockchip_i2c_data), GFP_KERNEL);
        if (!i2c) 
        {
                dev_err(&pdev->dev, "<error>no memory for state\n");
@@ -634,7 +642,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
 
        strlcpy(i2c->adap.name, DRV_NAME, sizeof(i2c->adap.name));
        i2c->adap.owner         = THIS_MODULE;
-       i2c->adap.algo          = &rk2818_i2c_algorithm;
+       i2c->adap.algo          = &rockchip_i2c_algorithm;
        i2c->adap.class         = I2C_CLASS_HWMON;
        spin_lock_init(&i2c->cmd_lock);
 
@@ -678,7 +686,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
        if(pdata->io_init)
                pdata->io_init();
         
-       rk2818_i2c_init_hw(i2c);
+       rockchip_i2c_init_hw(i2c);
 
        i2c->irq = ret = platform_get_irq(pdev, 0);
        if (ret <= 0) {
@@ -687,7 +695,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
        }
        if(i2c->mode == I2C_MODE_IRQ)
        {
-               ret = request_irq(i2c->irq, rk2818_i2c_irq, IRQF_DISABLED,
+               ret = request_irq(i2c->irq, rockchip_i2c_irq, IRQF_DISABLED,
                                dev_name(&pdev->dev), i2c);
 
                if (ret != 0) {
@@ -695,7 +703,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
                        goto err_iomap;
                }
        }
-       ret = rk2818_i2c_register_cpufreq(i2c);
+       ret = rockchip_i2c_register_cpufreq(i2c);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
                goto err_irq;
@@ -714,7 +722,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
        return 0;
 
  err_cpufreq:
-       rk2818_i2c_unregister_cpufreq(i2c);
+       rockchip_i2c_unregister_cpufreq(i2c);
 
  err_irq:
        if(i2c->mode == I2C_MODE_IRQ)
@@ -737,11 +745,11 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
 }
 
 
-static int rk2818_i2c_remove(struct platform_device *pdev)
+static int rockchip_i2c_remove(struct platform_device *pdev)
 {
-       struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
+       struct rockchip_i2c_data *i2c = platform_get_drvdata(pdev);
 
-       rk2818_i2c_unregister_cpufreq(i2c);
+       rockchip_i2c_unregister_cpufreq(i2c);
 
        i2c_del_adapter(&i2c->adap);
         if(i2c->mode == I2C_MODE_IRQ)
@@ -761,51 +769,51 @@ static int rk2818_i2c_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 
-static int rk2818_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+static int rockchip_i2c_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
+       struct rockchip_i2c_data *i2c = platform_get_drvdata(pdev);
 
        i2c->suspended = 1;
        return 0;
 }
-static int rk2818_i2c_resume(struct platform_device *pdev)
+static int rockchip_i2c_resume(struct platform_device *pdev)
 {
-       struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
+       struct rockchip_i2c_data *i2c = platform_get_drvdata(pdev);
 
        i2c->suspended = 0;
-       rk2818_i2c_init_hw(i2c);
+       rockchip_i2c_init_hw(i2c);
 
        return 0;
 }
 #else
-#define rk2818_i2c_suspend             NULL
-#define rk2818_i2c_resume              NULL
+#define rockchip_i2c_suspend           NULL
+#define rockchip_i2c_resume            NULL
 #endif
 
 
-static struct platform_driver rk2818_i2c_driver = {
-       .probe          = rk2818_i2c_probe,
-       .remove         = rk2818_i2c_remove,
-       .suspend        = rk2818_i2c_suspend,
-       .resume         = rk2818_i2c_resume,
+static struct platform_driver rockchip_i2c_driver = {
+       .probe          = rockchip_i2c_probe,
+       .remove         = rockchip_i2c_remove,
+       .suspend        = rockchip_i2c_suspend,
+       .resume         = rockchip_i2c_resume,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
        },
 };
 
-static int __init rk2818_i2c_adap_init(void)
+static int __init rockchip_i2c_adap_init(void)
 {
-       return platform_driver_register(&rk2818_i2c_driver);
+       return platform_driver_register(&rockchip_i2c_driver);
 }
 
-static void __exit rk2818_i2c_adap_exit(void)
+static void __exit rockchip_i2c_adap_exit(void)
 {
-       platform_driver_unregister(&rk2818_i2c_driver);
+       platform_driver_unregister(&rockchip_i2c_driver);
 }
 
-subsys_initcall(rk2818_i2c_adap_init);
-module_exit(rk2818_i2c_adap_exit);
+subsys_initcall(rockchip_i2c_adap_init);
+module_exit(rockchip_i2c_adap_exit);
 
 MODULE_DESCRIPTION("Driver for RK2818 I2C Bus");
 MODULE_AUTHOR("kfx, kfx@rock-chips.com");
diff --git a/drivers/i2c/busses/i2c-rk29.c b/drivers/i2c/busses/i2c-rk29.c
new file mode 100755 (executable)
index 0000000..b5b8227
--- /dev/null
@@ -0,0 +1,821 @@
+/* drivers/i2c/busses/i2c_rk29.c
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <mach/board.h>
+#include <asm/io.h>
+
+#include "i2c-rk29.h"
+#define DRV_NAME       "rk29_i2c"
+
+#define RK2818_I2C_TIMEOUT             (msecs_to_jiffies(500))
+#define RK2818_DELAY_TIME              2
+
+#if 1
+#define i2c_dbg(dev, format, arg...)           \
+       dev_printk(KERN_INFO , dev , format , ## arg)
+#else
+#define i2c_dbg(dev, format, arg...)   
+#endif
+
+enum rk29_error {
+       RK2818_ERROR_NONE = 0,
+       RK2818_ERROR_ARBITR_LOSE,
+       RK2818_ERROR_UNKNOWN
+};
+
+enum rk29_event {
+       RK2818_EVENT_NONE = 0,
+       /* master has received ack(MTX mode) 
+          means that data has been sent to slave.
+        */
+       RK2818_EVENT_MTX_RCVD_ACK,      
+       /* master needs to send ack to slave(MRX mode) 
+          means that data has been received from slave.
+        */
+       RK2818_EVENT_MRX_NEED_ACK,       
+       RK2818_EVENT_MAX
+};
+
+struct rk29_i2c_data {
+       struct device                   *dev;  
+       struct i2c_adapter              adap;
+       void __iomem                    *regs;
+       struct resource                 *ioarea;
+
+       unsigned int                    suspended:1;
+       unsigned long                   scl_rate;
+       unsigned long                   i2c_rate;
+       struct clk                              *clk;
+
+       unsigned int                    mode;
+
+       unsigned int                    irq;
+
+       spinlock_t                              cmd_lock;
+       struct completion               cmd_complete;
+       enum rk29_event         cmd_event;
+       enum rk29_error         cmd_err;
+
+       unsigned int                    msg_idx;
+       unsigned int                    msg_num;
+#ifdef CONFIG_CPU_FREQ
+               struct notifier_block   freq_transition;
+#endif 
+};
+
+static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c);
+
+static inline void rk29_i2c_disable_irqs(struct rk29_i2c_data *i2c)
+{
+       unsigned long tmp;
+
+       tmp = readl(i2c->regs + I2C_IER);
+       writel(tmp & IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
+}
+static inline void rk29_i2c_enable_irqs(struct rk29_i2c_data *i2c)
+{
+       unsigned long tmp;
+
+       tmp = readl(i2c->regs + I2C_IER);
+       writel(tmp | IRQ_MST_ENABLE, i2c->regs + I2C_IER);
+}
+
+/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
+static void rk29_i2c_calcdivisor(unsigned long pclk, 
+                                                               unsigned long scl_rate, 
+                                                               unsigned long *real_rate,
+                                                               unsigned int *rem, unsigned int *exp)
+{
+       unsigned int calc_rem = 0;
+       unsigned int calc_exp = 0;
+
+       for(calc_exp = 0; calc_exp < I2CCDVR_EXP_MAX; calc_exp++)
+       {
+               calc_rem = pclk / (5 * scl_rate * (1 <<(calc_exp +1)));
+               if(calc_rem < I2CCDVR_REM_MAX)
+                       break;
+       }
+       if(calc_rem >= I2CCDVR_REM_MAX || calc_exp >= I2CCDVR_EXP_MAX)
+       {
+               calc_rem = I2CCDVR_REM_MAX - 1;
+               calc_exp = I2CCDVR_EXP_MAX - 1;
+       }
+       *rem = calc_rem;
+       *exp = calc_exp;
+       *real_rate = pclk/(5 * (calc_rem + 1) * (1 <<(calc_exp +1)));
+       return;
+}
+/* set i2c bus scl rate */
+static void  rk29_i2c_clockrate(struct rk29_i2c_data *i2c)
+{
+#ifdef CONFIG_ARCH_RK2818
+       struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data;
+#else
+       struct rk29_i2c_platform_data *pdata = i2c->dev->platform_data;
+#endif
+       unsigned int rem = 0, exp = 0;
+       unsigned long scl_rate, real_rate = 0, tmp;
+
+       i2c->i2c_rate = clk_get_rate(i2c->clk);
+
+       scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000);
+
+       rk29_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
+
+       tmp = readl(i2c->regs + I2C_OPR);
+       tmp |= exp;
+       tmp |= rem<<I2CCDVR_EXP_BITS;   
+       writel(tmp, i2c->regs + I2C_OPR);
+       if(real_rate > 400000)
+               dev_warn(i2c->dev, "i2c_rate[%luKhz], scl_rate[%luKhz], real_rate[%luKhz] > 400Khz\n", 
+                               i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
+       else
+               i2c_dbg(i2c->dev, "i2c_rate[%luKhz], scl_rate[%luKhz], real_rate[%luKhz]\n", 
+                               i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
+       return;
+}
+static int rk29_event_occurred(struct rk29_i2c_data *i2c)
+{
+       unsigned long isr;
+
+       isr = readl(i2c->regs + I2C_ISR);
+       i2c_dbg(i2c->dev,"event occurred, isr = %lx\n", isr);
+       if(isr & I2C_ISR_ARBITR_LOSE)
+       {
+               isr &= ~I2C_ISR_ARBITR_LOSE;
+               writel(isr, i2c->regs + I2C_ISR);
+               i2c->cmd_err = RK2818_ERROR_ARBITR_LOSE;
+               dev_err(i2c->dev, "<error>arbitration loss\n");
+               return 1;
+       }
+
+       switch(i2c->cmd_event)
+       {
+               case RK2818_EVENT_MTX_RCVD_ACK:
+                       if(isr & I2C_ISR_MTX_RCVD_ACK)
+                       {
+                               isr &= ~I2C_ISR_MTX_RCVD_ACK;
+                               writel(isr, i2c->regs + I2C_ISR);
+                               return 1;
+                       }
+               break;
+               case RK2818_EVENT_MRX_NEED_ACK:
+                       if(isr & I2C_ISR_MRX_NEED_ACK)
+                       {
+                               isr &= ~I2C_ISR_MRX_NEED_ACK;
+                               writel(isr, i2c->regs + I2C_ISR);
+                               return 1;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       i2c->cmd_err = RK2818_ERROR_UNKNOWN;
+       return 0;
+}
+
+static irqreturn_t rk29_i2c_irq(int irq, void *data)
+{
+       struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)data;
+       int res;
+       
+       rk29_i2c_disable_irqs(i2c);
+       spin_lock(&i2c->cmd_lock);
+       res = rk29_event_occurred(i2c);
+       if(res)
+       //if(res || i2c->cmd_err != RK2818_ERROR_NONE)
+               complete(&i2c->cmd_complete);
+       spin_unlock(&i2c->cmd_lock);
+       return IRQ_HANDLED;
+}
+static int wait_for_completion_poll_timeout(struct rk29_i2c_data *i2c, unsigned long timeout)
+{
+       unsigned int time = RK2818_DELAY_TIME;
+       int res;
+
+       while(!time_after(jiffies, jiffies + timeout))
+       {
+               res = rk29_event_occurred(i2c);
+               if(res)
+               //if(res || (i2c->cmd_err != RK2818_ERROR_NONE && i2c->cmd_err != RK2818_ERROR_UNKNOWN))
+                       return 1;
+               udelay(time);
+               time *= 2;
+       }
+       return 0;
+
+}
+static int rk29_wait_event(struct rk29_i2c_data *i2c,
+                                       enum rk29_event mr_event)
+{
+       int ret = 0;
+       unsigned long flags;
+       if(i2c->mode == I2C_MODE_IRQ)
+       {
+               if(unlikely(irqs_disabled()))
+               {
+                       dev_err(i2c->dev, "irqs are disabled on this system!\n");
+                       return -EIO;
+               }
+       }
+       spin_lock_irqsave(&i2c->cmd_lock,flags);
+       i2c->cmd_err = RK2818_ERROR_NONE;
+       i2c->cmd_event = mr_event;
+
+       init_completion(&i2c->cmd_complete);
+
+       spin_unlock_irqrestore(&i2c->cmd_lock,flags);
+
+       rk29_i2c_enable_irqs(i2c);
+       if(i2c->mode == I2C_MODE_IRQ)
+               ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
+                                                               RK2818_I2C_TIMEOUT);
+       else
+               ret = wait_for_completion_poll_timeout(i2c, RK2818_I2C_TIMEOUT);
+       
+       if(ret < 0)
+       {
+               dev_err(i2c->dev, "i2c wait for event %04x, retrun %d \n", mr_event, ret);
+               return ret;
+       }
+       if(ret == 0)
+       {
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static int rk29_wait_while_busy(struct rk29_i2c_data *i2c)
+{
+       unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
+       unsigned long lsr;
+       unsigned int time = RK2818_DELAY_TIME;
+
+       while(!time_after(jiffies, timeout))
+       {
+               lsr = readl(i2c->regs + I2C_LSR);
+               if(!(lsr & I2C_LSR_BUSY))
+                       return 0;
+               udelay(time);
+               time *= 2;
+       }
+       return -ETIMEDOUT;
+}
+static int rk29_i2c_stop(struct rk29_i2c_data *i2c)
+{
+       unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
+       unsigned int time = RK2818_DELAY_TIME;
+
+       writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+       while(!time_after(jiffies, timeout))
+       {
+               if(!(readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP))
+               {
+                       i2c_dbg(i2c->dev, "i2c stop successfully\n");
+                       return 0;
+               }
+               udelay(time);
+               time *= 2;
+       }
+       return -ETIMEDOUT;
+    
+}
+static int rk29_send_2nd_addr(struct rk29_i2c_data *i2c,
+                                               struct i2c_msg *msg, int start)
+{
+       int ret = 0;
+       unsigned long addr_2nd = msg->addr & 0xff;
+       unsigned long conr = readl(i2c->regs + I2C_CONR);
+
+       conr |= I2C_CONR_MTX_MODE;
+       //conr &= I2C_CONR_ACK;
+       writel(conr, i2c->regs + I2C_CONR);
+       
+       i2c_dbg(i2c->dev, "i2c send addr_2nd: %lx\n", addr_2nd);        
+       writel(addr_2nd, i2c->regs + I2C_MTXR);
+       writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+       if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+       {
+               dev_err(i2c->dev, "after sent addr_2nd, i2c wait for ACK timeout\n");
+               return ret;
+       }
+       return ret;
+}
+static int rk29_send_address(struct rk29_i2c_data *i2c,
+                                               struct i2c_msg *msg, int start)
+{
+       unsigned long addr_1st;
+       unsigned long conr = readl(i2c->regs + I2C_CONR);
+       int ret = 0;
+       
+       if(msg->flags & I2C_M_TEN)
+               addr_1st = (0xf0 | (((unsigned long) msg->addr & 0x300) >> 7)) & 0xff;
+       else
+               addr_1st = ((msg->addr << 1) & 0xff);
+       
+       if (msg->flags & I2C_M_RD) 
+               addr_1st |= 0x01;
+       else
+               addr_1st &= (~0x01);
+
+       conr |= I2C_CONR_MTX_MODE;
+       //conr &= I2C_CONR_ACK;
+       writel(conr, i2c->regs + I2C_CONR);
+       i2c_dbg(i2c->dev, "i2c send addr_1st: %lx\n", addr_1st);
+       
+       writel(addr_1st, i2c->regs + I2C_MTXR);
+       
+       if (start)
+       {
+               if((ret = rk29_wait_while_busy(i2c)) != 0)
+               {
+                       dev_err(i2c->dev, "i2c is busy, when send address\n");
+                       return ret;
+               }
+               writel(I2C_LCMR_START, i2c->regs + I2C_LCMR);
+       }
+       else
+               writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+
+       if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+       {
+               dev_err(i2c->dev, "after sent addr_1st, i2c wait for ACK timeout\n");
+               return ret;
+       }
+       if(start && (msg->flags & I2C_M_TEN))
+               ret = rk29_send_2nd_addr(i2c, msg, start);
+       return ret;
+}
+
+static int rk29_i2c_send_msg(struct rk29_i2c_data *i2c, struct i2c_msg *msg)
+{
+       int i, ret = 0;
+       unsigned long conr = readl(i2c->regs + I2C_CONR);
+       
+       conr = readl(i2c->regs + I2C_CONR);
+       conr |= I2C_CONR_MTX_MODE;
+       writel(conr, i2c->regs + I2C_CONR);
+       for(i = 0; i < msg->len; i++)
+       {
+               i2c_dbg(i2c->dev, "i2c send buf[%d]: %x\n", i, msg->buf[i]);
+               writel(msg->buf[i], i2c->regs + I2C_MTXR);
+               /*
+               conr = readl(i2c->regs + I2C_CONR);
+               conr &= I2C_CONR_ACK;
+               writel(conr, i2c->regs + I2C_CONR);
+               */
+               writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+
+               if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+                       return ret;
+       }
+       return ret;
+}
+static int rk29_i2c_recv_msg(struct rk29_i2c_data *i2c, struct i2c_msg *msg)
+{
+       int i, ret = 0;
+       unsigned long conr = readl(i2c->regs + I2C_CONR);
+
+       conr = readl(i2c->regs + I2C_CONR);
+       conr &= I2C_CONR_MRX_MODE;
+       writel(conr, i2c->regs + I2C_CONR);
+
+       for(i = 0; i < msg->len; i++)
+       {
+               writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+               if((ret = rk29_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK)) != 0)
+                       return ret;
+               conr = readl(i2c->regs + I2C_CONR);
+               conr &= I2C_CONR_ACK;
+               writel(conr, i2c->regs + I2C_CONR);
+               msg->buf[i] = (uint8_t)readl(i2c->regs + I2C_MRXR);
+               i2c_dbg(i2c->dev, "i2c recv >>>>>>>>>>>> buf[%d]: %x\n", i, msg->buf[i]);
+       }
+       return ret;
+}
+static int rk29_xfer_msg(struct i2c_adapter *adap, 
+                                                struct i2c_msg *msg, int start, int stop)
+{
+       struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
+       unsigned long conr = readl(i2c->regs + I2C_CONR);
+       int ret = 0;
+       
+       #if defined (CONFIG_IOEXTEND_TCA6424)
+       struct tca6424_platform_data  *pdata = adap->dev.platform_data;
+       #endif
+       
+       if(msg->len == 0)
+       {
+               ret = -EINVAL;
+               dev_err(i2c->dev, "<error>msg->len = %d\n", msg->len);
+               goto exit;
+       }
+
+       if((ret = rk29_send_address(i2c, msg, start))!= 0)
+       {
+               dev_err(i2c->dev, "<error>rk29_send_address timeout\n");
+               goto exit;
+       }
+       if(msg->flags & I2C_M_RD)
+       {       
+               if((ret = rk29_i2c_recv_msg(i2c, msg)) != 0)
+               {
+                       dev_err(i2c->dev, "<error>rk29_i2c_recv_msg timeout\n");
+                       goto exit;
+               }
+       }
+       else
+       {
+               if((ret = rk29_i2c_send_msg(i2c, msg)) != 0)
+               {
+                       dev_err(i2c->dev, "<error>rk29_i2c_send_msg timeout\n");
+                       goto exit;
+               }
+       }
+       
+exit:  
+       if(stop)
+       {
+               conr = readl(i2c->regs + I2C_CONR);
+               conr |= I2C_CONR_NAK;
+               writel(conr, i2c->regs + I2C_CONR);
+               if((ret = rk29_i2c_stop(i2c)) != 0)
+               {
+                       dev_err(i2c->dev, "<error>rk29_i2c_stop timeout\n");
+               }
+#if 0
+               //not I2C code,add by sxj,used for extend gpio intrrupt,set SCL and SDA pin.
+               if(msg->flags & I2C_M_RD)
+               {
+                       #if defined (CONFIG_IOEXTEND_TCA6424)
+                       if (pdata && pdata->reseti2cpin) {
+                               pdata->reseti2cpin();
+                       }
+                       #endif  
+               }
+\r#endif                        
+       }
+       return ret;
+
+}
+
+static int rk29_i2c_xfer(struct i2c_adapter *adap,
+                       struct i2c_msg *msgs, int num)
+{
+       int ret = -1;
+       int i;
+       struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
+       unsigned long conr = readl(i2c->regs + I2C_CONR);
+       /*
+       if(i2c->suspended ==1)
+               return -EIO;
+       */
+       if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate > 0)
+               i2c->scl_rate = msgs[0].scl_rate;
+       else
+               i2c->scl_rate = 400000;
+       
+       conr |= I2C_CONR_MPORT_ENABLE;
+       writel(conr, i2c->regs + I2C_CONR);
+       
+       rk29_i2c_init_hw(i2c);
+       
+       conr = readl(i2c->regs + I2C_CONR);
+       conr &= I2C_CONR_ACK;
+       writel(conr, i2c->regs + I2C_CONR);
+
+       for (i = 0; i < num; i++) 
+       {
+               ret = rk29_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
+               if (ret != 0)
+               {
+                       num = ret;
+                       dev_err(i2c->dev, "rk29_xfer_msg error, ret = %d\n", ret);
+                       break;
+               }
+       }
+       conr = readl(i2c->regs + I2C_CONR);
+       conr &= I2C_CONR_MPORT_DISABLE;
+       writel(conr, i2c->regs + I2C_CONR);
+       return num;
+}
+
+static u32 rk29_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm rk29_i2c_algorithm = {
+       .master_xfer            = rk29_i2c_xfer,
+       .functionality          = rk29_i2c_func,
+};
+
+int i2c_suspended(struct i2c_adapter *adap)
+{
+       struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
+       if(adap->nr > 1)
+               return 1;
+       if(i2c == NULL)
+               return 1;
+       return i2c->suspended;
+}
+EXPORT_SYMBOL(i2c_suspended);
+       
+static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c)
+{
+       unsigned long lcmr = 0x00000000;
+
+       unsigned long opr = readl(i2c->regs + I2C_OPR);
+       opr |= I2C_OPR_RESET_STATUS;
+       writel(opr, i2c->regs + I2C_OPR);
+       
+       writel(lcmr, i2c->regs + I2C_LCMR);
+
+       rk29_i2c_disable_irqs(i2c);
+
+       rk29_i2c_clockrate(i2c); 
+
+       opr = readl(i2c->regs + I2C_OPR);
+       opr |= I2C_OPR_CORE_ENABLE;
+       writel(opr, i2c->regs + I2C_OPR);
+
+       return;
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+#define freq_to_i2c(_n) container_of(_n, struct rk29_i2c_data, freq_transition)
+
+static int rk29_i2c_cpufreq_transition(struct notifier_block *nb,
+                                         unsigned long val, void *data)
+{
+       struct rk29_i2c_data *i2c = freq_to_i2c(nb);
+       unsigned long flags;
+       int delta_f;
+       delta_f = clk_get_rate(i2c->clk) - i2c->i2c_rate;
+
+       if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
+           (val == CPUFREQ_PRECHANGE && delta_f > 0)) 
+       {
+               spin_lock_irqsave(&i2c->cmd_lock, flags);
+               rk29_i2c_clockrate(i2c);
+               spin_unlock_irqrestore(&i2c->cmd_lock, flags);
+       }
+       return 0;
+}
+
+static inline int rk29_i2c_register_cpufreq(struct rk29_i2c_data *i2c)
+{
+       i2c->freq_transition.notifier_call = rk29_i2c_cpufreq_transition;
+
+       return cpufreq_register_notifier(&i2c->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void rk29_i2c_unregister_cpufreq(struct rk29_i2c_data *i2c)
+{
+       cpufreq_unregister_notifier(&i2c->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int rk29_i2c_register_cpufreq(struct rk29_i2c_data *i2c)
+{
+       return 0;
+}
+
+static inline void rk29_i2c_unregister_cpufreq(struct rk29_i2c_data *i2c)
+{
+       return;
+}
+#endif
+
+static int rk29_i2c_probe(struct platform_device *pdev)
+{
+       struct rk29_i2c_data *i2c;
+#ifdef CONFIG_ARCH_RK2818
+       struct rk2818_i2c_platform_data *pdata = NULL;
+#else
+       struct rk29_i2c_platform_data *pdata = NULL;
+#endif
+       struct resource *res;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) 
+       {
+               dev_err(&pdev->dev, "<error>no platform data\n");
+               return -EINVAL;
+       }
+       i2c = kzalloc(sizeof(struct rk29_i2c_data), GFP_KERNEL);
+       if (!i2c) 
+       {
+               dev_err(&pdev->dev, "<error>no memory for state\n");
+               return -ENOMEM;
+       }
+       i2c->mode = pdata->mode;
+       i2c->scl_rate = (pdata->scl_rate) ? pdata->scl_rate : 100000;
+
+       strlcpy(i2c->adap.name, DRV_NAME, sizeof(i2c->adap.name));
+       i2c->adap.owner         = THIS_MODULE;
+       i2c->adap.algo          = &rk29_i2c_algorithm;
+       i2c->adap.class         = I2C_CLASS_HWMON;
+       spin_lock_init(&i2c->cmd_lock);
+
+       i2c->dev = &pdev->dev;
+       
+       i2c->clk = clk_get(&pdev->dev, "i2c");
+       if (IS_ERR(i2c->clk)) {
+               dev_err(&pdev->dev, "<error>cannot get clock\n");
+               ret = -ENOENT;
+               goto err_noclk;
+       }
+
+       clk_enable(i2c->clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "<error>cannot find IO resource\n");
+               ret = -ENOENT;
+               goto err_clk;
+       }
+
+       i2c->ioarea = request_mem_region(res->start, res->end - res->start + 1,
+                                        pdev->name);
+
+       if (i2c->ioarea == NULL) {
+               dev_err(&pdev->dev, "<error>cannot request IO\n");
+               ret = -ENXIO;
+               goto err_clk;
+       }
+
+       i2c->regs = ioremap(res->start, res->end - res->start + 1);
+
+       if (i2c->regs == NULL) {
+               dev_err(&pdev->dev, "<error>annot map IO\n");
+               ret = -ENXIO;
+               goto err_ioarea;
+       }
+       i2c->adap.algo_data = i2c;
+       i2c->adap.dev.parent = &pdev->dev;
+
+       if(pdata->io_init)
+               pdata->io_init();
+        
+       rk29_i2c_init_hw(i2c);
+
+       i2c->irq = ret = platform_get_irq(pdev, 0);
+       if (ret <= 0) {
+               dev_err(&pdev->dev, "cannot find IRQ\n");
+               goto err_iomap;
+       }
+       if(i2c->mode == I2C_MODE_IRQ)
+       {
+               ret = request_irq(i2c->irq, rk29_i2c_irq, IRQF_DISABLED,
+                               dev_name(&pdev->dev), i2c);
+
+               if (ret != 0) {
+                       dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+                       goto err_iomap;
+               }
+       }
+       ret = rk29_i2c_register_cpufreq(i2c);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+               goto err_irq;
+       }
+
+       i2c->adap.nr = pdata->bus_num;
+       ret = i2c_add_numbered_adapter(&i2c->adap);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+               goto err_cpufreq;
+       }
+
+       platform_set_drvdata(pdev, i2c);
+
+       dev_info(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev));
+       return 0;
+
+ err_cpufreq:
+       rk29_i2c_unregister_cpufreq(i2c);
+
+ err_irq:
+       if(i2c->mode == I2C_MODE_IRQ)
+               free_irq(i2c->irq, i2c);
+
+ err_iomap:
+       iounmap(i2c->regs);
+
+ err_ioarea:
+       release_resource(i2c->ioarea);
+       kfree(i2c->ioarea);
+
+ err_clk:
+       clk_disable(i2c->clk);
+       clk_put(i2c->clk);
+
+ err_noclk:
+       kfree(i2c);
+       return ret;
+}
+
+
+static int rk29_i2c_remove(struct platform_device *pdev)
+{
+       struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
+
+       rk29_i2c_unregister_cpufreq(i2c);
+
+       i2c_del_adapter(&i2c->adap);
+        if(i2c->mode == I2C_MODE_IRQ)
+               free_irq(i2c->irq, i2c);
+
+       clk_disable(i2c->clk);
+       clk_put(i2c->clk);
+
+       iounmap(i2c->regs);
+
+       release_resource(i2c->ioarea);
+       kfree(i2c->ioarea);
+       kfree(i2c);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int rk29_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
+
+       i2c->suspended = 1;
+       return 0;
+}
+static int rk29_i2c_resume(struct platform_device *pdev)
+{
+       struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
+
+       i2c->suspended = 0;
+       rk29_i2c_init_hw(i2c);
+
+       return 0;
+}
+#else
+#define rk29_i2c_suspend               NULL
+#define rk29_i2c_resume                NULL
+#endif
+
+
+static struct platform_driver rk29_i2c_driver = {
+       .probe          = rk29_i2c_probe,
+       .remove         = rk29_i2c_remove,
+       .suspend        = rk29_i2c_suspend,
+       .resume         = rk29_i2c_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = DRV_NAME,
+       },
+};
+
+static int __init rk29_i2c_adap_init(void)
+{
+       return platform_driver_register(&rk29_i2c_driver);
+}
+
+static void __exit rk29_i2c_adap_exit(void)
+{
+       platform_driver_unregister(&rk29_i2c_driver);
+}
+
+subsys_initcall(rk29_i2c_adap_init);
+module_exit(rk29_i2c_adap_exit);
+
+MODULE_DESCRIPTION("Driver for RK2818 I2C Bus");
+MODULE_AUTHOR("kfx, kfx@rock-chips.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-rk29.h b/drivers/i2c/busses/i2c-rk29.h
new file mode 100755 (executable)
index 0000000..97bf03c
--- /dev/null
@@ -0,0 +1,73 @@
+/* drivers/i2c/busses/i2c_rk2818.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __RK2818_I2C_H
+#define __RK2818_I2C_H
+
+/* master transmit */
+#define I2C_MTXR                (0x0000)
+/* master receive */
+#define I2C_MRXR                (0x0004)
+/* slave address */
+#define I2C_SADDR               (0x0010)
+/* interrupt enable control */
+#define I2C_IER                 (0x0014)
+#define I2C_IER_ARBITR_LOSE     (1<<7)
+#define I2C_IER_MRX_NEED_ACK    (1<<1)
+#define I2C_IER_MTX_RCVD_ACK    (1<<0)
+
+#define IRQ_MST_ENABLE         (I2C_IER_ARBITR_LOSE | \
+                                        I2C_IER_MRX_NEED_ACK | \
+                                        I2C_IER_MTX_RCVD_ACK)
+#define IRQ_ALL_DISABLE         (0x00)
+
+/* interrupt status, write 0 to clear */
+#define I2C_ISR                 (0x0018)
+#define I2C_ISR_ARBITR_LOSE     (1<<7)
+#define I2C_ISR_MRX_NEED_ACK    (1<<1)
+#define I2C_ISR_MTX_RCVD_ACK    (1<<0)
+
+/* stop/start/resume command, write 1 to set */
+#define I2C_LCMR                (0x001c)
+#define I2C_LCMR_RESUME         (1<<2)
+#define I2C_LCMR_STOP           (1<<1)
+#define I2C_LCMR_START          (1<<0)
+
+/* i2c core status */
+#define I2C_LSR                 (0x0020)
+#define I2C_LSR_RCV_NAK         (1<<1)
+#define I2C_LSR_RCV_ACK         (~(1<<1))
+#define I2C_LSR_BUSY            (1<<0)
+
+/* i2c config */
+#define I2C_CONR                (0x0024)
+#define I2C_CONR_NAK               (1<<4)
+#define I2C_CONR_ACK            (~(1<<4))
+#define I2C_CONR_MTX_MODE       (1<<3)
+#define I2C_CONR_MRX_MODE       (~(1<<3))
+#define I2C_CONR_MPORT_ENABLE   (1<<2)
+#define I2C_CONR_MPORT_DISABLE  (~(1<<2))
+
+/* i2c core config */
+#define I2C_OPR                 (0x0028)
+#define I2C_OPR_RESET_STATUS    (1<<7)
+#define I2C_OPR_CORE_ENABLE     (1<<6)
+
+#define I2CCDVR_REM_BITS        (0x03)
+#define I2CCDVR_REM_MAX         (1<<(I2CCDVR_REM_BITS))
+#define I2CCDVR_EXP_BITS        (0x03)
+#define I2CCDVR_EXP_MAX         (1<<(I2CCDVR_EXP_BITS))
+
+#endif
index 5a3264f4abffe632f28e00b5a082d0a7c4f21a1c..fac7cedadc736e02b5616b371a015a2dd9b64103 100755 (executable)
@@ -1091,7 +1091,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                                (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
                }
 #endif
-#ifdef CONFIG_I2C_RK2818
+#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29)
                if (!(i2c_suspended(adap)) && (in_atomic() || irqs_disabled())) {
 #else
                if (in_atomic() || irqs_disabled()) {
@@ -1123,7 +1123,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        }
 }
 EXPORT_SYMBOL(i2c_transfer);
-#if defined (CONFIG_I2C_RK2818)
+#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29)
 int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
 {
        int ret;
index 63276d3f88f06886246c3b74bafe18ed4e6073ad..28af1f86cdc8f5822438c73bf5f64bf75190f1a7 100755 (executable)
@@ -54,7 +54,7 @@ struct i2c_board_info;
  * transmit one message at a time, a more complex version can be used to
  * transmit an arbitrary number of messages without interruption.
  */
-#if defined (CONFIG_I2C_RK2818)
+#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29)
 /* If everything went ok, return 'count' transmitted, else error code. */
 extern int i2c_master_normal_send(struct i2c_client *client,const char *buf ,int count, int scl_rate);
 extern int i2c_master_normal_recv(struct i2c_client *client, char *buf ,int count, int scl_rate);