Alexander Vasiliev wrote:
Hi, Dirk.
As i remember the problem is that Davinci cannot send zero length
packets on i2c. To find
device on some address linux (i2c_probe_address in i2c-core.c) sends
zero length packets.
So in i2c_davinci_xfer_msg(in i2c-davinci.c) we use the hack -
//////////////////////////////////////////////////////
#ifndef DAVINCI_HACK
dev->buf = msg->buf;
dev->buf_len = msg->len;
#else
if (msg->len == 0) {
dev->buf = &zero_byte;
dev->buf_len = 1;
} else {
dev->buf = msg->buf;
dev->buf_len = msg->len;
}
#endif
/////////////////////////////////////////////////////
and hope that Davinci sends address byte + one byte.
Yes, that is my understanding as well.
But it sends only
address byte in this case. It seems like AIC33 terminates transfer.
Did you measure this with logic analyzer or similiar? Unfortunately,
I'm not sure if this is the root cause of the problem or if it is the
result of an error happening earlier. See below.
Then we detect stop condition interrupt, but dev->buf_len still equals
to 1. So i2c_davinci_xfer_msg(in i2c-davinci.c) returns -EREMOTEIO.
And linux thinks that there was no answer from that address.
Hmm, I'm not sure what might be the root cause of the problem. There
are two options. Maybe an I2C expert can comment?
While debugging, I found that the code scans for two AIC I2C addresses
(TLV320AIC23ID1 and TLV320AIC23ID2). While scanning the first ID
(which doesn't exist) the driver reports *no* error. And if I only
scan for the second, correct ID, this works as well. The error is
reported while scanning for the second (correct) ID.
So the two root cause options are:
a) Scanning for an I2C address basically doesn't work with the zero
length hack above. But trying this on a non-existing I2C ID doesn't
cause any error.
or
b) While scanning for the first non-existing ID the error exit path of
I2C driver (the "if (dev->cmd_err & DAVINCI_I2C_STR_NACK)" path)
doesn't exits cleanly. Then, I2C HW is in an intermediate state not
able to execute the next scan with (correct) I2C address properly.
I tend to (b). If anybody would confirm that with using only
TLV320AIC23ID2 and not scanning for TLV320AIC23ID1 audio works fine,
this would be a proof for (b) (?)
//////////////////////////////////////////////////////////
r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
DAVINCI_I2C_TIMEOUT);
if (r == 0) {
dev_err(dev->dev, "controller timed out\n");
i2c_davinci_init(dev);
dev->buf = NULL;
return -ETIMEDOUT;
}
if (dev->buf_len) { /*it is not NULL, as
/* 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 = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////
Here some kind of patch for function i2c_davinci_xfer_msg in file i2c-davinci.c
#ifndef DAVINCI_HACK
dev->buf = msg->buf;
dev->buf_len = msg->len;
#else
if (msg->len == 0) {
dev->buf = &zero_byte;
dev->buf_len = 1;
zero_byte = 1; /*it is u8. We don't wait for any data to
be transfered*/
printk(KERN_INFO"I2CDavinci: trying to send zero bytes.\n");
} else {
dev->buf = msg->buf;
dev->buf_len = msg->len;
}
#endif
//////////////////////////////
r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
DAVINCI_I2C_TIMEOUT);
if (r == 0) {
dev_err(dev->dev, "controller timed out\n");
i2c_davinci_init(dev);
dev->buf = NULL;
return -ETIMEDOUT;
}
if(zero_byte == 1)/*There is no problem, if transfer didn't occur.*/
>
dev->buf_len = 0;
if (dev->buf_len) {
////////////////////////////
Is there a special reason why you set zero_byte to 1 for the
detection? You could detect for 0 as well?
Why Davinci sends only address byte - that's the question is.
Anybody with an idea regarding this?
Many thanks
Dirk
2008/3/21, Dirk Behme <[EMAIL PROTECTED]>:
Make sure that in case access to non-exisiting I2C address is done HW
is reset afterwards and works properly for next access.
Signed-off-by: Dirk Behme <[EMAIL PROTECTED]>
Index: linux-davinci/drivers/i2c/busses/i2c-davinci.c
===================================================================
--- linux-davinci.orig/drivers/i2c/busses/i2c-davinci.c
+++ linux-davinci/drivers/i2c/busses/i2c-davinci.c
@@ -348,6 +348,12 @@ i2c_davinci_xfer_msg(struct i2c_adapter
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);
+#ifdef DAVINCI_HACK
+ /* Reset error for next access working properly again */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+#endif
}
return -EREMOTEIO;
}
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source