Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 101274
b: refs/heads/master
c: 5a0d5f5
h: refs/heads/master
v: v3
  • Loading branch information
Troy Kisky authored and Jean Delvare committed Jul 14, 2008
1 parent 3ab405e commit 732c0ed
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0ab56e20674b41dd0203d16b602aac8d9d26a70a
refs/heads/master: 5a0d5f5ffa5d294d895ef54fc220c6182db63998
62 changes: 52 additions & 10 deletions trunk/drivers/i2c/busses/i2c-davinci.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
#define DAVINCI_I2C_MDR_MST (1 << 10)
#define DAVINCI_I2C_MDR_TRX (1 << 9)
#define DAVINCI_I2C_MDR_XA (1 << 8)
#define DAVINCI_I2C_MDR_RM (1 << 7)
#define DAVINCI_I2C_MDR_IRS (1 << 5)

#define DAVINCI_I2C_IMR_AAS (1 << 6)
Expand Down Expand Up @@ -112,6 +113,7 @@ struct davinci_i2c_dev {
u8 *buf;
size_t buf_len;
int irq;
u8 terminate;
struct i2c_adapter adapter;
};

Expand Down Expand Up @@ -283,20 +285,34 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);

dev->terminate = 0;
/* write the data into mode register */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);

r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
DAVINCI_I2C_TIMEOUT);
dev->buf_len = 0;
if (r < 0)
return r;

if (r == 0) {
dev_err(dev->dev, "controller timed out\n");
i2c_davinci_init(dev);
dev->buf_len = 0;
return -ETIMEDOUT;
}
if (dev->buf_len) {
/* This should be 0 if all bytes were transferred
* or dev->cmd_err denotes an error.
* A signal may have aborted the transfer.
*/
if (r >= 0) {
dev_err(dev->dev, "abnormal termination buf_len=%i\n",
dev->buf_len);
r = -EREMOTEIO;
}
dev->terminate = 1;
wmb();
dev->buf_len = 0;
}
if (r < 0)
return r;

/* no error */
if (likely(!dev->cmd_err))
Expand Down Expand Up @@ -354,6 +370,27 @@ static u32 i2c_davinci_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}

static void terminate_read(struct davinci_i2c_dev *dev)
{
u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
w |= DAVINCI_I2C_MDR_NACK;
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);

/* Throw away data */
davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG);
if (!dev->terminate)
dev_err(dev->dev, "RDR IRQ while no data requested\n");
}
static void terminate_write(struct davinci_i2c_dev *dev)
{
u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP;
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);

if (!dev->terminate)
dev_err(dev->dev, "TDR IRQ while no data to send\n");
}

/*
* Interrupt service routine. This gets called whenever an I2C interrupt
* occurs.
Expand All @@ -374,12 +411,15 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)

switch (stat) {
case DAVINCI_I2C_IVR_AL:
/* Arbitration lost, must retry */
dev->cmd_err |= DAVINCI_I2C_STR_AL;
dev->buf_len = 0;
complete(&dev->cmd_complete);
break;

case DAVINCI_I2C_IVR_NACK:
dev->cmd_err |= DAVINCI_I2C_STR_NACK;
dev->buf_len = 0;
complete(&dev->cmd_complete);
break;

Expand All @@ -401,9 +441,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
davinci_i2c_write_reg(dev,
DAVINCI_I2C_STR_REG,
DAVINCI_I2C_IMR_RRDY);
} else
dev_err(dev->dev, "RDR IRQ while no "
"data requested\n");
} else {
/* signal can terminate transfer */
terminate_read(dev);
}
break;

case DAVINCI_I2C_IVR_XRDY:
Expand All @@ -420,9 +461,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
davinci_i2c_write_reg(dev,
DAVINCI_I2C_IMR_REG,
w);
} else
dev_err(dev->dev, "TDR IRQ while no data to "
"send\n");
} else {
/* signal can terminate transfer */
terminate_write(dev);
}
break;

case DAVINCI_I2C_IVR_SCD:
Expand Down

0 comments on commit 732c0ed

Please sign in to comment.