RK30 I2C drivers: new adapter(rk30) support
authorkfx <kfx@rock-chips.com>
Wed, 15 Feb 2012 12:17:42 +0000 (20:17 +0800)
committerkfx <kfx@rock-chips.com>
Wed, 15 Feb 2012 12:17:42 +0000 (20:17 +0800)
arch/arm/mach-rk30/devices.c
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-rk29-adapter.c
drivers/i2c/busses/i2c-rk30-adapter.c
drivers/i2c/busses/i2c-rk30-test.c [new file with mode: 0644]
drivers/i2c/busses/i2c-rk30.c
drivers/i2c/busses/i2c-rk30.h

index f597d442b503d732d104dd6f0212b37eb23b519a..f587b07398257e87e7b1a4d5b076414340642d63 100755 (executable)
@@ -265,16 +265,66 @@ static void __init rk30_init_uart(void)
 }
 
 // i2c
-#ifdef CONFIG_I2C0_RK30
-static struct rk30_i2c_platform_data default_i2c0_data = {
-       .bus_num = 0,
-       .is_div_from_arm = 1,
 #ifdef CONFIG_I2C0_CONTROLLER_RK29
-       .adap_type = I2C_RK29_ADAP,
+#define I2C0_ADAP_TYPE  I2C_RK29_ADAP
+#define I2C0_START      RK30_I2C0_PHYS
+#define I2C0_END        RK30_I2C0_PHYS + SZ_4K - 1
 #endif
 #ifdef CONFIG_I2C0_CONTROLLER_RK30
-       .adap_type = I2C_RK30_ADAP,
+#define I2C0_ADAP_TYPE   I2C_RK30_ADAP
+#define I2C0_START      RK30_I2C0_PHYS + SZ_4K
+#define I2C0_END        RK30_I2C0_PHYS + SZ_8K - 1
+#endif
+
+#ifdef CONFIG_I2C1_CONTROLLER_RK29
+#define I2C1_ADAP_TYPE  I2C_RK29_ADAP
+#define I2C1_START      RK30_I2C1_PHYS
+#define I2C1_END        RK30_I2C1_PHYS + SZ_4K - 1
+#endif
+#ifdef CONFIG_I2C1_CONTROLLER_RK30
+#define I2C1_ADAP_TYPE   I2C_RK30_ADAP
+#define I2C1_START      RK30_I2C1_PHYS + SZ_4K
+#define I2C1_END        RK30_I2C1_PHYS + SZ_8K - 1
+#endif
+
+#ifdef CONFIG_I2C2_CONTROLLER_RK29
+#define I2C2_ADAP_TYPE  I2C_RK29_ADAP
+#define I2C2_START      RK30_I2C2_PHYS
+#define I2C2_END        RK30_I2C2_PHYS + SZ_4K - 1
 #endif
+#ifdef CONFIG_I2C2_CONTROLLER_RK30
+#define I2C2_ADAP_TYPE   I2C_RK30_ADAP
+#define I2C2_START      RK30_I2C2_PHYS + SZ_4K
+#define I2C2_END        RK30_I2C2_PHYS + SZ_8K - 1
+#endif
+
+#ifdef CONFIG_I2C3_CONTROLLER_RK29
+#define I2C3_ADAP_TYPE  I2C_RK29_ADAP
+#define I2C3_START      RK30_I2C3_PHYS
+#define I2C3_END        RK30_I2C3_PHYS + SZ_4K - 1
+#endif
+#ifdef CONFIG_I2C3_CONTROLLER_RK30
+#define I2C3_ADAP_TYPE   I2C_RK30_ADAP
+#define I2C3_START      RK30_I2C3_PHYS + SZ_4K
+#define I2C3_END        RK30_I2C3_PHYS + SZ_8K - 1
+#endif
+
+#ifdef CONFIG_I2C4_CONTROLLER_RK29
+#define I2C4_ADAP_TYPE  I2C_RK29_ADAP
+#define I2C4_START      RK30_I2C4_PHYS
+#define I2C4_END        RK30_I2C4_PHYS + SZ_4K - 1
+#endif
+#ifdef CONFIG_I2C4_CONTROLLER_RK30
+#define I2C4_ADAP_TYPE   I2C_RK30_ADAP
+#define I2C4_START      RK30_I2C4_PHYS + SZ_4K
+#define I2C4_END        RK30_I2C4_PHYS + SZ_8K - 1
+#endif
+
+#ifdef CONFIG_I2C0_RK30
+static struct rk30_i2c_platform_data default_i2c0_data = {
+       .bus_num = 0,
+       .is_div_from_arm = 1,
+       .adap_type = I2C0_ADAP_TYPE,
 };
 
 static struct resource resources_i2c0[] = {
@@ -284,8 +334,8 @@ static struct resource resources_i2c0[] = {
                .flags  = IORESOURCE_IRQ,
        },
        {
-               .start  = RK30_I2C0_PHYS,
-               .end    = RK30_I2C0_PHYS + RK30_I2C0_SIZE - 1,
+               .start  = I2C0_START,
+        .end    = I2C0_END,    
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -305,12 +355,7 @@ static struct platform_device device_i2c0 = {
 static struct rk30_i2c_platform_data default_i2c1_data = {
        .bus_num = 1,
        .is_div_from_arm = 1,
-#ifdef CONFIG_I2C1_CONTROLLER_RK29
-       .adap_type = I2C_RK29_ADAP,
-#endif
-#ifdef CONFIG_I2C1_CONTROLLER_RK30
-       .adap_type = I2C_RK30_ADAP,
-#endif
+       .adap_type = I2C1_ADAP_TYPE,
 };
 
 static struct resource resources_i2c1[] = {
@@ -320,8 +365,8 @@ static struct resource resources_i2c1[] = {
                .flags  = IORESOURCE_IRQ,
        },
        {
-               .start  = RK30_I2C1_PHYS,
-               .end    = RK30_I2C1_PHYS + RK30_I2C1_SIZE - 1,
+               .start  = I2C1_START,
+        .end    = I2C1_END,    
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -341,12 +386,7 @@ static struct platform_device device_i2c1 = {
 static struct rk30_i2c_platform_data default_i2c2_data = {
        .bus_num = 2,
        .is_div_from_arm = 0,
-#ifdef CONFIG_I2C2_CONTROLLER_RK29
-       .adap_type = I2C_RK29_ADAP,
-#endif
-#ifdef CONFIG_I2C2_CONTROLLER_RK30
-       .adap_type = I2C_RK30_ADAP,
-#endif
+       .adap_type = I2C2_ADAP_TYPE,
 };
 
 static struct resource resources_i2c2[] = {
@@ -356,8 +396,8 @@ static struct resource resources_i2c2[] = {
                .flags  = IORESOURCE_IRQ,
        },
        {
-               .start  = RK30_I2C2_PHYS,
-               .end    = RK30_I2C2_PHYS + RK30_I2C2_SIZE - 1,
+               .start  = I2C2_START,
+        .end    = I2C2_END,    
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -377,12 +417,7 @@ static struct platform_device device_i2c2 = {
 static struct rk30_i2c_platform_data default_i2c3_data = {
        .bus_num = 3,
        .is_div_from_arm = 0,
-#ifdef CONFIG_I2C3_CONTROLLER_RK29
-       .adap_type = I2C_RK29_ADAP,
-#endif
-#ifdef CONFIG_I2C3_CONTROLLER_RK30
-       .adap_type = I2C_RK30_ADAP,
-#endif
+       .adap_type = I2C3_ADAP_TYPE,
 };
 
 static struct resource resources_i2c3[] = {
@@ -392,8 +427,8 @@ static struct resource resources_i2c3[] = {
                .flags  = IORESOURCE_IRQ,
        },
        {
-               .start  = RK30_I2C3_PHYS,
-               .end    = RK30_I2C3_PHYS + RK30_I2C3_SIZE - 1,
+               .start  = I2C3_START,
+        .end    = I2C3_END,    
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -413,12 +448,7 @@ static struct platform_device device_i2c3 = {
 static struct rk30_i2c_platform_data default_i2c4_data = {
        .bus_num = 4,
        .is_div_from_arm = 0,
-#ifdef CONFIG_I2C4_CONTROLLER_RK29
-       .adap_type = I2C_RK29_ADAP,
-#endif
-#ifdef CONFIG_I2C4_CONTROLLER_RK30
-       .adap_type = I2C_RK30_ADAP,
-#endif
+       .adap_type = I2C4_ADAP_TYPE,
 };
 
 static struct resource resources_i2c4[] = {
@@ -428,8 +458,8 @@ static struct resource resources_i2c4[] = {
                .flags  = IORESOURCE_IRQ,
        },
        {
-               .start  = RK30_I2C4_PHYS,
-               .end    = RK30_I2C4_PHYS + RK30_I2C4_SIZE - 1,
+               .start  = I2C4_START,
+        .end    = I2C4_END,    
                .flags  = IORESOURCE_MEM,
        },
 };
index bb71ae214ec346ffa03fab31edc3fb65c469d4c5..3948ba06a19c6720595aff1dd8ec54137d42f8db 100644 (file)
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_I2C_RK29)         += i2c-rk29.o
 obj-$(CONFIG_I2C_DEV_RK29)     += i2c-dev-rk29.o
-obj-$(CONFIG_I2C_RK30)         += i2c-rk30.o i2c-rk29-adapter.o i2c-rk30-adapter.o
+obj-$(CONFIG_I2C_RK30)         += i2c-rk30.o i2c-rk29-adapter.o i2c-rk30-adapter.o i2c-rk30-test.o
 obj-y                          += i2c-gpio.o
 
 # ACPI drivers
index a560db3ce1507b9781c6dad30bcd4bffea3dcc8a..edae8e907693c140ff4b7b649ea886e5be269607 100755 (executable)
 
 
 #define RK29_I2C_START_TMO_COUNT        100 // msleep 1 * 100
-#define ABNORMAL_STOP_DELAY             200 //unit us
-static unsigned int abnormal_stop_addr[] = {
-    0x2d,
-};
 
 int i2c_suspended(struct i2c_adapter *adap)
 {
@@ -171,7 +167,7 @@ static void  rk29_i2c_set_clk(struct rk30_i2c *i2c, unsigned long scl_rate)
        return;
 }
 
-static void rk29_i2c_init_hw(struct rk30_i2c *i2c)
+static void rk29_i2c_init_hw(struct rk30_i2c *i2c, unsigned long scl_rate)
 {
        unsigned long opr = readl(i2c->regs + I2C_OPR);
        
@@ -183,7 +179,7 @@ static void rk29_i2c_init_hw(struct rk30_i2c *i2c)
        opr &= ~I2C_OPR_RESET_STATUS;
        writel(opr, i2c->regs + I2C_OPR);
        
-       rk29_i2c_set_clk(i2c, 100000); 
+       rk29_i2c_set_clk(i2c, scl_rate); 
 
        rk29_i2c_disable_irq(i2c);
        writel(0, i2c->regs + I2C_LCMR);
@@ -242,19 +238,9 @@ static void rk29_i2c_message_start(struct rk30_i2c *i2c,
 
 static inline void rk29_i2c_stop(struct rk30_i2c *i2c, int ret)
 {
-    unsigned int n, i;
-
        i2c_dbg(i2c->dev, "STOP\n");
     udelay(i2c->tx_setup);
 
-    n = sizeof(abnormal_stop_addr)/sizeof(abnormal_stop_addr[0]);
-    for(i = 0; i < n; i++){
-        if(i2c->addr == abnormal_stop_addr[i])
-            udelay(ABNORMAL_STOP_DELAY);
-    }
-
-
-
     writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
 
        i2c->state = STATE_STOP;
@@ -306,16 +292,14 @@ static int rk29_i2c_irq_nextbyte(struct rk30_i2c *i2c, unsigned long isr)
                        dev_err(i2c->dev, "START: addr[0x%02x] ack was not received(isr)\n", i2c->addr);
                        goto out;
         }
-
                if ((lsr & I2C_LSR_RCV_NAK) &&
                    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
             writel(isr & ~I2C_ISR_MTX_RCVD_ACK, i2c->regs + I2C_ISR);
 
-                       rk29_i2c_stop(i2c, -ENXIO);
+                       rk29_i2c_stop(i2c, -EAGAIN);
                        dev_err(i2c->dev, "START: addr[0x%02x] ack was not received(lsr)\n", i2c->addr);
                        goto out;
                }
-
                if (i2c->msg->flags & I2C_M_RD)
                        i2c->state = STATE_READ;
                else
@@ -474,6 +458,7 @@ static int rk29_i2c_set_master(struct rk30_i2c *i2c)
            lsr = readl(i2c->regs + I2C_LSR);
                if (!(lsr & I2C_LSR_BUSY))
                        return 0;
+        writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
                msleep(1);
        }
        return -ETIMEDOUT;
@@ -512,7 +497,7 @@ static int rk29_i2c_doxfer(struct rk30_i2c *i2c,
        rk29_i2c_message_start(i2c, msgs);
        spin_unlock_irq(&i2c->lock);
 
-       timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+       timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, msecs_to_jiffies(I2C_WAIT_TIMEOUT));
 
        ret = i2c->msg_idx;
 
@@ -520,15 +505,19 @@ static int rk29_i2c_doxfer(struct rk30_i2c *i2c,
            i2c_dbg(i2c->dev, "addr[0x%02x] wait event timeout\n", msgs[0].addr);
        else if (ret != num)
                i2c_dbg(i2c->dev, "addr[0x%02x ]incomplete xfer (%d)\n", msgs[0].addr, ret);
-    msleep(1);
     if((readl(i2c->regs + I2C_LSR) &  I2C_LSR_BUSY) ||
        readl(i2c->regs + I2C_LCMR) &  I2C_LCMR_STOP ){
-        dev_warn(i2c->dev, "WARNING: STOP abnormal, addr[0x%02x] isr = 0x%x, lsr = 0x%x, lcmr = 0x%x\n",
-                msgs[0].addr,
-                readl(i2c->regs + I2C_ISR),
-                readl(i2c->regs + I2C_LSR),
-                readl(i2c->regs + I2C_LCMR)
+        msleep(1);
+        writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+        if((readl(i2c->regs + I2C_LSR) &  I2C_LSR_BUSY) ||
+            readl(i2c->regs + I2C_LCMR) &  I2C_LCMR_STOP ){
+            dev_warn(i2c->dev, "WARNING: STOP abnormal, addr[0x%02x] isr = 0x%x, lsr = 0x%x, lcmr = 0x%x\n",
+                    msgs[0].addr,
+                    readl(i2c->regs + I2C_ISR),
+                    readl(i2c->regs + I2C_LSR),
+                    readl(i2c->regs + I2C_LCMR)
                 );
+        }
     }
  out:
        return ret;
@@ -544,8 +533,7 @@ static int rk29_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
 {
        struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
-       int retry;
-       int ret;
+       int ret = 0;
     unsigned long scl_rate;
 
     if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
@@ -567,23 +555,12 @@ static int rk29_i2c_xfer(struct i2c_adapter *adap,
     rk29_i2c_enable_mport(i2c);
     udelay(i2c->tx_setup);
 
-       for (retry = 0; retry < adap->retries; retry++) {
-
-               ret = rk29_i2c_doxfer(i2c, msgs, num);
-
-               if (ret != -EAGAIN) {
-                       return ret;
-               }
-
-               i2c_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+       ret = rk29_i2c_doxfer(i2c, msgs, num);
 
-               msleep(1);
-       }
-       
     rk29_i2c_disable_mport(i2c);
     if(i2c->is_div_from_arm[i2c->adap.nr])
                wake_unlock(&i2c->idlelock[i2c->adap.nr]);
-       return -EREMOTEIO;
+       return ret;
 }
 
 /* declare our i2c functionality */
@@ -605,7 +582,6 @@ int i2c_add_rk29_adapter(struct i2c_adapter *adap)
     struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
 
     adap->algo = &rk29_i2c_algorithm;
-       adap->retries = 2;
 
     i2c->i2c_init_hw = &rk29_i2c_init_hw;
     i2c->i2c_set_clk = &rk29_i2c_set_clk;
index ea1e350c84f36828ab3ccc2f15c62c250510e7e2..d7459c31333d1c3de98f4f3969a1976066317df6 100755 (executable)
  */
 #include "i2c-rk30.h"
 
+/* Control register */
+#define I2C_CON         0X000
+enum{
+    I2C_EN_BIT  = 0,
+    I2C_MOD_BIT = 1,
+    I2C_START_BIT = 3,
+    I2C_STOP_BIT = 4,
+    I2C_LAST_ACK_BIT = 5,
+    I2C_ACT2ACK_BIT = 6,
+};
+//send ACK to slave when the last byte received in RX only mode
+#define LAST_SEND_ACK   0
+//send NAK to slave when the last byte received in RX only mode
+#define LAST_SEND_NAK   1
+#define LAST_SEND_TYPE  LAST_SEND_ACK //LAST_SEND_NAK
+
+#define I2C_MOD_MASK    (3 << I2C_MOD_BIT)
+enum{
+    I2C_MOD_TX = 0,
+    I2C_MOD_TRX,
+    I2C_MOD_RX,
+    I2C_MOD_RRX,
+};
+/* Clock dividor register */
+#define I2C_CLKDIV      0x004
+#define I2C_CLKDIV_VAL(divl, divh) (((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))    
+/* the slave address accessed  for master rx mode */
+#define I2C_MRXADDR     0x008
+#define I2C_MRXADDR_LOW     (1 << 24)
+#define I2C_MRXADDR_MID     (1 << 25)
+#define I2C_MRXADDR_HIGH     (1 << 26)
+/* the slave register address accessed  for master rx mode */
+#define I2C_MRXRADDR    0x00c
+#define I2C_MRXRADDR_LOW     (1 << 24)
+#define I2C_MRXRADDR_MID     (1 << 25)
+#define I2C_MRXRADDR_HIGH     (1 << 26)
+/* master tx count */
+#define I2C_MTXCNT      0x010
+/* master rx count */
+#define I2C_MRXCNT      0x014
+/* interrupt enable register */
+#define I2C_IEN         0x018
+#define I2C_BTFIEN  (1 << 0)
+#define I2C_BRFIEN  (1 << 1)
+#define I2C_MBTFIEN  (1 << 2)
+#define I2C_MBRFIEN  (1 << 3)
+#define I2C_STARTIEN  (1 << 4)
+#define I2C_STOPIEN  (1 << 5)
+#define I2C_NAKRCVIEN  (1 << 6)
+#define IRQ_MST_ENABLE (I2C_MBTFIEN | I2C_MBRFIEN | I2C_NAKRCVIEN | I2C_STARTIEN | I2C_STOPIEN)
+#define IRQ_ALL_DISABLE 0
+/* interrupt pending register */
+#define I2C_IPD         0x01c
+#define I2C_BTFIPD  (1 << 0)
+#define I2C_BRFIPD  (1 << 1)
+#define I2C_MBTFIPD  (1 << 2)
+#define I2C_MBRFIPD  (1 << 3)
+#define I2C_STARTIPD  (1 << 4)
+#define I2C_STOPIPD  (1 << 5)
+#define I2C_NAKRCVIPD  (1 << 6)
+/* finished count */
+#define I2C_FCNT        0x020
+/* I2C tx data register */
+#define I2C_TXDATA_BASE 0X100
+/* I2C rx data register */
+#define I2C_RXDATA_BASE 0x200
+static void rk30_show_regs(struct rk30_i2c *i2c)
+{
+    i2c_dbg(i2c->dev, "I2C_CON: 0x%08x\n", readl(i2c->regs + I2C_CON));
+    i2c_dbg(i2c->dev, "I2C_CLKDIV: 0x%08x\n", readl(i2c->regs + I2C_CLKDIV));
+    i2c_dbg(i2c->dev, "I2C_MRXADDR: 0x%08x\n", readl(i2c->regs + I2C_MRXADDR));
+    i2c_dbg(i2c->dev, "I2C_MRXRADDR: 0x%08x\n", readl(i2c->regs + I2C_MRXRADDR));
+    i2c_dbg(i2c->dev, "I2C_MTXCNT: 0x%08x\n", readl(i2c->regs + I2C_MTXCNT));
+    i2c_dbg(i2c->dev, "I2C_MRXCNT: 0x%08x\n", readl(i2c->regs + I2C_MRXCNT));
+    i2c_dbg(i2c->dev, "I2C_IEN: 0x%08x\n", readl(i2c->regs + I2C_IEN));
+    i2c_dbg(i2c->dev, "I2C_IPD: 0x%08x\n", readl(i2c->regs + I2C_IPD));
+    i2c_dbg(i2c->dev, "I2C_FCNT: 0x%08x\n", readl(i2c->regs + I2C_FCNT));
+    i2c_dbg(i2c->dev, "I2C_TXDATA0: 0x%08x\n", readl(i2c->regs + I2C_TXDATA_BASE + 0));
+    i2c_dbg(i2c->dev, "I2C_RXDATA0: 0x%08x\n", readl(i2c->regs + I2C_RXDATA_BASE + 0));
+}
+static inline void rk30_i2c_last_ack(struct rk30_i2c *i2c, int enable)
+{
+    unsigned int p = readl(i2c->regs + I2C_CON);
+
+    writel(rk30_set_bit(p, enable, I2C_LAST_ACK_BIT), i2c->regs + I2C_CON);
+}
+static inline void rk30_i2c_act2ack(struct rk30_i2c *i2c, int enable)
+{
+    unsigned int p = readl(i2c->regs + I2C_CON);
+
+    writel(rk30_set_bit(p, enable, I2C_ACT2ACK_BIT), i2c->regs + I2C_CON);
+}
+static inline void rk30_i2c_enable(struct rk30_i2c *i2c, int enable)
+{
+    unsigned int p = readl(i2c->regs + I2C_CON);
+
+    writel(rk30_set_bit(p, enable, I2C_EN_BIT), i2c->regs + I2C_CON);
+}
+static inline void rk30_i2c_set_mode(struct rk30_i2c *i2c)
+{
+    unsigned int p = readl(i2c->regs + I2C_CON);
+    
+    writel(rk30_set_bits(p, i2c->mode, I2C_MOD_BIT, I2C_MOD_MASK), i2c->regs + I2C_CON);
+}
+static inline void rk30_i2c_disable_irq(struct rk30_i2c *i2c)
+{
+    writel(IRQ_ALL_DISABLE, i2c->regs + I2C_IEN);
+}
+
+static inline void rk30_i2c_enable_irq(struct rk30_i2c *i2c)
+{
+    writel(IRQ_MST_ENABLE, i2c->regs + I2C_IEN);
+}
+
+static inline void rk30_i2c_send_start(struct rk30_i2c *i2c)
+{
+    unsigned int p = readl(i2c->regs + I2C_CON);
+    
+    p = rk30_set_bit(p, 1, I2C_START_BIT);
+    p = rk30_set_bit(p, 0, I2C_STOP_BIT);
+    writel(p, i2c->regs + I2C_CON);
+}
+static inline void rk30_i2c_send_stop(struct rk30_i2c *i2c)
+{
+    unsigned int p = readl(i2c->regs + I2C_CON);
+
+    p = rk30_set_bit(p, 0, I2C_START_BIT);
+    p = rk30_set_bit(p, 1, I2C_STOP_BIT);
+    writel(p, i2c->regs + I2C_CON);
+
+}
+/* SCL Divisor = CLKDIVL + CLKDIVH
+ * SCL = i2c_rate/ 8*SCLK Divisor
+*/
 static void  rk30_i2c_set_clk(struct rk30_i2c *i2c, unsigned long scl_rate)
 {
+    unsigned long i2c_rate = clk_get_rate(i2c->clk);
+
+    unsigned int div, divl, divh;
+
+    if((scl_rate == i2c->scl_rate) && (i2c_rate == i2c->i2c_rate))
+        return; 
+    i2c->i2c_rate = i2c_rate;
+    i2c->scl_rate = scl_rate;
+    div = rk30_ceil(i2c_rate, scl_rate * 8);
+    divh = divl = rk30_ceil(div, 2);
+    writel(I2C_CLKDIV_VAL(divl, divh), i2c->regs + I2C_CLKDIV);
     return;
 }
-static void rk30_i2c_init_hw(struct rk30_i2c *i2c)
+static void rk30_i2c_init_hw(struct rk30_i2c *i2c, unsigned long scl_rate)
 {
+    rk30_i2c_set_clk(i2c, scl_rate);
        return;
 }
+/* returns TRUE if we this is the last byte in the current message */
+static inline int is_msglast(struct rk30_i2c *i2c)
+{
+       return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/* returns TRUE if we reached the end of the current message */
+static inline int is_msgend(struct rk30_i2c *i2c)
+{
+       return i2c->msg_ptr >= i2c->msg->len;
+}
 
+static void rk30_i2c_stop(struct rk30_i2c *i2c, int ret)
+{
+
+    i2c->msg_ptr = 0;
+       i2c->msg = NULL;
+       i2c->msg_idx++;
+       i2c->msg_num = 0;
+       if (ret)
+               i2c->msg_idx = ret;
+
+    i2c->state = STATE_STOP;
+    rk30_i2c_send_stop(i2c);
+}
+static void rk30_irq_read_prepare(struct rk30_i2c *i2c)
+{
+    unsigned int cnt, len = i2c->msg->len - i2c->msg_ptr;
 
+    if(is_msgend(i2c)) {
+        rk30_i2c_stop(i2c, 0);
+        return;
+    }
+    if(len > 32)
+        cnt = 32;
+    else
+        cnt = len;
+
+    writel(cnt, i2c->regs + I2C_MRXCNT);
+}
+static void rk30_irq_read_get_data(struct rk30_i2c *i2c)
+{
+     unsigned int i, len = i2c->msg->len - i2c->msg_ptr;
+     unsigned int p;
+
+     len = (len >= 32)?32:len;
+
+     for(i = 0; i < len; i++){
+         if(i%4 == 0)
+             p = readl(i2c->regs + I2C_RXDATA_BASE +  (i/4) * 4);
+         i2c->msg->buf[i2c->msg_ptr++] = (p >>((i%4) * 8)) & 0xff;
+    }
+
+     return;
+}
+static void rk30_irq_write_prepare(struct rk30_i2c *i2c)
+{
+    unsigned int data = 0, cnt = 0, i, j;
+    unsigned char byte;
+
+    if(is_msgend(i2c)) {
+        rk30_i2c_stop(i2c, 0);
+        return;
+    }
+    for(i = 0; i < 8; i++){
+        data = 0;
+        for(j = 0; j < 4; j++) {
+            if(is_msgend(i2c)) 
+                break;
+            if(i2c->msg_ptr == 0 && cnt == 0)
+                byte = (i2c->addr & 0x7f) << 1;
+            else
+                byte =  i2c->msg->buf[i2c->msg_ptr++];
+            cnt++;
+            data |= (byte << (j * 8));
+        }
+        writel(data, i2c->regs + I2C_TXDATA_BASE + 4 * i);
+        if(is_msgend(i2c)) 
+            break;
+    }
+    writel(cnt, i2c->regs + I2C_MTXCNT);
+}
+static void rk30_i2c_irq_nextblock(struct rk30_i2c *i2c, unsigned int ipd)
+{
+    switch (i2c->state) {
+       case STATE_IDLE:
+               dev_err(i2c->dev, "Addr[0x%02x] called in STATE_IDLE\n", i2c->addr);
+               goto out;
+    case STATE_START:
+        if(!(ipd & I2C_STARTIPD)){
+            if(ipd & I2C_STOPIPD){
+                writel(I2C_STOPIPD, i2c->regs + I2C_IPD);
+                rk30_i2c_send_start(i2c);
+            }
+            else {
+                rk30_i2c_stop(i2c, -ENXIO);
+                           dev_err(i2c->dev, "Addr[0x%02x] no start irq in STATE_START\n", i2c->addr);
+                rk30_show_regs(i2c);
+            }
+            goto out;
+        }
+        writel(I2C_STARTIPD, i2c->regs + I2C_IPD);
+        if(i2c->mode ==  I2C_MOD_TX){
+            i2c->state = STATE_WRITE;
+            goto prepare_write;
+        }
+        else {
+             i2c->state = STATE_READ;
+             goto prepare_read;
+        }
+    case STATE_WRITE:
+        if(!(ipd & I2C_MBTFIPD)){
+            goto out;
+        }
+        writel(I2C_MBTFIPD, i2c->regs + I2C_IPD);
+prepare_write:
+        rk30_irq_write_prepare(i2c);
+        break;
+    case STATE_READ:
+        if(!(ipd & I2C_MBRFIPD)){
+            goto out;
+        }
+        writel(I2C_MBRFIPD, i2c->regs + I2C_IPD);
+        rk30_irq_read_get_data(i2c);
+prepare_read:
+        rk30_irq_read_prepare(i2c);
+        break;
+    case STATE_STOP:
+        if(ipd & I2C_STOPIPD || i2c->msg_idx  < 0){
+            writel(0xff, i2c->regs + I2C_IPD);
+               rk30_i2c_disable_irq(i2c);
+               wake_up(&i2c->wait);
+        }
+        break;
+    default:
+        break;
+    }
+out:
+    return;
+}
 static irqreturn_t rk30_i2c_irq(int irq, void *dev_id)
 {
+    struct rk30_i2c *i2c = dev_id;
+    unsigned int ipd;
+    spin_lock(&i2c->lock);
+    ipd = readl(i2c->regs + I2C_IPD);
+
+    if(ipd & I2C_NAKRCVIPD) {
+        writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD);
+        rk30_i2c_stop(i2c, -EAGAIN);
+               dev_err(i2c->dev, "Addr[0x%02x] ack was not received\n", i2c->addr);
+        rk30_show_regs(i2c);
+        goto out;
+    }
+
+    rk30_i2c_irq_nextblock(i2c, ipd);
+out:
+    spin_unlock(&i2c->lock);
        return IRQ_HANDLED;
 }
 
 
+static int rk30_i2c_set_master(struct rk30_i2c *i2c, struct i2c_msg *msgs, int num)
+{
+    unsigned int addr = (msgs[0].addr & 0x7f) << 1;
+    unsigned int reg_valid_bits = 0;
+    unsigned int reg_addr = 0;
+    
+    if(num == 1) {
+        if(!(msgs[0].flags & I2C_M_RD)){
+               i2c->msg = &msgs[0];
+            i2c->mode = I2C_MOD_TX;
+        }
+        else {
+            addr |= 1;
+               i2c->msg = &msgs[0];
+            writel(addr | I2C_MRXADDR_LOW, i2c->regs + I2C_MRXADDR);
+            i2c->mode = I2C_MOD_RX;
+        }
+    }
+    else if(num == 2) {
+        switch(msgs[0].len){
+            case 1:
+                reg_addr = msgs[0].buf[0];
+                reg_valid_bits |= I2C_MRXADDR_LOW;
+                break;
+            case 2:
+                reg_addr = msgs[0].buf[0] | (msgs[0].buf[1] << 8);
+                reg_valid_bits |= I2C_MRXADDR_LOW | I2C_MRXADDR_MID;
+                break;
+            case 3:
+                reg_addr = msgs[0].buf[0] | (msgs[0].buf[1] << 8) | (msgs[0].buf[2] << 16);
+                reg_valid_bits |= I2C_MRXADDR_LOW | I2C_MRXADDR_MID | I2C_MRXADDR_HIGH;
+                break;
+            default:
+                return -EIO;
+        }
+        if((msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+            addr |= 1;
+               i2c->msg = &msgs[1];
+            writel(addr | I2C_MRXADDR_LOW, i2c->regs + I2C_MRXADDR);
+            writel(reg_addr | reg_valid_bits, i2c->regs + I2C_MRXRADDR);
+            i2c->mode = I2C_MOD_RRX;
+        }
+        else if(!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+               i2c->msg = &msgs[1];
+            writel(addr | I2C_MRXADDR_LOW, i2c->regs + I2C_MRXADDR);
+            writel(reg_addr | reg_valid_bits, i2c->regs + I2C_MRXRADDR);
+            i2c->mode = I2C_MOD_TRX;
+        }
+        else 
+            return -EIO;
+    }
+    else {
+        dev_err(i2c->dev, "This case(num > 2) has not been support now\n");
+        return -EIO;
+    }
+    rk30_i2c_set_mode(i2c);
+    rk30_i2c_last_ack(i2c, LAST_SEND_TYPE);
+    if(msgs[0].flags & I2C_M_IGNORE_NAK)
+        rk30_i2c_act2ack(i2c, 0);
+    else
+        rk30_i2c_act2ack(i2c, 1);
+
+    return 0;
+}
+/* rk30_i2c_doxfer
+ *
+ * this starts an i2c transfer
+*/
+static int rk30_i2c_doxfer(struct rk30_i2c *i2c,
+                             struct i2c_msg *msgs, int num)
+{
+       unsigned long timeout;
+       int ret = 0;
+
+       if (i2c->suspended)
+               return -EIO;
+
+       ret = rk30_i2c_set_master(i2c, msgs, num);
+       if (ret != 0) {
+        dev_err(i2c->dev, "addr[0x%02x] set master error\n", msgs[0].addr);  
+       return ret;
+    }
+       spin_lock_irq(&i2c->lock);
+
+    i2c->addr = msgs[0].addr;
+       i2c->msg_num = num;
+    i2c->msg_ptr = 0;
+    i2c->msg_idx = 0;
+    i2c->state = STATE_START;
+
+       spin_unlock_irq(&i2c->lock);
+
+       rk30_i2c_enable_irq(i2c);
+    rk30_i2c_send_start(i2c);
+
+       timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, msecs_to_jiffies(I2C_WAIT_TIMEOUT));
+
+       ret = i2c->msg_idx;
+
+       if (timeout == 0){
+        dev_err(i2c->dev, "addr[0x%02x] wait event timeout, state = %d\n", msgs[0].addr, i2c->state);  
+        rk30_show_regs(i2c);
+        rk30_i2c_send_stop(i2c);
+        if(ret >= 0)
+            ret = -ETIMEDOUT;
+        goto out;
+    }
+    if(ret > 0)
+        ret = num;
+ out:
+    writel(0xff, i2c->regs + I2C_IPD);
+       rk30_i2c_disable_irq(i2c);
+       return ret;
+}
+
+/* rk30_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+*/
+
 static int rk30_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
 {
-    return 0;
+       int ret = 0;
+    unsigned long scl_rate;
+       struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
+
+    if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
+               scl_rate = msgs[0].scl_rate;
+       else if(msgs[0].scl_rate > 400000){
+               dev_warn(i2c->dev, "Warning: addr[0x%x] msg[0].scl_rate( = %dKhz) is too high!",
+                       msgs[0].addr, msgs[0].scl_rate/1000);
+               scl_rate = 400000;      
+       }
+       else{
+               dev_warn(i2c->dev, "Warning: addr[0x%x] msg[0].scl_rate( = %dKhz) is too low!",
+                       msgs[0].addr, msgs[0].scl_rate/1000);
+               scl_rate = 10000;
+       }
+    if(i2c->is_div_from_arm[i2c->adap.nr])
+               wake_lock(&i2c->idlelock[i2c->adap.nr]);
+
+    rk30_i2c_enable(i2c, 1);
+       rk30_i2c_set_clk(i2c, scl_rate);
+    udelay(i2c->tx_setup);
+
+    i2c_dbg(i2c->dev, "i2c transfer: addr[0x%x], scl_reate[%ldKhz]\n", msgs[0].addr, scl_rate/1000);
+       ret = rk30_i2c_doxfer(i2c, msgs, num);
+
+    rk30_i2c_enable(i2c, 0);
+    i2c->state = STATE_IDLE;
+    if(i2c->is_div_from_arm[i2c->adap.nr])
+               wake_unlock(&i2c->idlelock[i2c->adap.nr]);
+       return ret;
 }
 
 /* declare our i2c functionality */
@@ -55,7 +506,6 @@ int i2c_add_rk30_adapter(struct i2c_adapter *adap)
     struct rk30_i2c *i2c = (struct rk30_i2c *)adap->algo_data;
 
     adap->algo = &rk30_i2c_algorithm;
-       adap->retries = 3;
 
     i2c->i2c_init_hw = &rk30_i2c_init_hw;
     i2c->i2c_set_clk = &rk30_i2c_set_clk;
@@ -66,4 +516,3 @@ int i2c_add_rk30_adapter(struct i2c_adapter *adap)
     return ret;
 }
 
-
diff --git a/drivers/i2c/busses/i2c-rk30-test.c b/drivers/i2c/busses/i2c-rk30-test.c
new file mode 100644 (file)
index 0000000..d86b3e9
--- /dev/null
@@ -0,0 +1,128 @@
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "i2c-rk30.h"
+
+#if 0
+#define TEST_SCL_RATE (100 * 1000)
+#define I2C_NUM     1
+
+struct rw_info {
+    unsigned short addr;
+    unsigned int reg;
+    unsigned int reg_bytes;
+    unsigned char buf[100];
+    unsigned int len;
+};
+
+static int test_write(struct i2c_client *client, struct rw_info *info)
+{
+    int i, ret = 0;
+    struct i2c_msg msg;
+    
+    char *buf = kzalloc(info->reg_bytes + info->len, GFP_KERNEL);
+    for(i = 0; i < info->reg_bytes; i++)
+        buf[i] = (info->reg >> i)& 0xff;
+    for(i = info->reg_bytes; i < info->len; i++)
+        buf[i] = info->buf[i - info->reg_bytes];
+
+    msg.addr = client->addr;
+    msg.flags = client->flags;
+    msg.buf = buf;
+    msg.len = info->reg_bytes + info->len;
+    msg.scl_rate = TEST_SCL_RATE;
+    ret = i2c_transfer(client->adapter, &msg, 1);
+    kfree(buf);
+
+    return ret;
+
+}
+
+static int test_read(struct i2c_client *client, struct rw_info *info)
+{
+    int i, ret = 0, msg_num = 0;
+    char buf[4];
+    struct i2c_msg msgs[2];
+    if(info->reg_bytes == 0){
+        msgs[0].addr = client->addr;
+        msgs[0].flags = client->flags|I2C_M_RD;
+        msgs[0].buf = info->buf;
+        msgs[0].len = info->len;
+        msgs[0].scl_rate = TEST_SCL_RATE;  
+        msg_num = 1;
+    }else {
+        for(i = 0; i < info->reg_bytes; i++) {
+            buf[i] = (info->reg >> i) & 0xff;
+        }
+        msgs[0].addr = client->addr;
+        msgs[0].flags = client->flags;
+        msgs[0].buf = buf;
+        msgs[0].len = info->reg_bytes;
+        msgs[0].scl_rate = TEST_SCL_RATE;  
+
+        msgs[1].addr = client->addr;
+        msgs[1].flags = client->flags|I2C_M_RD;
+        msgs[1].buf = info->buf;
+        msgs[1].len = info->len;
+        msgs[1].scl_rate = TEST_SCL_RATE;
+        msg_num = 2;
+    }
+
+
+    ret = i2c_transfer(client->adapter, msgs, msg_num);
+    return ret;
+}
+
+static void test_set_client(struct i2c_client *client, __u16 addr, int nr)
+{
+    client->flags = 0;
+    client->addr = addr;
+    client->adapter = i2c_get_adapter(nr);
+}
+static int __init test_init(void)
+{
+    int nr = 0, ret = 0;
+    struct i2c_client *client = NULL;
+    struct rw_info info = {
+        .addr = 0x51,
+        .reg = 0x01,
+        .reg_bytes = 1,
+        .len = 8,
+        .buf = 
+        {
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+        },
+    };
+        
+    client = kzalloc(sizeof(struct i2c_client) * I2C_NUM, GFP_KERNEL);
+
+    printk("%s: start\n", __func__);
+    while(1) {
+        for(nr = 0; nr < I2C_NUM; nr++){
+            test_set_client(&client[nr], info.addr, nr);
+            ret = test_write(&client[nr], &info);
+            printk("i2c-%d: write val [0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x], ret = %d\n",
+                    nr, info.buf[0], info.buf[1], info.buf[2], info.buf[3], info.buf[4], info.buf[5], info.buf[6], info.buf[7], ret);
+            if(ret < 0)
+                break;
+            ret = test_read(&client[nr], &info);
+            printk("i2c-%d: read val [0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x], ret = %d\n",
+                    nr, info.buf[0], info.buf[1], info.buf[2], info.buf[3], info.buf[4], info.buf[5], info.buf[6], info.buf[7], ret);
+            if(ret < 0)
+                break;
+        }
+    }
+    kfree(client);
+    return 0;
+}
+
+static void __exit test_exit(void)
+{
+    return;
+}
+
+subsys_initcall_sync(test_init);
+module_exit(test_exit);
+
+#endif
+
index e738fbaabc228b1535b5a2c41a30fc44495c3df0..82f3073e2e4746d60809941005c562456630637f 100755 (executable)
 #include "i2c-rk30.h"
 
 #define TX_SETUP                        1 //unit us
+void i2c_adap_sel(struct rk30_i2c *i2c, int nr, int adap_type)
+{
+    unsigned int p = readl(i2c->con_base);
+
+    writel(rk30_set_bit(p, adap_type, I2C_ADAP_SEL_BIT(nr)), i2c->con_base);
+}
 
 #ifdef CONFIG_CPU_FREQ
 
@@ -86,19 +92,25 @@ static int rk30_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "no platform data\n");
                return -EINVAL;
        }
-    if(pdata->io_init)
-               pdata->io_init();
+
 
        i2c = kzalloc(sizeof(struct rk30_i2c), GFP_KERNEL);
        if (!i2c) {
                dev_err(&pdev->dev, "no memory for state\n");
                return -ENOMEM;
        }
+    i2c->con_base = (void __iomem *)GRF_I2C_CON_BASE;
+    i2c_adap_sel(i2c, pdata->bus_num, pdata->adap_type);
+
+    if(pdata->io_init)
+               pdata->io_init();
 
        strlcpy(i2c->adap.name, "rk30_i2c", sizeof(i2c->adap.name));
        i2c->adap.owner   = THIS_MODULE;
        i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        i2c->tx_setup     = TX_SETUP;
+       i2c->adap.retries = 5;
+    i2c->adap.timeout = msecs_to_jiffies(500);
 
        spin_lock_init(&i2c->lock);
        init_waitqueue_head(&i2c->wait);
@@ -192,7 +204,7 @@ static int rk30_i2c_probe(struct platform_device *pdev)
     if(i2c->is_div_from_arm[i2c->adap.nr])
         wake_lock_init(&i2c->idlelock[i2c->adap.nr], WAKE_LOCK_IDLE, name);
 
-    i2c->i2c_init_hw(i2c);
+    i2c->i2c_init_hw(i2c, 100 * 1000);
        dev_info(&pdev->dev, "%s: RK30 I2C adapter\n", dev_name(&i2c->adap.dev));
        return 0;
 //err_none:
index 23f0751bac614f4487b9a3182d9ba54fb4fb9431..05db8a4c22a655dc221df435cd46164a31552d3a 100755 (executable)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 
 #include <mach/board.h>
+#include <mach/iomux.h>
 #include <asm/irq.h>
 
 #if 0
 #define i2c_dbg(dev, format, arg...)
 #endif
 
+#define I2C_WAIT_TIMEOUT            100  //100ms
 
+#define rk30_set_bit(p, v, b)        (((p) & ~(1 << (b))) | ((v) << (b)))
+#define rk30_get_bit(p, b)           (((p) & (1 << (b))) >> (b))
+
+#define rk30_set_bits(p, v, b, m)      (((p) & ~(m)) | ((v) << (b)))
+#define rk30_get_bits(p, b, m)     (((p) & (m)) >> (b))
+
+#define rk30_ceil(x, y) \
+       ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; })
+
+#define GRF_I2C_CON_BASE            (RK30_GRF_BASE + GRF_SOC_CON1)
+#define I2C_ADAP_SEL_BIT(nr)        ((nr) + 11)
 enum rk30_i2c_state {
        STATE_IDLE,
        STATE_START,
@@ -35,9 +48,8 @@ enum rk30_i2c_state {
        STATE_WRITE,
        STATE_STOP
 };
-
 struct rk30_i2c {
-       spinlock_t              lock;
+       spinlock_t                  lock;
        wait_queue_head_t       wait;
        unsigned int            suspended:1;
 
@@ -53,6 +65,7 @@ struct rk30_i2c {
        unsigned long           clkrate;
 
        void __iomem            *regs;
+    void __iomem        *con_base;
        struct clk                  *clk;
        struct device           *dev;
        struct resource         *ioarea;
@@ -61,6 +74,7 @@ struct rk30_i2c {
     unsigned long              scl_rate;
        unsigned long           i2c_rate;
     unsigned int        addr;
+    unsigned int        mode;
 
     struct wake_lock    idlelock[5];
     int is_div_from_arm[5];
@@ -69,11 +83,11 @@ struct rk30_i2c {
        struct notifier_block   freq_transition;
 #endif
 
-    void (*i2c_init_hw)(struct rk30_i2c *);
+    void (*i2c_init_hw)(struct rk30_i2c *, unsigned long scl_rate);
     void (*i2c_set_clk)(struct rk30_i2c *, unsigned long);
     irqreturn_t (*i2c_irq)(int, void *);
 };
-
+void i2c_adap_sel(struct rk30_i2c *i2c, int nr, int adap_type);
 int i2c_add_rk29_adapter(struct i2c_adapter *);
 int i2c_add_rk30_adapter(struct i2c_adapter *);
 #endif