}
// 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[] = {
.flags = IORESOURCE_IRQ,
},
{
- .start = RK30_I2C0_PHYS,
- .end = RK30_I2C0_PHYS + RK30_I2C0_SIZE - 1,
+ .start = I2C0_START,
+ .end = I2C0_END,
.flags = IORESOURCE_MEM,
},
};
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[] = {
.flags = IORESOURCE_IRQ,
},
{
- .start = RK30_I2C1_PHYS,
- .end = RK30_I2C1_PHYS + RK30_I2C1_SIZE - 1,
+ .start = I2C1_START,
+ .end = I2C1_END,
.flags = IORESOURCE_MEM,
},
};
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[] = {
.flags = IORESOURCE_IRQ,
},
{
- .start = RK30_I2C2_PHYS,
- .end = RK30_I2C2_PHYS + RK30_I2C2_SIZE - 1,
+ .start = I2C2_START,
+ .end = I2C2_END,
.flags = IORESOURCE_MEM,
},
};
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[] = {
.flags = IORESOURCE_IRQ,
},
{
- .start = RK30_I2C3_PHYS,
- .end = RK30_I2C3_PHYS + RK30_I2C3_SIZE - 1,
+ .start = I2C3_START,
+ .end = I2C3_END,
.flags = IORESOURCE_MEM,
},
};
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[] = {
.flags = IORESOURCE_IRQ,
},
{
- .start = RK30_I2C4_PHYS,
- .end = RK30_I2C4_PHYS + RK30_I2C4_SIZE - 1,
+ .start = I2C4_START,
+ .end = I2C4_END,
.flags = IORESOURCE_MEM,
},
};
#
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
#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)
{
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);
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);
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;
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
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;
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;
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;
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)
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 */
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;
*/
#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 */
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;
return ret;
}
-
--- /dev/null
+#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
+
#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
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);
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:
#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,
STATE_WRITE,
STATE_STOP
};
-
struct rk30_i2c {
- spinlock_t lock;
+ spinlock_t lock;
wait_queue_head_t wait;
unsigned int suspended:1;
unsigned long clkrate;
void __iomem *regs;
+ void __iomem *con_base;
struct clk *clk;
struct device *dev;
struct resource *ioarea;
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];
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