Hi,
> Discussions about the Linux i2c drivers belongs on the
> [email protected] list, let's move discussion there.
>
Ok, I wrote on opencore list because I made a little modification in
VHDL design (wrapper).
>
> It could be that we have a problem with zero length transfers (don't
> have access to any smbus devices) - Could you please send a proper
> patch in diff -urpN format?
>
Done
--
Bye, FabM
--- ../../../../../../buildroot/project_build_armv4t/apf9328/linux-2.6.27.2/drivers/i2c/busses/i2c-ocores.c 2008-10-10 00:13:53.000000000 +0200
+++ i2c-ocores.c 2009-01-14 17:11:03.000000000 +0100
@@ -36,26 +36,30 @@ struct ocores_i2c {
#define OCI2C_PRELOW 0
#define OCI2C_PREHIGH 1
#define OCI2C_CONTROL 2
-#define OCI2C_DATA 3
-#define OCI2C_CMD 4 /* write only */
-#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
-
-#define OCI2C_CTRL_IEN 0x40
-#define OCI2C_CTRL_EN 0x80
-
-#define OCI2C_CMD_START 0x91
-#define OCI2C_CMD_STOP 0x41
-#define OCI2C_CMD_READ 0x21
-#define OCI2C_CMD_WRITE 0x11
-#define OCI2C_CMD_READ_ACK 0x21
-#define OCI2C_CMD_READ_NACK 0x29
-#define OCI2C_CMD_IACK 0x01
-
-#define OCI2C_STAT_IF 0x01
-#define OCI2C_STAT_TIP 0x02
-#define OCI2C_STAT_ARBLOST 0x20
-#define OCI2C_STAT_BUSY 0x40
-#define OCI2C_STAT_NACK 0x80
+#define OCI2C_CMD 4 /* write only */
+#define OCI2C_DATA_TXR 5
+#define OCI2C_STATUS 6 /* read only, same address as OCI2C_CMD */
+#define OCI2C_DATA_RXR 7
+
+
+#define OCI2C_CTRL_IEN (0x40)
+#define OCI2C_CTRL_EN (0x80)
+
+#define OCI2C_CMD_START (0x91)
+#define OCI2C_CMD_STOP (0x41)
+#define OCI2C_CMD_READ (0x21)
+#define OCI2C_CMD_WRITE (0x11)
+#define OCI2C_CMD_READ_ACK (0x21)
+#define OCI2C_CMD_READ_NACK (0x29)
+#define OCI2C_CMD_IACK (0x01)
+#define OCI2C_CMD_NACK (0x08)
+#define OCI2C_CMD_ACK (0x00)
+
+#define OCI2C_STAT_IF (0x01)
+#define OCI2C_STAT_TIP (0x02)
+#define OCI2C_STAT_ARBLOST (0x20)
+#define OCI2C_STAT_BUSY (0x40)
+#define OCI2C_STAT_NACK (0x80)
#define STATE_DONE 0
#define STATE_START 1
@@ -65,12 +69,12 @@ struct ocores_i2c {
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
{
- iowrite8(value, i2c->base + reg * i2c->regstep);
+ iowrite16((u16)value, i2c->base + reg * i2c->regstep);
}
static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
{
- return ioread8(i2c->base + reg * i2c->regstep);
+ return (u8)ioread16(i2c->base + reg * i2c->regstep);
}
static void ocores_process(struct ocores_i2c *i2c)
@@ -78,6 +82,15 @@ static void ocores_process(struct ocores
struct i2c_msg *msg = i2c->msg;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+ /* manage SMBus quick command */
+ if ((i2c->state == STATE_START)&&(i2c->msg->len==0)){
+ if(stat&OCI2C_STAT_NACK){
+ i2c->state = STATE_ERROR;
+ }else{
+ i2c->state = STATE_DONE;
+ }
+ }
+
if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
/* stop has been sent */
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
@@ -88,7 +101,7 @@ static void ocores_process(struct ocores
/* error? */
if (stat & OCI2C_STAT_ARBLOST) {
i2c->state = STATE_ERROR;
- oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP|OCI2C_CMD_READ);
return;
}
@@ -98,11 +111,11 @@ static void ocores_process(struct ocores
if (stat & OCI2C_STAT_NACK) {
i2c->state = STATE_ERROR;
- oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP|OCI2C_CMD_READ);
return;
}
} else
- msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA_RXR);
/* end of msg? */
if (i2c->pos == msg->len) {
@@ -121,7 +134,7 @@ static void ocores_process(struct ocores
i2c->state = STATE_START;
- oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_DATA_TXR, addr);
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
return;
} else
@@ -129,17 +142,21 @@ static void ocores_process(struct ocores
? STATE_READ : STATE_WRITE;
} else {
i2c->state = STATE_DONE;
- oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up(&i2c->wait);
return;
}
}
if (i2c->state == STATE_READ) {
- oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
- OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
- } else {
- oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
- oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ oc_setreg(i2c, OCI2C_CMD, ((i2c->pos == (msg->len-1)) ?
+ (OCI2C_CMD_READ_NACK|OCI2C_CMD_STOP) : OCI2C_CMD_READ_ACK));
+ return;
+ } else {/* STATE_WRITE */
+ oc_setreg(i2c, OCI2C_DATA_TXR, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, ((i2c->pos == msg->len) ?
+ (OCI2C_CMD_WRITE|OCI2C_CMD_STOP):OCI2C_CMD_WRITE));
+ return;
}
}
@@ -161,11 +178,15 @@ static int ocores_xfer(struct i2c_adapte
i2c->nmsgs = num;
i2c->state = STATE_START;
- oc_setreg(i2c, OCI2C_DATA,
+ oc_setreg(i2c, OCI2C_DATA_TXR,
(i2c->msg->addr << 1) |
((i2c->msg->flags & I2C_M_RD) ? 1:0));
- oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ if(i2c->msg->len == 0)
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START|OCI2C_CMD_STOP);
+ else
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
(i2c->state == STATE_DONE), HZ))
@@ -215,7 +236,7 @@ static int __devinit ocores_i2c_probe(st
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
struct resource *res, *res2;
- int ret;
+ int ret=0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)