Hi, > Discussions about the Linux i2c drivers belongs on the > linux-i2c@xxxxxxxxxxxxxxx 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)