Commit dd7319a5 authored by Sonic Zhang's avatar Sonic Zhang Committed by Ben Dooks

i2c-bfin-twi: integrate timeout timer with completion interface

There isn't much point in managing our own custom timeout timer when the
completion interface already includes support for it.  This makes the
resulting code much simpler and robust.
Signed-off-by: default avatarSonic Zhang <sonic.zhang@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent 1bc2962e
...@@ -25,8 +25,6 @@ ...@@ -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 { ...@@ -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;
...@@ -169,16 +165,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) ...@@ -169,16 +165,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
write_INT_MASK(iface, 0); write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0); write_MASTER_CTL(iface, 0);
SSYNC(); SSYNC();
/* If it is a quick transfer, only address bug no data, /* If it is a quick transfer, only address without data,
* not an err, return 1. * not an err, return 1.
* If address is acknowledged return 1.
*/ */
if (iface->writeNum == 0 && (mast_stat & BUFRDERR)) if ((iface->writeNum == 0 && (mast_stat & BUFRDERR))
|| !(mast_stat & ANAK))
iface->result = 1; 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;
...@@ -250,9 +243,9 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) ...@@ -250,9 +243,9 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
write_INT_MASK(iface, 0); write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0); write_MASTER_CTL(iface, 0);
SSYNC(); SSYNC();
complete(&iface->complete);
} }
} }
complete(&iface->complete);
} }
/* Interrupt handler */ /* Interrupt handler */
...@@ -262,36 +255,15 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) ...@@ -262,36 +255,15 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&iface->lock, flags); spin_lock_irqsave(&iface->lock, flags);
del_timer(&iface->timeout_timer);
bfin_twi_handle_interrupt(iface); bfin_twi_handle_interrupt(iface);
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 +291,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, ...@@ -319,7 +291,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 +329,49 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, ...@@ -358,30 +329,49 @@ 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,
rc = iface->result; adap->timeout)) {
iface->result = -1;
dev_err(&adap->dev, "master transfer timeout\n");
}
}
if (rc == 1) if (iface->result == 1)
return num; rc = iface->cur_msg + 1;
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)
{
int i, ret = 0;
int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, for (i = 0; i < adap->retries; i++) {
ret = bfin_twi_do_master_xfer(adap, msgs, num);
if (ret > 0)
break;
}
return ret;
}
/*
* 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 +459,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, ...@@ -469,7 +459,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 +475,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, ...@@ -486,9 +475,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 +536,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, ...@@ -550,10 +536,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 +553,38 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, ...@@ -569,13 +553,38 @@ 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)
{
int i, ret = 0;
for (i = 0; i < adap->retries; i++) {
ret = bfin_twi_do_smbus_xfer(adap, addr, flags,
read_write, command, size, data);
if (ret == 0)
break;
}
return ret;
}
/* /*
* Return what the adapter supports * Return what the adapter supports
*/ */
...@@ -667,10 +676,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) ...@@ -667,10 +676,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 +683,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) ...@@ -678,6 +683,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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment