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:
commit
c3ad33c9bc
|
@ -2747,6 +2747,7 @@ M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
|
|||
L: linux-i2c@vger.kernel.org
|
||||
W: http://i2c.wiki.kernel.org/
|
||||
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
|
||||
F: Documentation/i2c/
|
||||
F: drivers/i2c/
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-omap.h>
|
||||
|
||||
#include <mach/irqs.h>
|
||||
#include <plat/mux.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/omap-pm.h>
|
||||
|
||||
#define OMAP_I2C_SIZE 0x3f
|
||||
#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[] = {
|
||||
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)
|
||||
I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]),
|
||||
I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]),
|
||||
#endif
|
||||
#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
|
||||
};
|
||||
|
||||
|
@ -100,10 +103,12 @@ static int __init omap_i2c_nr_ports(void)
|
|||
static int __init omap_i2c_add_bus(int bus_id)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct omap_i2c_bus_platform_data *pd;
|
||||
struct resource *res;
|
||||
resource_size_t base, irq;
|
||||
|
||||
pdev = &omap_i2c_devices[bus_id - 1];
|
||||
pd = pdev->dev.platform_data;
|
||||
if (bus_id == 1) {
|
||||
res = pdev->resource;
|
||||
if (cpu_class_is_omap1()) {
|
||||
|
@ -123,6 +128,15 @@ static int __init omap_i2c_add_bus(int bus_id)
|
|||
if (cpu_class_is_omap2())
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -146,8 +160,8 @@ static int __init omap_i2c_bus_setup(char *str)
|
|||
get_options(str, 3, ints);
|
||||
if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
|
||||
return 0;
|
||||
i2c_rate[ints[1] - 1] = ints[2];
|
||||
i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP;
|
||||
i2c_pdata[ints[1] - 1].clkrate = ints[2];
|
||||
i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -161,9 +175,9 @@ static int __init omap_register_i2c_bus_cmdline(void)
|
|||
{
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_rate); i++)
|
||||
if (i2c_rate[i] & OMAP_I2C_CMDLINE_SETUP) {
|
||||
i2c_rate[i] &= ~OMAP_I2C_CMDLINE_SETUP;
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
|
||||
if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
|
||||
i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
|
||||
err = omap_i2c_add_bus(i + 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -197,9 +211,10 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!i2c_rate[bus_id - 1])
|
||||
i2c_rate[bus_id - 1] = clkrate;
|
||||
i2c_rate[bus_id - 1] &= ~OMAP_I2C_CMDLINE_SETUP;
|
||||
if (!i2c_pdata[bus_id - 1].clkrate)
|
||||
i2c_pdata[bus_id - 1].clkrate = clkrate;
|
||||
|
||||
i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
|
||||
|
||||
return omap_i2c_add_bus(bus_id);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
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 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);
|
||||
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 (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,13 +542,30 @@ 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;
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
9
include/linux/i2c-omap.h
Normal file
9
include/linux/i2c-omap.h
Normal 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
|
Loading…
Reference in a new issue