#include "i2c-rk29.h"
#define DRV_NAME "rk29_i2c"
-#define RETRY_NUM 3
+#define RETRY_NUM 1
-#define RK2818_I2C_TIMEOUT (msecs_to_jiffies(100))
-#define RK2818_DELAY_TIME 2
+#define RK29_I2C_TIMEOUT(x) (msecs_to_jiffies(x))
#if 0
#define i2c_dbg(dev, format, arg...) \
#else
#define i2c_dbg(dev, format, arg...)
-#define i2c_err(dev, format, arg...)
+#define i2c_err(dev, format, arg...)
#endif
enum rk29_error {
- RK2818_ERROR_NONE = 0,
- RK2818_ERROR_ARBITR_LOSE,
- RK2818_ERROR_UNKNOWN
+ RK29_ERROR_NONE = 0,
+ RK29_ERROR_ARBITR_LOSE,
+ RK29_ERROR_UNKNOWN
};
enum rk29_event {
- RK2818_EVENT_NONE = 0,
+ RK29_EVENT_NONE = 0,
/* master has received ack(MTX mode)
means that data has been sent to slave.
*/
- RK2818_EVENT_MTX_RCVD_ACK,
+ RK29_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
+ RK29_EVENT_MRX_NEED_ACK,
+ RK29_EVENT_MAX
};
struct rk29_i2c_data {
unsigned int mode;
int retry;
+ int poll_status;
+
unsigned int irq;
spinlock_t cmd_lock;
#endif
};
-static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c);
-
static void rk29_set_ack(struct rk29_i2c_data *i2c)
{
unsigned long conr = readl(i2c->regs + I2C_CONR);
/* 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;
}
static int rk29_event_occurred(struct rk29_i2c_data *i2c)
{
- unsigned long isr;
+ unsigned long isr, lsr;
isr = readl(i2c->regs + I2C_ISR);
- i2c_dbg(i2c->dev,"event occurred, isr = %lx\n", isr);
+ lsr = readl(i2c->regs + I2C_LSR);
+ i2c_dbg(i2c->dev,"event occurred, isr = %lx, lsr = %lx\n", isr, lsr);
if(isr & I2C_ISR_ARBITR_LOSE)
{
- isr &= ~I2C_ISR_ARBITR_LOSE;
- writel(isr, i2c->regs + I2C_ISR);
- i2c->cmd_err = RK2818_ERROR_ARBITR_LOSE;
+ writel(0, i2c->regs + I2C_ISR);
+ i2c->cmd_err = RK29_ERROR_ARBITR_LOSE;
i2c_err(i2c->dev, "<error>arbitration loss\n");
- return 1;
+ return 0;
}
switch(i2c->cmd_event)
{
- case RK2818_EVENT_MTX_RCVD_ACK:
+ case RK29_EVENT_MTX_RCVD_ACK:
if(isr & I2C_ISR_MTX_RCVD_ACK)
{
isr &= ~I2C_ISR_MTX_RCVD_ACK;
return 1;
}
break;
- case RK2818_EVENT_MRX_NEED_ACK:
+ case RK29_EVENT_MRX_NEED_ACK:
if(isr & I2C_ISR_MRX_NEED_ACK)
{
isr &= ~I2C_ISR_MRX_NEED_ACK;
default:
break;
}
- i2c->cmd_err = RK2818_ERROR_UNKNOWN;
+ writel(0, i2c->regs + I2C_ISR);
+ i2c->cmd_err = RK29_ERROR_UNKNOWN;
return 0;
}
spin_lock(&i2c->cmd_lock);
res = rk29_event_occurred(i2c);
if(res)
- //if(res || i2c->cmd_err != RK2818_ERROR_NONE)
- complete(&i2c->cmd_complete);
+ {
+ if(i2c->mode == I2C_MODE_IRQ)
+ complete(&i2c->cmd_complete);
+ else
+ i2c->poll_status = 1;
+ }
spin_unlock(&i2c->cmd_lock);
return IRQ_HANDLED;
}
-static int wait_for_completion_poll_timeout(struct rk29_i2c_data *i2c, unsigned long timeout)
+static int wait_for_completion_poll_timeout(struct rk29_i2c_data *i2c)
{
- unsigned int time = RK2818_DELAY_TIME;
- int res;
-
- while(!time_after(jiffies, jiffies + timeout))
+ int tmo = 10000;
+
+ while(--tmo)
{
- res = rk29_event_occurred(i2c);
- if(res)
- //if(res || (i2c->cmd_err != RK2818_ERROR_NONE && i2c->cmd_err != RK2818_ERROR_UNKNOWN))
+ if(i2c->poll_status == 1)
return 1;
- udelay(time);
- time *= 2;
+ udelay(400*1000/i2c->scl_rate);
}
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()))
{
- if(unlikely(irqs_disabled()))
- {
- i2c_err(i2c->dev, "irqs are disabled on this system!\n");
- return -EIO;
- }
+ i2c_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_err = RK29_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)
+ {
+ init_completion(&i2c->cmd_complete);
ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
- RK2818_I2C_TIMEOUT);
+ RK29_I2C_TIMEOUT(40000 * 1000/i2c->scl_rate));
+ }
else
- ret = wait_for_completion_poll_timeout(i2c, RK2818_I2C_TIMEOUT);
-
+ {
+ i2c->poll_status = 0;
+ ret = wait_for_completion_poll_timeout(i2c);
+ }
if(ret < 0)
{
i2c_err(i2c->dev, "i2c wait for event %04x, retrun %d \n", mr_event, ret);
return 0;
}
-static int rk29_wait_while_busy(struct rk29_i2c_data *i2c)
+static void rk29_i2c_stop(struct rk29_i2c_data *i2c)
{
- unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT/1000;
- unsigned long lsr;
- unsigned int time = RK2818_DELAY_TIME;
+ int tmo = 10000 * 1000/i2c->scl_rate;
- while(!time_after(jiffies, timeout))
+ writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+ while(--tmo && !(readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP))
{
- lsr = readl(i2c->regs + I2C_LSR);
- if(!(lsr & I2C_LSR_BUSY))
- return 0;
- udelay(time);
- time *= 2;
+ udelay(400*1000/i2c->scl_rate);
}
- return 0;
+ writel(0, i2c->regs + I2C_ISR);
+ rk29_i2c_disable_irqs(i2c);
+
+ udelay(tmo);
+ return;
}
-static int rk29_i2c_stop(struct rk29_i2c_data *i2c)
+static void rk29_wait_while_busy(struct rk29_i2c_data *i2c)
{
- unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT/1000;
- unsigned int time = RK2818_DELAY_TIME;
-
- writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
- while(!time_after(jiffies, timeout))
+ int tmo = 10000 * 1000/i2c->scl_rate;
+
+ while(--tmo && (readl(i2c->regs + I2C_LSR) & I2C_LSR_BUSY))
{
- if(!(readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP))
- {
- udelay(100);
- return 0;
- }
- udelay(time);
- time *= 2;
+ udelay(400*1000/i2c->scl_rate);
}
- return 0;
+ return;
}
+
static int rk29_send_2nd_addr(struct rk29_i2c_data *i2c,
struct i2c_msg *msg, int start)
{
int ret = 0;
+ unsigned long lsr;
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)
+ rk29_set_ack(i2c);
+
+ if((ret = rk29_wait_event(i2c, RK29_EVENT_MTX_RCVD_ACK)) != 0)
{
i2c_err(i2c->dev, "after sent addr_2nd, i2c wait for ACK timeout\n");
return ret;
}
+ lsr = readl(i2c->regs + I2C_LSR);
+ if(lsr & I2C_LSR_RCV_NAK)
+ return -EINVAL;
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);
+ unsigned long conr,lsr;
int ret = 0;
if(msg->flags & I2C_M_TEN)
addr_1st |= 0x01;
else
addr_1st &= (~0x01);
- rk29_set_ack(i2c);
+
+ if(start)
+ rk29_wait_while_busy(i2c);
+
+ writel(0, i2c->regs + I2C_ISR);
+ conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MTX_MODE;
+ conr |= I2C_CONR_MPORT_ENABLE;
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)
- {
- i2c_err(i2c->dev, "i2c is busy, when send address\n");
- return ret;
- }
- }
+ rk29_set_ack(i2c);
writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
- if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+ if((ret = rk29_wait_event(i2c, RK29_EVENT_MTX_RCVD_ACK)) != 0)
{
i2c_err(i2c->dev, "after sent addr_1st, i2c wait for ACK timeout\n");
return ret;
}
+ lsr = readl(i2c->regs + I2C_LSR);
+ if(lsr & I2C_LSR_RCV_NAK)
+ return -EINVAL;
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);
+ unsigned long conr, lsr;
conr = readl(i2c->regs + I2C_CONR);
conr |= I2C_CONR_MTX_MODE;
+ //conr |= I2C_CONR_MPORT_ENABLE;
writel(conr, i2c->regs + I2C_CONR);
-
- rk29_set_ack(i2c);
+
for(i = 0; i < msg->len; i++)
{
- i2c_dbg(i2c->dev, "i2c send buf[%d]: %x\n", i, msg->buf[i]);
+ i2c_dbg(i2c->dev, "i2c send buf[%d]: %x\n", i, msg->buf[i]);
writel(msg->buf[i], i2c->regs + I2C_MTXR);
+ rk29_set_ack(i2c);
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
- if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
+ if((ret = rk29_wait_event(i2c, RK29_EVENT_MTX_RCVD_ACK)) != 0)
return ret;
- if(readl(i2c->regs + I2C_LSR) & I2C_LSR_RCV_NAK)
- rk29_set_nak(i2c);
+ lsr = readl(i2c->regs + I2C_LSR);
+ if((lsr & I2C_LSR_RCV_NAK) && (i != msg->len -1))
+ return -EINVAL;
+
}
return ret;
}
int i, ret = 0;
unsigned long conr;
- rk29_set_ack(i2c);
conr = readl(i2c->regs + I2C_CONR);
conr &= I2C_CONR_MRX_MODE;
+ //conr |= I2C_CONR_MPORT_ENABLE;
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)
+ if((ret = rk29_wait_event(i2c, RK29_EVENT_MRX_NEED_ACK)) != 0)
return ret;
msg->buf[i] = (uint8_t)readl(i2c->regs + I2C_MRXR);
- if( i == msg->len - 1)
+ if( i == msg->len -1)
rk29_set_nak(i2c);
+ else
+ rk29_set_ack(i2c);
i2c_dbg(i2c->dev, "i2c recv >>>>>>>>>>>> buf[%d]: %x\n", i, msg->buf[i]);
}
return ret;
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
int ret = 0;
- #if defined (CONFIG_IOEXTEND_TCA6424)
- struct tca6424_platform_data *pdata = adap->dev.platform_data;
- #endif
-
if(msg->len == 0)
{
ret = -EINVAL;
if((ret = rk29_send_address(i2c, msg, start))!= 0)
{
+ rk29_set_nak(i2c);
i2c_err(i2c->dev, "<error>rk29_send_address timeout\n");
goto exit;
}
{
if((ret = rk29_i2c_send_msg(i2c, msg)) != 0)
{
+ rk29_set_nak(i2c);
i2c_err(i2c->dev, "<error>rk29_i2c_send_msg timeout\n");
goto exit;
}
}
exit:
- if(stop || ret < 0)
- {
- if(ret < 0)
- rk29_set_nak(i2c);
- if((ret = rk29_i2c_stop(i2c)) != 0)
- {
- i2c_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
- }
-#endif
- }
+ //if(stop || ret < 0)
+ //{
+ rk29_i2c_stop(i2c);
+ //}
return ret;
}
int ret = -1;
int i;
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
- int retry = i2c->retry;
- unsigned long conr = readl(i2c->regs + I2C_CONR);
+ //int retry = i2c->retry;
/*
if(i2c->suspended ==1)
return -EIO;
*/
-retry:
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);
+ i2c->scl_rate = 400000;
+ rk29_i2c_clockrate(i2c);
for (i = 0; i < num; i++)
{
break;
}
}
- conr = readl(i2c->regs + I2C_CONR);
- conr &= I2C_CONR_MPORT_DISABLE;
- writel(conr, i2c->regs + I2C_CONR);
+ /*
if( --retry && num < 0)
{
- mdelay(1);
+ udelay(10000 * 1000/i2c->scl_rate);
goto retry;
}
+ */
if(num < 0)
- dev_err(i2c->dev, "i2c transfer err, client address is 0x%x", msgs[0].addr);
+ dev_err(i2c->dev, "i2c transfer err, client address is 0x%x [20110106]\n", msgs[0].addr);
return num;
}
return i2c->suspended;
}
EXPORT_SYMBOL(i2c_suspended);
-
-static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c)
+
+static void rk29_i2c_deinit_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);
+ return;
+}
+static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c)
+{
unsigned long opr = readl(i2c->regs + I2C_OPR);
+
opr |= I2C_OPR_RESET_STATUS;
writel(opr, i2c->regs + I2C_OPR);
+
+ udelay(10);
+ 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_clockrate(i2c);
rk29_i2c_disable_irqs(i2c);
-
- rk29_i2c_clockrate(i2c);
- i2c->io_init();
+ writel(0, i2c->regs + I2C_LCMR);
+ writel(0, i2c->regs + I2C_LCMR);
+
opr = readl(i2c->regs + I2C_OPR);
opr |= I2C_OPR_CORE_ENABLE;
writel(opr, i2c->regs + I2C_OPR);
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;
i2c->io_init = pdata->io_init;
pdata->io_init();
}
- rk29_i2c_init_hw(i2c);
i2c->irq = ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
i2c_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,
+ ret = request_irq(i2c->irq, rk29_i2c_irq, IRQF_DISABLED,
dev_name(&pdev->dev), i2c);
- if (ret != 0) {
- i2c_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
- goto err_iomap;
- }
+ if (ret != 0) {
+ i2c_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ goto err_iomap;
}
ret = rk29_i2c_register_cpufreq(i2c);
if (ret < 0) {
}
platform_set_drvdata(pdev, i2c);
-
- dev_info(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev));
+ rk29_i2c_init_hw(i2c);
+
+ dev_info(&pdev->dev, "%s: RK29 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);
+ free_irq(i2c->irq, i2c);
err_iomap:
iounmap(i2c->regs);
{
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
+
+ rk29_i2c_deinit_hw(i2c);
rk29_i2c_unregister_cpufreq(i2c);
i2c_del_adapter(&i2c->adap);
- if(i2c->mode == I2C_MODE_IRQ)
- free_irq(i2c->irq, i2c);
+ free_irq(i2c->irq, i2c);
clk_disable(i2c->clk);
clk_put(i2c->clk);
subsys_initcall(rk29_i2c_adap_init);
module_exit(rk29_i2c_adap_exit);
-MODULE_DESCRIPTION("Driver for RK2818 I2C Bus");
+MODULE_DESCRIPTION("Driver for RK29 I2C Bus");
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
MODULE_LICENSE("GPL");