summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-20 09:41:17 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-20 09:41:17 -0700
commitc3ad33c9bcb6616999953af76f16318120fe3691 (patch)
treea6b239cecc675693cfb5145493bd1b750ea360fb /drivers/i2c
parentfb091be08d1acf184e8801dfdcace6e0cb19b1fe (diff)
parentb5c80bc5d70a1ce5b071ed06dd95292b9de46f95 (diff)
downloadblackbird-op-linux-c3ad33c9bcb6616999953af76f16318120fe3691.tar.gz
blackbird-op-linux-c3ad33c9bcb6616999953af76f16318120fe3691.zip
Merge branch 'for-linus/i2c-2635' of git://git.fluff.org/bjdooks/linux
* 'for-linus/i2c-2635' of git://git.fluff.org/bjdooks/linux: (21 commits) i2c-highlander: remover superflous variable i2c-ibm-iic: drop NO_IRQ i2c-cpm: drop NO_IRQ i2c-mpc: drop NO_IRQ MAINTAINERS: add i2c tree for embedded platforms i2c-pxa: only define 'blue_murder'-function if DEBUG is #defined i2c-pxa: remove unused macro i2c-nomadik: fix operator precedence warning i2c-nomadik: release region when removed OMAP3: I2C: Clean up Errata 1p153 handling OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt omap: i2c: add a timeout to the busy waiting omap: i2c: make errata 1.153 workaround a separate function i2c-omap: add mpu wake up latency constraint in i2c omap: i2c: Add i2c support on omap4 platform i2c-bfin-twi: return completion in interrupt for smbus quick transfers i2c-bfin-twi: remove redundant retry i2c-bfin-twi: fix lost interrupts at high speeds i2c-bfin-twi: add debug output for error status i2c-bfin-twi: integrate timeout timer with completion interface ...
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c168
-rw-r--r--drivers/i2c/busses/i2c-cpm.c2
-rw-r--r--drivers/i2c/busses/i2c-highlander.c5
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c14
-rw-r--r--drivers/i2c/busses/i2c-mpc.c6
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c6
-rw-r--r--drivers/i2c/busses/i2c-omap.c265
-rw-r--r--drivers/i2c/busses/i2c-pxa.c26
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c19
9 files changed, 337 insertions, 174 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index f1e14dd590c9..fb26e5c67515 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -25,8 +25,6 @@
#include <asm/portmux.h>
#include <asm/irq.h>
-#define POLL_TIMEOUT (2 * HZ)
-
/* SMBus mode*/
#define TWI_I2C_MODE_STANDARD 1
#define TWI_I2C_MODE_STANDARDSUB 2
@@ -44,8 +42,6 @@ struct bfin_twi_iface {
int cur_mode;
int manual_stop;
int result;
- int timeout_count;
- struct timer_list timeout_timer;
struct i2c_adapter adap;
struct completion complete;
struct i2c_msg *pmsg;
@@ -85,14 +81,15 @@ static const u16 pin_req[2][3] = {
{P_TWI1_SCL, P_TWI1_SDA, 0},
};
-static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
+ unsigned short twi_int_status)
{
- unsigned short twi_int_status = read_INT_STAT(iface);
unsigned short mast_stat = read_MASTER_STAT(iface);
if (twi_int_status & XMTSERV) {
/* Transmit next data */
if (iface->writeNum > 0) {
+ SSYNC();
write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--;
}
@@ -114,10 +111,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
}
- SSYNC();
- /* Clear status */
- write_INT_STAT(iface, XMTSERV);
- SSYNC();
}
if (twi_int_status & RCVSERV) {
if (iface->readNum > 0) {
@@ -139,7 +132,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
} else if (iface->manual_stop) {
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | STOP);
- SSYNC();
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg + 1 < iface->msg_num) {
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
@@ -148,44 +140,37 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
else
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
- SSYNC();
}
- /* Clear interrupt source */
- write_INT_STAT(iface, RCVSERV);
- SSYNC();
}
if (twi_int_status & MERR) {
- write_INT_STAT(iface, MERR);
write_INT_MASK(iface, 0);
write_MASTER_STAT(iface, 0x3e);
write_MASTER_CTL(iface, 0);
- SSYNC();
iface->result = -EIO;
- /* if both err and complete int stats are set, return proper
- * results.
+
+ if (mast_stat & LOSTARB)
+ dev_dbg(&iface->adap.dev, "Lost Arbitration\n");
+ if (mast_stat & ANAK)
+ dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n");
+ if (mast_stat & DNAK)
+ dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n");
+ if (mast_stat & BUFRDERR)
+ dev_dbg(&iface->adap.dev, "Buffer Read Error\n");
+ if (mast_stat & BUFWRERR)
+ dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
+
+ /* If it is a quick transfer, only address without data,
+ * not an err, return 1.
*/
- if (twi_int_status & MCOMP) {
- write_INT_STAT(iface, MCOMP);
- write_INT_MASK(iface, 0);
- write_MASTER_CTL(iface, 0);
- SSYNC();
- /* If it is a quick transfer, only address bug no data,
- * not an err, return 1.
- */
- if (iface->writeNum == 0 && (mast_stat & BUFRDERR))
- iface->result = 1;
- /* If address not acknowledged return -1,
- * else return 0.
- */
- else if (!(mast_stat & ANAK))
- iface->result = 0;
- }
+ if (iface->cur_mode == TWI_I2C_MODE_STANDARD &&
+ iface->transPtr == NULL &&
+ (twi_int_status & MCOMP) && (mast_stat & DNAK))
+ iface->result = 1;
+
complete(&iface->complete);
return;
}
if (twi_int_status & MCOMP) {
- write_INT_STAT(iface, MCOMP);
- SSYNC();
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
if (iface->readNum == 0) {
/* set the read number to 1 and ask for manual
@@ -207,7 +192,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
/* remove restart bit and enable master receive */
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~RSTART);
- SSYNC();
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg+1 < iface->msg_num) {
iface->cur_msg++;
@@ -226,7 +210,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
write_XMT_DATA8(iface,
*(iface->transPtr++));
iface->writeNum--;
- SSYNC();
}
}
@@ -244,15 +227,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
/* remove restart bit and enable master receive */
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~RSTART);
- SSYNC();
} else {
iface->result = 1;
write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0);
- SSYNC();
- complete(&iface->complete);
}
}
+ complete(&iface->complete);
}
/* Interrupt handler */
@@ -260,38 +241,26 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
{
struct bfin_twi_iface *iface = dev_id;
unsigned long flags;
+ unsigned short twi_int_status;
spin_lock_irqsave(&iface->lock, flags);
- del_timer(&iface->timeout_timer);
- bfin_twi_handle_interrupt(iface);
- spin_unlock_irqrestore(&iface->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void bfin_twi_timeout(unsigned long data)
-{
- struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&iface->lock, flags);
- bfin_twi_handle_interrupt(iface);
- if (iface->result == 0) {
- iface->timeout_count--;
- if (iface->timeout_count > 0) {
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
- } else {
- iface->result = -1;
- complete(&iface->complete);
- }
+ while (1) {
+ twi_int_status = read_INT_STAT(iface);
+ if (!twi_int_status)
+ break;
+ /* Clear interrupt status */
+ write_INT_STAT(iface, twi_int_status);
+ bfin_twi_handle_interrupt(iface, twi_int_status);
+ SSYNC();
}
spin_unlock_irqrestore(&iface->lock, flags);
+ return IRQ_HANDLED;
}
/*
- * Generic i2c master transfer entrypoint
+ * One i2c master transfer
*/
-static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct bfin_twi_iface *iface = adap->algo_data;
@@ -319,7 +288,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
iface->transPtr = pmsg->buf;
iface->writeNum = iface->readNum = pmsg->len;
iface->result = 0;
- iface->timeout_count = 10;
init_completion(&(iface->complete));
/* Set Transmit device address */
write_MASTER_ADDR(iface, pmsg->addr);
@@ -358,30 +326,41 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
iface->manual_stop = 1;
}
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
-
/* Master enable */
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
SSYNC();
- wait_for_completion(&iface->complete);
-
- rc = iface->result;
+ while (!iface->result) {
+ if (!wait_for_completion_timeout(&iface->complete,
+ adap->timeout)) {
+ iface->result = -1;
+ dev_err(&adap->dev, "master transfer timeout\n");
+ }
+ }
- if (rc == 1)
- return num;
+ if (iface->result == 1)
+ rc = iface->cur_msg + 1;
else
- return rc;
+ rc = iface->result;
+
+ return rc;
}
/*
- * SMBus type transfer entrypoint
+ * Generic i2c master transfer entrypoint
*/
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ return bfin_twi_do_master_xfer(adap, msgs, num);
+}
-int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+/*
+ * One I2C SMBus transfer
+ */
+int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data)
{
@@ -469,7 +448,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
iface->manual_stop = 0;
iface->read_write = read_write;
iface->command = command;
- iface->timeout_count = 10;
init_completion(&(iface->complete));
/* FIFO Initiation. Data in FIFO should be discarded before
@@ -486,9 +464,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
write_MASTER_ADDR(iface, addr);
SSYNC();
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
-
switch (iface->cur_mode) {
case TWI_I2C_MODE_STANDARDSUB:
write_XMT_DATA8(iface, iface->command);
@@ -550,10 +525,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
else if (iface->readNum > 255) {
write_MASTER_CTL(iface, 0xff << 6);
iface->manual_stop = 1;
- } else {
- del_timer(&iface->timeout_timer);
+ } else
break;
- }
}
}
write_INT_MASK(iface, MCOMP | MERR |
@@ -569,7 +542,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
}
SSYNC();
- wait_for_completion(&iface->complete);
+ while (!iface->result) {
+ if (!wait_for_completion_timeout(&iface->complete,
+ adap->timeout)) {
+ iface->result = -1;
+ dev_err(&adap->dev, "smbus transfer timeout\n");
+ }
+ }
rc = (iface->result >= 0) ? 0 : -1;
@@ -577,6 +556,17 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
}
/*
+ * Generic I2C SMBus transfer entrypoint
+ */
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ return bfin_twi_do_smbus_xfer(adap, addr, flags,
+ read_write, command, size, data);
+}
+
+/*
* Return what the adapter supports
*/
static u32 bfin_twi_functionality(struct i2c_adapter *adap)
@@ -667,10 +657,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
goto out_error_no_irq;
}
- init_timer(&(iface->timeout_timer));
- iface->timeout_timer.function = bfin_twi_timeout;
- iface->timeout_timer.data = (unsigned long)iface;
-
p_adap = &iface->adap;
p_adap->nr = pdev->id;
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
@@ -678,6 +664,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
p_adap->algo_data = iface;
p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
p_adap->dev.parent = &pdev->dev;
+ p_adap->timeout = 5 * HZ;
+ p_adap->retries = 3;
rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
if (rc) {
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 9c2e10082b79..16948db38973 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -441,7 +441,7 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
init_waitqueue_head(&cpm->i2c_wait);
cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL);
- if (cpm->irq == NO_IRQ)
+ if (!cpm->irq)
return -EINVAL;
/* Install interrupt handler. */
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
index ce87a902c94d..3df1bc80f37a 100644
--- a/drivers/i2c/busses/i2c-highlander.c
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -282,7 +282,6 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
union i2c_smbus_data *data)
{
struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
- int read = read_write & I2C_SMBUS_READ;
u16 tmp;
init_completion(&dev->cmd_complete);
@@ -337,11 +336,11 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
highlander_i2c_done(dev);
/* Set slave address */
- iowrite16((addr << 1) | read, dev->base + SMSMADR);
+ iowrite16((addr << 1) | read_write, dev->base + SMSMADR);
highlander_i2c_command(dev, command, dev->buf_len);
- if (read)
+ if (read_write == I2C_SMBUS_READ)
return highlander_i2c_read(dev);
else
return highlander_i2c_write(dev);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index b1bc6e277d2a..2bef534cbff1 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -668,12 +668,12 @@ static int __devinit iic_request_irq(struct of_device *ofdev,
int irq;
if (iic_force_poll)
- return NO_IRQ;
+ return 0;
irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
- return NO_IRQ;
+ return 0;
}
/* Disable interrupts until we finish initialization, assumes
@@ -683,7 +683,7 @@ static int __devinit iic_request_irq(struct of_device *ofdev,
if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
/* Fallback to the polling mode */
- return NO_IRQ;
+ return 0;
}
return irq;
@@ -719,7 +719,7 @@ static int __devinit iic_probe(struct of_device *ofdev,
init_waitqueue_head(&dev->wq);
dev->irq = iic_request_irq(ofdev, dev);
- if (dev->irq == NO_IRQ)
+ if (!dev->irq)
dev_warn(&ofdev->dev, "using polling mode\n");
/* Board specific settings */
@@ -766,7 +766,7 @@ static int __devinit iic_probe(struct of_device *ofdev,
return 0;
error_cleanup:
- if (dev->irq != NO_IRQ) {
+ if (dev->irq) {
iic_interrupt_mode(dev, 0);
free_irq(dev->irq, dev);
}
@@ -790,7 +790,7 @@ static int __devexit iic_remove(struct of_device *ofdev)
i2c_del_adapter(&dev->adap);
- if (dev->irq != NO_IRQ) {
+ if (dev->irq) {
iic_interrupt_mode(dev, 0);
free_irq(dev->irq, dev);
}
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index f1321f763789..e86cef300c7d 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -118,7 +118,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
u32 x;
int result = 0;
- if (i2c->irq == NO_IRQ) {
+ if (!i2c->irq) {
while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
schedule();
if (time_after(jiffies, orig_jiffies + timeout)) {
@@ -568,7 +568,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
}
i2c->irq = irq_of_parse_and_map(op->node, 0);
- if (i2c->irq != NO_IRQ) { /* i2c->irq = NO_IRQ implies polling */
+ if (i2c->irq) { /* no i2c->irq implies polling */
result = request_irq(i2c->irq, mpc_i2c_isr,
IRQF_SHARED, "i2c-mpc", i2c);
if (result < 0) {
@@ -627,7 +627,7 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
i2c_del_adapter(&i2c->adap);
dev_set_drvdata(&op->dev, NULL);
- if (i2c->irq != NO_IRQ)
+ if (i2c->irq)
free_irq(i2c->irq, i2c);
irq_dispose_mapping(i2c->irq);
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index a4f8d33fa389..73de8ade10b1 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -704,7 +704,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
case I2C_IT_MTD:
case I2C_IT_MTDWS:
if (dev->cli.operation == I2C_READ) {
- while (!readl(dev->virtbase + I2C_RISR) & I2C_IT_RXFE) {
+ while (!(readl(dev->virtbase + I2C_RISR)
+ & I2C_IT_RXFE)) {
if (dev->cli.count == 0)
break;
*dev->cli.buffer =
@@ -914,6 +915,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
static int __devexit nmk_i2c_remove(struct platform_device *pdev)
{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
i2c_del_adapter(&dev->adap);
@@ -924,6 +926,8 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
free_irq(dev->irq, dev);
iounmap(dev->virtbase);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
clk_disable(dev->clk);
clk_put(dev->clk);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 389ac6032a7b..7674efb55378 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -38,6 +38,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/i2c-omap.h>
/* I2C controller revisions */
#define OMAP_I2C_REV_2 0x20
@@ -45,29 +46,37 @@
/* I2C controller revisions present on specific hardware */
#define OMAP_I2C_REV_ON_2430 0x36
#define OMAP_I2C_REV_ON_3430 0x3C
+#define OMAP_I2C_REV_ON_4430 0x40
/* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
-#define OMAP_I2C_REV_REG 0x00
-#define OMAP_I2C_IE_REG 0x01
-#define OMAP_I2C_STAT_REG 0x02
-#define OMAP_I2C_IV_REG 0x03
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
-#define OMAP_I2C_WE_REG 0x03
-#define OMAP_I2C_SYSS_REG 0x04
-#define OMAP_I2C_BUF_REG 0x05
-#define OMAP_I2C_CNT_REG 0x06
-#define OMAP_I2C_DATA_REG 0x07
-#define OMAP_I2C_SYSC_REG 0x08
-#define OMAP_I2C_CON_REG 0x09
-#define OMAP_I2C_OA_REG 0x0a
-#define OMAP_I2C_SA_REG 0x0b
-#define OMAP_I2C_PSC_REG 0x0c
-#define OMAP_I2C_SCLL_REG 0x0d
-#define OMAP_I2C_SCLH_REG 0x0e
-#define OMAP_I2C_SYSTEST_REG 0x0f
-#define OMAP_I2C_BUFSTAT_REG 0x10
+enum {
+ OMAP_I2C_REV_REG = 0,
+ OMAP_I2C_IE_REG,
+ OMAP_I2C_STAT_REG,
+ OMAP_I2C_IV_REG,
+ OMAP_I2C_WE_REG,
+ OMAP_I2C_SYSS_REG,
+ OMAP_I2C_BUF_REG,
+ OMAP_I2C_CNT_REG,
+ OMAP_I2C_DATA_REG,
+ OMAP_I2C_SYSC_REG,
+ OMAP_I2C_CON_REG,
+ OMAP_I2C_OA_REG,
+ OMAP_I2C_SA_REG,
+ OMAP_I2C_PSC_REG,
+ OMAP_I2C_SCLL_REG,
+ OMAP_I2C_SCLH_REG,
+ OMAP_I2C_SYSTEST_REG,
+ OMAP_I2C_BUFSTAT_REG,
+ OMAP_I2C_REVNB_LO,
+ OMAP_I2C_REVNB_HI,
+ OMAP_I2C_IRQSTATUS_RAW,
+ OMAP_I2C_IRQENABLE_SET,
+ OMAP_I2C_IRQENABLE_CLR,
+};
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
@@ -157,6 +166,9 @@
#define SYSC_IDLEMODE_SMART 0x2
#define SYSC_CLOCKACTIVITY_FCLK 0x2
+/* Errata definitions */
+#define I2C_OMAP_ERRATA_I207 (1 << 0)
+#define I2C_OMAP3_1P153 (1 << 1)
struct omap_i2c_dev {
struct device *dev;
@@ -167,9 +179,13 @@ struct omap_i2c_dev {
struct clk *fclk; /* Functional clock */
struct completion cmd_complete;
struct resource *ioarea;
+ u32 latency; /* maximum mpu wkup latency */
+ void (*set_mpu_wkup_lat)(struct device *dev,
+ long latency);
u32 speed; /* Speed of bus in Khz */
u16 cmd_err;
u8 *buf;
+ u8 *regs;
size_t buf_len;
struct i2c_adapter adapter;
u8 fifo_size; /* use as flag and value
@@ -186,17 +202,67 @@ struct omap_i2c_dev {
u16 bufstate;
u16 syscstate;
u16 westate;
+ u16 errata;
+};
+
+const static u8 reg_map[] = {
+ [OMAP_I2C_REV_REG] = 0x00,
+ [OMAP_I2C_IE_REG] = 0x01,
+ [OMAP_I2C_STAT_REG] = 0x02,
+ [OMAP_I2C_IV_REG] = 0x03,
+ [OMAP_I2C_WE_REG] = 0x03,
+ [OMAP_I2C_SYSS_REG] = 0x04,
+ [OMAP_I2C_BUF_REG] = 0x05,
+ [OMAP_I2C_CNT_REG] = 0x06,
+ [OMAP_I2C_DATA_REG] = 0x07,
+ [OMAP_I2C_SYSC_REG] = 0x08,
+ [OMAP_I2C_CON_REG] = 0x09,
+ [OMAP_I2C_OA_REG] = 0x0a,
+ [OMAP_I2C_SA_REG] = 0x0b,
+ [OMAP_I2C_PSC_REG] = 0x0c,
+ [OMAP_I2C_SCLL_REG] = 0x0d,
+ [OMAP_I2C_SCLH_REG] = 0x0e,
+ [OMAP_I2C_SYSTEST_REG] = 0x0f,
+ [OMAP_I2C_BUFSTAT_REG] = 0x10,
+};
+
+const static u8 omap4_reg_map[] = {
+ [OMAP_I2C_REV_REG] = 0x04,
+ [OMAP_I2C_IE_REG] = 0x2c,
+ [OMAP_I2C_STAT_REG] = 0x28,
+ [OMAP_I2C_IV_REG] = 0x34,
+ [OMAP_I2C_WE_REG] = 0x34,
+ [OMAP_I2C_SYSS_REG] = 0x90,
+ [OMAP_I2C_BUF_REG] = 0x94,
+ [OMAP_I2C_CNT_REG] = 0x98,
+ [OMAP_I2C_DATA_REG] = 0x9c,
+ [OMAP_I2C_SYSC_REG] = 0x20,
+ [OMAP_I2C_CON_REG] = 0xa4,
+ [OMAP_I2C_OA_REG] = 0xa8,
+ [OMAP_I2C_SA_REG] = 0xac,
+ [OMAP_I2C_PSC_REG] = 0xb0,
+ [OMAP_I2C_SCLL_REG] = 0xb4,
+ [OMAP_I2C_SCLH_REG] = 0xb8,
+ [OMAP_I2C_SYSTEST_REG] = 0xbC,
+ [OMAP_I2C_BUFSTAT_REG] = 0xc0,
+ [OMAP_I2C_REVNB_LO] = 0x00,
+ [OMAP_I2C_REVNB_HI] = 0x04,
+ [OMAP_I2C_IRQSTATUS_RAW] = 0x24,
+ [OMAP_I2C_IRQENABLE_SET] = 0x2c,
+ [OMAP_I2C_IRQENABLE_CLR] = 0x30,
};
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
int reg, u16 val)
{
- __raw_writew(val, i2c_dev->base + (reg << i2c_dev->reg_shift));
+ __raw_writew(val, i2c_dev->base +
+ (i2c_dev->regs[reg] << i2c_dev->reg_shift));
}
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
{
- return __raw_readw(i2c_dev->base + (reg << i2c_dev->reg_shift));
+ return __raw_readw(i2c_dev->base +
+ (i2c_dev->regs[reg] << i2c_dev->reg_shift));
}
static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
@@ -265,7 +331,11 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
WARN_ON(dev->idle);
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
- omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+ if (dev->rev >= OMAP_I2C_REV_ON_4430)
+ omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
+ else
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+
if (dev->rev < OMAP_I2C_REV_2) {
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
} else {
@@ -330,7 +400,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* REVISIT: Some wkup sources might not be needed.
*/
dev->westate = OMAP_I2C_WE_ALL;
- omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+ if (dev->rev < OMAP_I2C_REV_ON_4430)
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
+ dev->westate);
}
}
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
@@ -357,7 +429,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
psc = fclk_rate / 12000000;
}
- if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
/*
* HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -430,6 +502,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
/* Take the I2C module out of reset: */
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ dev->errata = 0;
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx())
+ dev->errata |= I2C_OMAP_ERRATA_I207;
+
/* Enable interrupts */
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -539,8 +616,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
* REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it.
*/
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, dev->latency);
r = wait_for_completion_timeout(&dev->cmd_complete,
OMAP_I2C_TIMEOUT);
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, -1);
dev->buf_len = 0;
if (r < 0)
return r;
@@ -623,6 +704,34 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
}
+static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
+{
+ /*
+ * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
+ * Not applicable for OMAP4.
+ * Under certain rare conditions, RDR could be set again
+ * when the bus is busy, then ignore the interrupt and
+ * clear the interrupt.
+ */
+ if (stat & OMAP_I2C_STAT_RDR) {
+ /* Step 1: If RDR is set, clear it */
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+
+ /* Step 2: */
+ if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
+ & OMAP_I2C_STAT_BB)) {
+
+ /* Step 3: */
+ if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
+ & OMAP_I2C_STAT_RDR) {
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+ dev_dbg(dev->dev, "RDR when bus is busy.\n");
+ }
+
+ }
+ }
+}
+
/* rev1 devices are apparently only on some 15xx */
#ifdef CONFIG_ARCH_OMAP15XX
@@ -684,6 +793,35 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
#define omap_i2c_rev1_isr NULL
#endif
+/*
+ * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
+ * data to DATA_REG. Otherwise some data bytes can be lost while transferring
+ * them from the memory to the I2C interface.
+ */
+static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
+{
+ unsigned long timeout = 10000;
+
+ while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
+ if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
+ OMAP_I2C_STAT_XDR));
+ *err |= OMAP_I2C_STAT_XUDF;
+ return -ETIMEDOUT;
+ }
+
+ cpu_relax();
+ *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ }
+
+ if (!timeout) {
+ dev_err(dev->dev, "timeout waiting on XUDF bit\n");
+ return 0;
+ }
+
+ return 0;
+}
+
static irqreturn_t
omap_i2c_isr(int this_irq, void *dev_id)
{
@@ -733,6 +871,10 @@ complete:
}
if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
u8 num_bytes = 1;
+
+ if (dev->errata & I2C_OMAP_ERRATA_I207)
+ i2c_omap_errata_i207(dev, stat);
+
if (dev->fifo_size) {
if (stat & OMAP_I2C_STAT_RRDY)
num_bytes = dev->fifo_size;
@@ -747,9 +889,12 @@ complete:
if (dev->buf_len) {
*dev->buf++ = w;
dev->buf_len--;
- /* Data reg from 2430 is 8 bit wide */
- if (!cpu_is_omap2430() &&
- !cpu_is_omap34xx()) {
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (cpu_class_is_omap1() ||
+ cpu_is_omap2420()) {
if (dev->buf_len) {
*dev->buf++ = w >> 8;
dev->buf_len--;
@@ -787,9 +932,12 @@ complete:
if (dev->buf_len) {
w = *dev->buf++;
dev->buf_len--;
- /* Data reg from 2430 is 8 bit wide */
- if (!cpu_is_omap2430() &&
- !cpu_is_omap34xx()) {
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (cpu_class_is_omap1() ||
+ cpu_is_omap2420()) {
if (dev->buf_len) {
w |= *dev->buf++ << 8;
dev->buf_len--;
@@ -807,25 +955,9 @@ complete:
break;
}
- /*
- * OMAP3430 Errata 1.153: When an XRDY/XDR
- * is hit, wait for XUDF before writing data
- * to DATA_REG. Otherwise some data bytes can
- * be lost while transferring them from the
- * memory to the I2C interface.
- */
-
- if (dev->rev <= OMAP_I2C_REV_ON_3430) {
- while (!(stat & OMAP_I2C_STAT_XUDF)) {
- if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
- omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
- err |= OMAP_I2C_STAT_XUDF;
- goto complete;
- }
- cpu_relax();
- stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
- }
- }
+ if ((dev->errata & I2C_OMAP3_1P153) &&
+ errata_omap3_1p153(dev, &stat, &err))
+ goto complete;
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
}
@@ -857,6 +989,7 @@ omap_i2c_probe(struct platform_device *pdev)
struct omap_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem, *irq, *ioarea;
+ struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
irq_handler_t isr;
int r;
u32 speed = 0;
@@ -886,10 +1019,13 @@ omap_i2c_probe(struct platform_device *pdev)
goto err_release_region;
}
- if (pdev->dev.platform_data != NULL)
- speed = *(u32 *)pdev->dev.platform_data;
- else
- speed = 100; /* Defualt speed */
+ if (pdata != NULL) {
+ speed = pdata->clkrate;
+ dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
+ } else {
+ speed = 100; /* Default speed */
+ dev->set_mpu_wkup_lat = NULL;
+ }
dev->speed = speed;
dev->idle = 1;
@@ -905,17 +1041,27 @@ omap_i2c_probe(struct platform_device *pdev)
if (cpu_is_omap7xx())
dev->reg_shift = 1;
+ else if (cpu_is_omap44xx())
+ dev->reg_shift = 0;
else
dev->reg_shift = 2;
if ((r = omap_i2c_get_clocks(dev)) != 0)
goto err_iounmap;
+ if (cpu_is_omap44xx())
+ dev->regs = (u8 *) omap4_reg_map;
+ else
+ dev->regs = (u8 *) reg_map;
+
omap_i2c_unidle(dev);
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
- if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ if (dev->rev <= OMAP_I2C_REV_ON_3430)
+ dev->errata |= I2C_OMAP3_1P153;
+
+ if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
u16 s;
/* Set up the fifo size - Get total size */
@@ -927,8 +1073,17 @@ omap_i2c_probe(struct platform_device *pdev)
* size. This is to ensure that we can handle the status on int
* call back latencies.
*/
- dev->fifo_size = (dev->fifo_size / 2);
- dev->b_hw = 1; /* Enable hardware fixes */
+ if (dev->rev >= OMAP_I2C_REV_ON_4430) {
+ dev->fifo_size = 0;
+ dev->b_hw = 0; /* Disable hardware fixes */
+ } else {
+ dev->fifo_size = (dev->fifo_size / 2);
+ dev->b_hw = 1; /* Enable hardware fixes */
+ }
+ /* calculate wakeup latency constraint for MPU */
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->latency = (1000000 * dev->fifo_size) /
+ (1000 * speed / 8);
}
/* reset ASAP, clearing any IRQs */
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 14d249f5ed3f..fbde6f614059 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -209,18 +209,6 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
}
#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__)
-#else
-#define i2c_debug 0
-
-#define show_state(i2c) do { } while (0)
-#define decode_ISR(val) do { } while (0)
-#define decode_ICR(val) do { } while (0)
-#endif
-
-#define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0)
-
-static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
-static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
{
@@ -236,6 +224,20 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
printk("\n");
}
+#else /* ifdef DEBUG */
+
+#define i2c_debug 0
+
+#define show_state(i2c) do { } while (0)
+#define decode_ISR(val) do { } while (0)
+#define decode_ICR(val) do { } while (0)
+#define i2c_pxa_scream_blue_murder(i2c, why) do { } while (0)
+
+#endif /* ifdef DEBUG / else */
+
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
+
static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
{
return !(readl(_ICR(i2c)) & ICR_SCLE);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index d27072b2249f..ec3256cce91e 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -482,7 +482,8 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
- unsigned long timeout;
+ unsigned long iicstat, timeout;
+ int spins = 20;
int ret;
if (i2c->suspended)
@@ -521,7 +522,21 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
/* ensure the stop has been through the bus */
- msleep(1);
+ dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+ /* first, try busy waiting briefly */
+ do {
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ } while ((iicstat & S3C2410_IICSTAT_START) && --spins);
+
+ /* if that timed out sleep */
+ if (!spins) {
+ msleep(1);
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ }
+
+ if (iicstat & S3C2410_IICSTAT_START)
+ dev_warn(i2c->dev, "timeout waiting for bus idle\n");
out:
return ret;
OpenPOWER on IntegriCloud