* Re: I2c-ocore linux driver debug
[not found] <ce62e9d00901130200v19a57684u69ed8cfbd1085085@mail.gmail.com>
@ 2009-01-14 15:51 ` Peter Korsgaard
[not found] ` <87zlhtrimu.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org>
0 siblings, 1 reply; 2+ messages in thread
From: Peter Korsgaard @ 2009-01-14 15:51 UTC (permalink / raw)
To: Discussion list about free open source IP cores, linux-i2c,
lepingouin.tux
>>>>> "FM" == Fabien Marteau <lepingouin.tux@gmail.com> writes:
Hi,
Discussions about the Linux i2c drivers belongs on the
linux-i2c@vger.kernel.org list, let's move discussion there.
FM> I integrated the IP i2c ocore for my platform ARMadeus apf9328
FM> (http://www.armadeus.com/wiki). ARMadeus platform is an embedded
FM> system with a processor i.MXL and a FPGA Spartan3.
FM> The interface between the processor and FPGA is a 16bits data bus,
FM> and it's wired to do only 16bits read/write. Thus, I had to write
FM> a wrapper to convert 8bits ocore interface in 16bits
FM> interface. This wrapper mutiplex data bus to keep data in low part
FM> of the 16bits bus (see attachement) and add an ID register to
FM> unsure driver that the component is configured correctly.
FM> I had two problems with the driver:
FM> * Registers addresses.
FM> * To send stop command, driver have to set stop bit *before*
FM> sending the last byte. In the driver, this stop bit is set at the
FM> end of command, and that doesn't work.
FM> I was really surprised of this bugs, because this IP is old and I
FM> feel I am the only one that have these problems. Maybe the problem
FM> come from wrapper but I don't know why.
FM> I modified the driver to fix these bugs (see diff in attachment), and that
FM> work well with two components (LIS3LV02DL accelerometer and DS28CZ04 EEPROM)
FM> and testbench provided in attachment.
FM> Addresses registers problem
FM> ===========================
FM> The original driver give these addresses:
FM> /* registers */
FM> #define OCI2C_PRELOW 0
FM> #define OCI2C_PREHIGH 1
FM> #define OCI2C_CONTROL 2
FM> #define OCI2C_DATA 3
FM> #define OCI2C_CMD 4 /* write only */
FM> #define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
That fits the specs (i2c_specs.pdf, by Richard Herveille)
FM> After lot of tests, I found that this addresses work better:
FM> /* registers */
FM> #define OCI2C_PRELOW 0
FM> #define OCI2C_PREHIGH 1
FM> #define OCI2C_CONTROL 2
FM> #define OCI2C_CMD 4
FM> #define OCI2C_DATA_TXR 5
FM> #define OCI2C_STATUS 6
FM> #define OCI2C_DATA_RXR 7
Strange, seems like something went wrong in your wrapper.
FM> Stop command
FM> ============
FM> The most important problem I had was the stop command. To send a command like
FM> write quick SMBus (see Documentation/i2c/smbus-protocol) :
FM> S Addr [Rd/Wr] P
FM> The stop bit must be set at the same time that start bit. To do
FM> that I modified
FM> the xfer function:
FM> oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
FM> by:
FM> if(i2c->msg->len == 0)
FM> oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START|OCI2C_CMD_STOP);
FM> else
FM> oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
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?
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [oc] I2c-ocore linux driver debug
[not found] ` <87zlhtrimu.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org>
@ 2009-01-14 16:20 ` Fabien Marteau
0 siblings, 0 replies; 2+ messages in thread
From: Fabien Marteau @ 2009-01-14 16:20 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 439 bytes --]
Hi,
> Discussions about the Linux i2c drivers belongs on the
> linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org 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
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: i2c-ocores.diff --]
[-- Type: text/x-diff; name=i2c-ocores.diff, Size: 5189 bytes --]
--- ../../../../../../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)
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2009-01-14 16:20 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <ce62e9d00901130200v19a57684u69ed8cfbd1085085@mail.gmail.com>
2009-01-14 15:51 ` I2c-ocore linux driver debug Peter Korsgaard
[not found] ` <87zlhtrimu.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org>
2009-01-14 16:20 ` [oc] " Fabien Marteau
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox