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
  ...
This commit is contained in:
Linus Torvalds 2010-05-20 09:41:17 -07:00
commit c3ad33c9bc
12 changed files with 374 additions and 186 deletions

View File

@ -2747,6 +2747,7 @@ M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/ W: http://i2c.wiki.kernel.org/
T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/ T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
T: git git://git.fluff.org/bjdooks/linux.git
S: Maintained S: Maintained
F: Documentation/i2c/ F: Documentation/i2c/
F: drivers/i2c/ F: drivers/i2c/

View File

@ -26,9 +26,12 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-omap.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <plat/mux.h> #include <plat/mux.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <plat/omap-pm.h>
#define OMAP_I2C_SIZE 0x3f #define OMAP_I2C_SIZE 0x3f
#define OMAP1_I2C_BASE 0xfffb3800 #define OMAP1_I2C_BASE 0xfffb3800
@ -70,14 +73,14 @@ static struct resource i2c_resources[][2] = {
}, \ }, \
} }
static u32 i2c_rate[ARRAY_SIZE(i2c_resources)]; static struct omap_i2c_bus_platform_data i2c_pdata[ARRAY_SIZE(i2c_resources)];
static struct platform_device omap_i2c_devices[] = { static struct platform_device omap_i2c_devices[] = {
I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]), I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]), I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]),
#endif #endif
#if defined(CONFIG_ARCH_OMAP3) #if defined(CONFIG_ARCH_OMAP3)
I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]), I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]),
#endif #endif
}; };
@ -100,10 +103,12 @@ static int __init omap_i2c_nr_ports(void)
static int __init omap_i2c_add_bus(int bus_id) static int __init omap_i2c_add_bus(int bus_id)
{ {
struct platform_device *pdev; struct platform_device *pdev;
struct omap_i2c_bus_platform_data *pd;
struct resource *res; struct resource *res;
resource_size_t base, irq; resource_size_t base, irq;
pdev = &omap_i2c_devices[bus_id - 1]; pdev = &omap_i2c_devices[bus_id - 1];
pd = pdev->dev.platform_data;
if (bus_id == 1) { if (bus_id == 1) {
res = pdev->resource; res = pdev->resource;
if (cpu_class_is_omap1()) { if (cpu_class_is_omap1()) {
@ -123,6 +128,15 @@ static int __init omap_i2c_add_bus(int bus_id)
if (cpu_class_is_omap2()) if (cpu_class_is_omap2())
omap2_i2c_mux_pins(bus_id); omap2_i2c_mux_pins(bus_id);
/*
* When waiting for completion of a i2c transfer, we need to
* set a wake up latency constraint for the MPU. This is to
* ensure quick enough wakeup from idle, when transfer
* completes.
*/
if (cpu_is_omap34xx())
pd->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat;
return platform_device_register(pdev); return platform_device_register(pdev);
} }
@ -146,8 +160,8 @@ static int __init omap_i2c_bus_setup(char *str)
get_options(str, 3, ints); get_options(str, 3, ints);
if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports) if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
return 0; return 0;
i2c_rate[ints[1] - 1] = ints[2]; i2c_pdata[ints[1] - 1].clkrate = ints[2];
i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP; i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
return 1; return 1;
} }
@ -161,9 +175,9 @@ static int __init omap_register_i2c_bus_cmdline(void)
{ {
int i, err = 0; int i, err = 0;
for (i = 0; i < ARRAY_SIZE(i2c_rate); i++) for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
if (i2c_rate[i] & OMAP_I2C_CMDLINE_SETUP) { if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
i2c_rate[i] &= ~OMAP_I2C_CMDLINE_SETUP; i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
err = omap_i2c_add_bus(i + 1); err = omap_i2c_add_bus(i + 1);
if (err) if (err)
goto out; goto out;
@ -197,9 +211,10 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
return err; return err;
} }
if (!i2c_rate[bus_id - 1]) if (!i2c_pdata[bus_id - 1].clkrate)
i2c_rate[bus_id - 1] = clkrate; i2c_pdata[bus_id - 1].clkrate = clkrate;
i2c_rate[bus_id - 1] &= ~OMAP_I2C_CMDLINE_SETUP;
i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
return omap_i2c_add_bus(bus_id); return omap_i2c_add_bus(bus_id);
} }

View File

@ -25,8 +25,6 @@
#include <asm/portmux.h> #include <asm/portmux.h>
#include <asm/irq.h> #include <asm/irq.h>
#define POLL_TIMEOUT (2 * HZ)
/* SMBus mode*/ /* SMBus mode*/
#define TWI_I2C_MODE_STANDARD 1 #define TWI_I2C_MODE_STANDARD 1
#define TWI_I2C_MODE_STANDARDSUB 2 #define TWI_I2C_MODE_STANDARDSUB 2
@ -44,8 +42,6 @@ struct bfin_twi_iface {
int cur_mode; int cur_mode;
int manual_stop; int manual_stop;
int result; int result;
int timeout_count;
struct timer_list timeout_timer;
struct i2c_adapter adap; struct i2c_adapter adap;
struct completion complete; struct completion complete;
struct i2c_msg *pmsg; struct i2c_msg *pmsg;
@ -85,14 +81,15 @@ static const u16 pin_req[2][3] = {
{P_TWI1_SCL, P_TWI1_SDA, 0}, {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); unsigned short mast_stat = read_MASTER_STAT(iface);
if (twi_int_status & XMTSERV) { if (twi_int_status & XMTSERV) {
/* Transmit next data */ /* Transmit next data */
if (iface->writeNum > 0) { if (iface->writeNum > 0) {
SSYNC();
write_XMT_DATA8(iface, *(iface->transPtr++)); write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--; iface->writeNum--;
} }
@ -114,10 +111,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
write_MASTER_CTL(iface, write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) | RSTART) & ~MDIR); (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
} }
SSYNC();
/* Clear status */
write_INT_STAT(iface, XMTSERV);
SSYNC();
} }
if (twi_int_status & RCVSERV) { if (twi_int_status & RCVSERV) {
if (iface->readNum > 0) { if (iface->readNum > 0) {
@ -139,7 +132,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
} else if (iface->manual_stop) { } else if (iface->manual_stop) {
write_MASTER_CTL(iface, write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | STOP); read_MASTER_CTL(iface) | STOP);
SSYNC();
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg + 1 < iface->msg_num) { iface->cur_msg + 1 < iface->msg_num) {
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) 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 else
write_MASTER_CTL(iface, write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) | RSTART) & ~MDIR); (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
SSYNC();
} }
/* Clear interrupt source */
write_INT_STAT(iface, RCVSERV);
SSYNC();
} }
if (twi_int_status & MERR) { if (twi_int_status & MERR) {
write_INT_STAT(iface, MERR);
write_INT_MASK(iface, 0); write_INT_MASK(iface, 0);
write_MASTER_STAT(iface, 0x3e); write_MASTER_STAT(iface, 0x3e);
write_MASTER_CTL(iface, 0); write_MASTER_CTL(iface, 0);
SSYNC();
iface->result = -EIO; 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) { if (iface->cur_mode == TWI_I2C_MODE_STANDARD &&
write_INT_STAT(iface, MCOMP); iface->transPtr == NULL &&
write_INT_MASK(iface, 0); (twi_int_status & MCOMP) && (mast_stat & DNAK))
write_MASTER_CTL(iface, 0); iface->result = 1;
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;
}
complete(&iface->complete); complete(&iface->complete);
return; return;
} }
if (twi_int_status & MCOMP) { if (twi_int_status & MCOMP) {
write_INT_STAT(iface, MCOMP);
SSYNC();
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
if (iface->readNum == 0) { if (iface->readNum == 0) {
/* set the read number to 1 and ask for manual /* 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 */ /* remove restart bit and enable master receive */
write_MASTER_CTL(iface, write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~RSTART); read_MASTER_CTL(iface) & ~RSTART);
SSYNC();
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg+1 < iface->msg_num) { iface->cur_msg+1 < iface->msg_num) {
iface->cur_msg++; iface->cur_msg++;
@ -226,7 +210,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
write_XMT_DATA8(iface, write_XMT_DATA8(iface,
*(iface->transPtr++)); *(iface->transPtr++));
iface->writeNum--; 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 */ /* remove restart bit and enable master receive */
write_MASTER_CTL(iface, write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~RSTART); read_MASTER_CTL(iface) & ~RSTART);
SSYNC();
} else { } else {
iface->result = 1; iface->result = 1;
write_INT_MASK(iface, 0); write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0); write_MASTER_CTL(iface, 0);
SSYNC();
complete(&iface->complete);
} }
} }
complete(&iface->complete);
} }
/* Interrupt handler */ /* 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; struct bfin_twi_iface *iface = dev_id;
unsigned long flags; unsigned long flags;
unsigned short twi_int_status;
spin_lock_irqsave(&iface->lock, flags); spin_lock_irqsave(&iface->lock, flags);
del_timer(&iface->timeout_timer); while (1) {
bfin_twi_handle_interrupt(iface); 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); spin_unlock_irqrestore(&iface->lock, flags);
return IRQ_HANDLED; 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);
}
}
spin_unlock_irqrestore(&iface->lock, flags);
}
/* /*
* 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 i2c_msg *msgs, int num)
{ {
struct bfin_twi_iface *iface = adap->algo_data; 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->transPtr = pmsg->buf;
iface->writeNum = iface->readNum = pmsg->len; iface->writeNum = iface->readNum = pmsg->len;
iface->result = 0; iface->result = 0;
iface->timeout_count = 10;
init_completion(&(iface->complete)); init_completion(&(iface->complete));
/* Set Transmit device address */ /* Set Transmit device address */
write_MASTER_ADDR(iface, pmsg->addr); 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->manual_stop = 1;
} }
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
add_timer(&iface->timeout_timer);
/* Master enable */ /* Master enable */
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
SSYNC(); 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, "master transfer timeout\n");
}
}
rc = iface->result; if (iface->result == 1)
rc = iface->cur_msg + 1;
if (rc == 1)
return num;
else 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, unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data) 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->manual_stop = 0;
iface->read_write = read_write; iface->read_write = read_write;
iface->command = command; iface->command = command;
iface->timeout_count = 10;
init_completion(&(iface->complete)); init_completion(&(iface->complete));
/* FIFO Initiation. Data in FIFO should be discarded before /* 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); write_MASTER_ADDR(iface, addr);
SSYNC(); SSYNC();
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
add_timer(&iface->timeout_timer);
switch (iface->cur_mode) { switch (iface->cur_mode) {
case TWI_I2C_MODE_STANDARDSUB: case TWI_I2C_MODE_STANDARDSUB:
write_XMT_DATA8(iface, iface->command); 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) { else if (iface->readNum > 255) {
write_MASTER_CTL(iface, 0xff << 6); write_MASTER_CTL(iface, 0xff << 6);
iface->manual_stop = 1; iface->manual_stop = 1;
} else { } else
del_timer(&iface->timeout_timer);
break; break;
}
} }
} }
write_INT_MASK(iface, MCOMP | MERR | write_INT_MASK(iface, MCOMP | MERR |
@ -569,13 +542,30 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
} }
SSYNC(); 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; rc = (iface->result >= 0) ? 0 : -1;
return rc; return rc;
} }
/*
* 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 * Return what the adapter supports
*/ */
@ -667,10 +657,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
goto out_error_no_irq; 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 = &iface->adap;
p_adap->nr = pdev->id; p_adap->nr = pdev->id;
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name)); 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->algo_data = iface;
p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
p_adap->dev.parent = &pdev->dev; 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"); rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
if (rc) { if (rc) {

View File

@ -441,7 +441,7 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
init_waitqueue_head(&cpm->i2c_wait); init_waitqueue_head(&cpm->i2c_wait);
cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL); cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL);
if (cpm->irq == NO_IRQ) if (!cpm->irq)
return -EINVAL; return -EINVAL;
/* Install interrupt handler. */ /* Install interrupt handler. */

View File

@ -282,7 +282,6 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
union i2c_smbus_data *data) union i2c_smbus_data *data)
{ {
struct highlander_i2c_dev *dev = i2c_get_adapdata(adap); struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
int read = read_write & I2C_SMBUS_READ;
u16 tmp; u16 tmp;
init_completion(&dev->cmd_complete); 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); highlander_i2c_done(dev);
/* Set slave address */ /* 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); highlander_i2c_command(dev, command, dev->buf_len);
if (read) if (read_write == I2C_SMBUS_READ)
return highlander_i2c_read(dev); return highlander_i2c_read(dev);
else else
return highlander_i2c_write(dev); return highlander_i2c_write(dev);

View File

@ -668,12 +668,12 @@ static int __devinit iic_request_irq(struct of_device *ofdev,
int irq; int irq;
if (iic_force_poll) if (iic_force_poll)
return NO_IRQ; return 0;
irq = irq_of_parse_and_map(np, 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"); dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
return NO_IRQ; return 0;
} }
/* Disable interrupts until we finish initialization, assumes /* 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)) { if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
dev_err(&ofdev->dev, "request_irq %d failed\n", irq); dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
/* Fallback to the polling mode */ /* Fallback to the polling mode */
return NO_IRQ; return 0;
} }
return irq; return irq;
@ -719,7 +719,7 @@ static int __devinit iic_probe(struct of_device *ofdev,
init_waitqueue_head(&dev->wq); init_waitqueue_head(&dev->wq);
dev->irq = iic_request_irq(ofdev, dev); dev->irq = iic_request_irq(ofdev, dev);
if (dev->irq == NO_IRQ) if (!dev->irq)
dev_warn(&ofdev->dev, "using polling mode\n"); dev_warn(&ofdev->dev, "using polling mode\n");
/* Board specific settings */ /* Board specific settings */
@ -766,7 +766,7 @@ static int __devinit iic_probe(struct of_device *ofdev,
return 0; return 0;
error_cleanup: error_cleanup:
if (dev->irq != NO_IRQ) { if (dev->irq) {
iic_interrupt_mode(dev, 0); iic_interrupt_mode(dev, 0);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
} }
@ -790,7 +790,7 @@ static int __devexit iic_remove(struct of_device *ofdev)
i2c_del_adapter(&dev->adap); i2c_del_adapter(&dev->adap);
if (dev->irq != NO_IRQ) { if (dev->irq) {
iic_interrupt_mode(dev, 0); iic_interrupt_mode(dev, 0);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
} }

View File

@ -118,7 +118,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
u32 x; u32 x;
int result = 0; int result = 0;
if (i2c->irq == NO_IRQ) { if (!i2c->irq) {
while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
schedule(); schedule();
if (time_after(jiffies, orig_jiffies + timeout)) { 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); 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, result = request_irq(i2c->irq, mpc_i2c_isr,
IRQF_SHARED, "i2c-mpc", i2c); IRQF_SHARED, "i2c-mpc", i2c);
if (result < 0) { if (result < 0) {
@ -627,7 +627,7 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
i2c_del_adapter(&i2c->adap); i2c_del_adapter(&i2c->adap);
dev_set_drvdata(&op->dev, NULL); dev_set_drvdata(&op->dev, NULL);
if (i2c->irq != NO_IRQ) if (i2c->irq)
free_irq(i2c->irq, i2c); free_irq(i2c->irq, i2c);
irq_dispose_mapping(i2c->irq); irq_dispose_mapping(i2c->irq);

View File

@ -704,7 +704,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
case I2C_IT_MTD: case I2C_IT_MTD:
case I2C_IT_MTDWS: case I2C_IT_MTDWS:
if (dev->cli.operation == I2C_READ) { 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) if (dev->cli.count == 0)
break; break;
*dev->cli.buffer = *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) 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); struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
i2c_del_adapter(&dev->adap); 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); i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
iounmap(dev->virtbase); iounmap(dev->virtbase);
if (res)
release_mem_region(res->start, resource_size(res));
clk_disable(dev->clk); clk_disable(dev->clk);
clk_put(dev->clk); clk_put(dev->clk);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);

View File

@ -38,6 +38,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c-omap.h>
/* I2C controller revisions */ /* I2C controller revisions */
#define OMAP_I2C_REV_2 0x20 #define OMAP_I2C_REV_2 0x20
@ -45,29 +46,37 @@
/* I2C controller revisions present on specific hardware */ /* I2C controller revisions present on specific hardware */
#define OMAP_I2C_REV_ON_2430 0x36 #define OMAP_I2C_REV_ON_2430 0x36
#define OMAP_I2C_REV_ON_3430 0x3C #define OMAP_I2C_REV_ON_3430 0x3C
#define OMAP_I2C_REV_ON_4430 0x40
/* timeout waiting for the controller to respond */ /* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) #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) */ /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
#define OMAP_I2C_WE_REG 0x03 enum {
#define OMAP_I2C_SYSS_REG 0x04 OMAP_I2C_REV_REG = 0,
#define OMAP_I2C_BUF_REG 0x05 OMAP_I2C_IE_REG,
#define OMAP_I2C_CNT_REG 0x06 OMAP_I2C_STAT_REG,
#define OMAP_I2C_DATA_REG 0x07 OMAP_I2C_IV_REG,
#define OMAP_I2C_SYSC_REG 0x08 OMAP_I2C_WE_REG,
#define OMAP_I2C_CON_REG 0x09 OMAP_I2C_SYSS_REG,
#define OMAP_I2C_OA_REG 0x0a OMAP_I2C_BUF_REG,
#define OMAP_I2C_SA_REG 0x0b OMAP_I2C_CNT_REG,
#define OMAP_I2C_PSC_REG 0x0c OMAP_I2C_DATA_REG,
#define OMAP_I2C_SCLL_REG 0x0d OMAP_I2C_SYSC_REG,
#define OMAP_I2C_SCLH_REG 0x0e OMAP_I2C_CON_REG,
#define OMAP_I2C_SYSTEST_REG 0x0f OMAP_I2C_OA_REG,
#define OMAP_I2C_BUFSTAT_REG 0x10 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): */ /* I2C Interrupt Enable Register (OMAP_I2C_IE): */
#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ #define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
@ -157,6 +166,9 @@
#define SYSC_IDLEMODE_SMART 0x2 #define SYSC_IDLEMODE_SMART 0x2
#define SYSC_CLOCKACTIVITY_FCLK 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 omap_i2c_dev {
struct device *dev; struct device *dev;
@ -167,9 +179,13 @@ struct omap_i2c_dev {
struct clk *fclk; /* Functional clock */ struct clk *fclk; /* Functional clock */
struct completion cmd_complete; struct completion cmd_complete;
struct resource *ioarea; 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 */ u32 speed; /* Speed of bus in Khz */
u16 cmd_err; u16 cmd_err;
u8 *buf; u8 *buf;
u8 *regs;
size_t buf_len; size_t buf_len;
struct i2c_adapter adapter; struct i2c_adapter adapter;
u8 fifo_size; /* use as flag and value u8 fifo_size; /* use as flag and value
@ -186,17 +202,67 @@ struct omap_i2c_dev {
u16 bufstate; u16 bufstate;
u16 syscstate; u16 syscstate;
u16 westate; 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, static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
int reg, u16 val) 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) 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) 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); WARN_ON(dev->idle);
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); 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) { if (dev->rev < OMAP_I2C_REV_2) {
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
} else { } else {
@ -330,7 +400,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* REVISIT: Some wkup sources might not be needed. * REVISIT: Some wkup sources might not be needed.
*/ */
dev->westate = OMAP_I2C_WE_ALL; 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); 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; 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 * 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: */ /* Take the I2C module out of reset: */
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); 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 */ /* Enable interrupts */
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | 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 * REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it. * 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, r = wait_for_completion_timeout(&dev->cmd_complete,
OMAP_I2C_TIMEOUT); OMAP_I2C_TIMEOUT);
if (dev->set_mpu_wkup_lat != NULL)
dev->set_mpu_wkup_lat(dev->dev, -1);
dev->buf_len = 0; dev->buf_len = 0;
if (r < 0) if (r < 0)
return r; 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); 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 */ /* rev1 devices are apparently only on some 15xx */
#ifdef CONFIG_ARCH_OMAP15XX #ifdef CONFIG_ARCH_OMAP15XX
@ -684,6 +793,35 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
#define omap_i2c_rev1_isr NULL #define omap_i2c_rev1_isr NULL
#endif #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 static irqreturn_t
omap_i2c_isr(int this_irq, void *dev_id) omap_i2c_isr(int this_irq, void *dev_id)
{ {
@ -733,6 +871,10 @@ complete:
} }
if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
u8 num_bytes = 1; u8 num_bytes = 1;
if (dev->errata & I2C_OMAP_ERRATA_I207)
i2c_omap_errata_i207(dev, stat);
if (dev->fifo_size) { if (dev->fifo_size) {
if (stat & OMAP_I2C_STAT_RRDY) if (stat & OMAP_I2C_STAT_RRDY)
num_bytes = dev->fifo_size; num_bytes = dev->fifo_size;
@ -747,9 +889,12 @@ complete:
if (dev->buf_len) { if (dev->buf_len) {
*dev->buf++ = w; *dev->buf++ = w;
dev->buf_len--; dev->buf_len--;
/* Data reg from 2430 is 8 bit wide */ /*
if (!cpu_is_omap2430() && * Data reg in 2430, omap3 and
!cpu_is_omap34xx()) { * omap4 is 8 bit wide
*/
if (cpu_class_is_omap1() ||
cpu_is_omap2420()) {
if (dev->buf_len) { if (dev->buf_len) {
*dev->buf++ = w >> 8; *dev->buf++ = w >> 8;
dev->buf_len--; dev->buf_len--;
@ -787,9 +932,12 @@ complete:
if (dev->buf_len) { if (dev->buf_len) {
w = *dev->buf++; w = *dev->buf++;
dev->buf_len--; dev->buf_len--;
/* Data reg from 2430 is 8 bit wide */ /*
if (!cpu_is_omap2430() && * Data reg in 2430, omap3 and
!cpu_is_omap34xx()) { * omap4 is 8 bit wide
*/
if (cpu_class_is_omap1() ||
cpu_is_omap2420()) {
if (dev->buf_len) { if (dev->buf_len) {
w |= *dev->buf++ << 8; w |= *dev->buf++ << 8;
dev->buf_len--; dev->buf_len--;
@ -807,25 +955,9 @@ complete:
break; break;
} }
/* if ((dev->errata & I2C_OMAP3_1P153) &&
* OMAP3430 Errata 1.153: When an XRDY/XDR errata_omap3_1p153(dev, &stat, &err))
* is hit, wait for XUDF before writing data goto complete;
* 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);
}
}
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); 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 omap_i2c_dev *dev;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct resource *mem, *irq, *ioarea; struct resource *mem, *irq, *ioarea;
struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
irq_handler_t isr; irq_handler_t isr;
int r; int r;
u32 speed = 0; u32 speed = 0;
@ -886,10 +1019,13 @@ omap_i2c_probe(struct platform_device *pdev)
goto err_release_region; goto err_release_region;
} }
if (pdev->dev.platform_data != NULL) if (pdata != NULL) {
speed = *(u32 *)pdev->dev.platform_data; speed = pdata->clkrate;
else dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
speed = 100; /* Defualt speed */ } else {
speed = 100; /* Default speed */
dev->set_mpu_wkup_lat = NULL;
}
dev->speed = speed; dev->speed = speed;
dev->idle = 1; dev->idle = 1;
@ -905,17 +1041,27 @@ omap_i2c_probe(struct platform_device *pdev)
if (cpu_is_omap7xx()) if (cpu_is_omap7xx())
dev->reg_shift = 1; dev->reg_shift = 1;
else if (cpu_is_omap44xx())
dev->reg_shift = 0;
else else
dev->reg_shift = 2; dev->reg_shift = 2;
if ((r = omap_i2c_get_clocks(dev)) != 0) if ((r = omap_i2c_get_clocks(dev)) != 0)
goto err_iounmap; goto err_iounmap;
if (cpu_is_omap44xx())
dev->regs = (u8 *) omap4_reg_map;
else
dev->regs = (u8 *) reg_map;
omap_i2c_unidle(dev); omap_i2c_unidle(dev);
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; 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; u16 s;
/* Set up the fifo size - Get total size */ /* 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 * size. This is to ensure that we can handle the status on int
* call back latencies. * call back latencies.
*/ */
dev->fifo_size = (dev->fifo_size / 2); if (dev->rev >= OMAP_I2C_REV_ON_4430) {
dev->b_hw = 1; /* Enable hardware fixes */ 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 */ /* reset ASAP, clearing any IRQs */

View File

@ -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__) #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) 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"); 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) static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
{ {
return !(readl(_ICR(i2c)) & ICR_SCLE); return !(readl(_ICR(i2c)) & ICR_SCLE);

View File

@ -482,7 +482,8 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num) struct i2c_msg *msgs, int num)
{ {
unsigned long timeout; unsigned long iicstat, timeout;
int spins = 20;
int ret; int ret;
if (i2c->suspended) if (i2c->suspended)
@ -521,7 +522,21 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
/* ensure the stop has been through the bus */ /* 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: out:
return ret; return ret;

9
include/linux/i2c-omap.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __I2C_OMAP_H__
#define __I2C_OMAP_H__
struct omap_i2c_bus_platform_data {
u32 clkrate;
void (*set_mpu_wkup_lat)(struct device *dev, long set);
};
#endif