Commit 54760fef authored by Dirk Behme's avatar Dirk Behme Committed by Kevin Hilman

I2C: DaVinci: Fix smbus Oops with AIC33 usage

This fixes Oops at kernel startup while "scanning" for TLV320AIC23IDx
addresses.
Signed-off-by: default avatarAlexander Vasiliev <alexvasiljev@gmail.com>
Signed-off-by: default avatarBrad Griffis <bgriffis@ti.com>
Signed-off-by: default avatarDirk Behme <dirk.behme@gmail.com>
Signed-off-by: default avatarKevin Hilman <khilman@mvista.com>
parent c16fe267
...@@ -112,6 +112,7 @@ struct davinci_i2c_dev { ...@@ -112,6 +112,7 @@ struct davinci_i2c_dev {
u8 *buf; u8 *buf;
size_t buf_len; size_t buf_len;
int irq; int irq;
int stop;
u8 terminate; u8 terminate;
struct i2c_adapter adapter; struct i2c_adapter adapter;
}; };
...@@ -249,9 +250,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) ...@@ -249,9 +250,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
u16 w; u16 w;
int r; int r;
if (msg->len == 0)
return -EINVAL;
if (!pdata) if (!pdata)
pdata = &davinci_i2c_platform_data_default; pdata = &davinci_i2c_platform_data_default;
/* Introduce a delay, required for some boards (e.g Davinci EVM) */ /* Introduce a delay, required for some boards (e.g Davinci EVM) */
...@@ -263,6 +261,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) ...@@ -263,6 +261,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
dev->buf = msg->buf; dev->buf = msg->buf;
dev->buf_len = msg->len; dev->buf_len = msg->len;
dev->stop = stop;
davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len); davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
...@@ -280,6 +279,10 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) ...@@ -280,6 +279,10 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
flag |= DAVINCI_I2C_MDR_TRX; flag |= DAVINCI_I2C_MDR_TRX;
if (stop) if (stop)
flag |= DAVINCI_I2C_MDR_STP; flag |= DAVINCI_I2C_MDR_STP;
if (msg->len == 0) {
flag |= DAVINCI_I2C_MDR_RM;
flag &= ~DAVINCI_I2C_MDR_STP;
}
/* Enable receive or transmit interrupts */ /* Enable receive or transmit interrupts */
w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG); w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
...@@ -290,6 +293,16 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) ...@@ -290,6 +293,16 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
dev->terminate = 0; dev->terminate = 0;
/* First byte should be set here, not after interrupt,
* because transmit-data-ready interrupt can come before
* NACK-interrupt during sending of previous message and
* ICDXR may have wrong data */
if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) {
davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++);
dev->buf_len--;
}
/* write the data into mode register */ /* write the data into mode register */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
...@@ -371,7 +384,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -371,7 +384,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
static u32 i2c_davinci_func(struct i2c_adapter *adap) static u32 i2c_davinci_func(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
} }
static void terminate_read(struct davinci_i2c_dev *dev) static void terminate_read(struct davinci_i2c_dev *dev)
...@@ -430,6 +443,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) ...@@ -430,6 +443,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
case DAVINCI_I2C_IVR_ARDY: case DAVINCI_I2C_IVR_ARDY:
davinci_i2c_write_reg(dev, davinci_i2c_write_reg(dev,
DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY); DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);
if (((dev->buf_len == 0) && (dev->stop != 0)) ||
(dev->cmd_err & DAVINCI_I2C_STR_NACK)) {
w = davinci_i2c_read_reg(dev,
DAVINCI_I2C_MDR_REG);
MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1);
davinci_i2c_write_reg(dev,
DAVINCI_I2C_MDR_REG, w);
}
complete(&dev->cmd_complete); complete(&dev->cmd_complete);
break; break;
......
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