commit a156bc18e08a648a7c073008af3fa8b4aeb0ef3b
parent 9e242746d88f3bc1a0d1a549811f2619a4acfbd4
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon, 28 Apr 2014 16:52:09 -0700
more i2c tools
- i2c_core.c provides a higher level API
- rdi2c/wri2c use that to read/write 16bit addr+data registers
Diffstat:
| M | Makefile |  |  | 12 | ++++++++++-- | 
| M | i2c.c |  |  | 33 | ++++++++++++++++++++++----------- | 
| A | i2c.h |  |  | 8 | ++++++++ | 
| A | i2c_core.c |  |  | 151 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | rdi2c.c |  |  | 41 | +++++++++++++++++++++++++++++++++++++++++ | 
| A | wri2c.c |  |  | 41 | +++++++++++++++++++++++++++++++++++++++++ | 
6 files changed, 273 insertions(+), 13 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,7 +2,7 @@
 CFLAGS := -g -Wall -O2
 LIBS := -lusb-1.0
 
-all: jtag i2c
+all: jtag i2c wri2c rdi2c
 
 jtag.c: jtag.h
 jtag-mpsse.c: jtag.h
@@ -14,5 +14,13 @@ jtag: $(JTAG2232_OBJS)
 i2c: i2c.o jtag-mpsse.o
 	$(CC) -o i2c i2c.o jtag-mpsse.o $(LIBS)
 
+WRI2C_OBJS := wri2c.o i2c_core.o jtag-mpsse.o
+wri2c: $(WRI2C_OBJS)
+	$(CC) -o wri2c $(WRI2C_OBJS) $(LIBS)
+
+RDI2C_OBJS := rdi2c.o i2c_core.o jtag-mpsse.o
+rdi2c: $(RDI2C_OBJS)
+	$(CC) -o rdi2c $(RDI2C_OBJS) $(LIBS)
+
 clean::
-	rm -f jtag *.o
+	rm -f jtag *.o i2c wri2c rdi2c
diff --git a/i2c.c b/i2c.c
@@ -53,25 +53,29 @@ u32 jwr(u32 n) {
 	return (u32) u;
 }
 
-#define STA	0x0100
-#define STP	0x0200
-#define WR	0x0400
-#define RD	0x0800
-#define TIP	0x1000
-#define ACK     0x2000
-#define LOST    0x4000
-#define BUSY    0x8000
+//              0x00XX // wo - data to write
+//              0x00XX // ro - last data read
+#define STA	0x0100 // rw - issue start on next rd or wr
+#define STP	0x0200 // rw - issue stop
+#define WR	0x0400 // rw - issue write
+#define RD	0x0800 // rw - issue read
+#define RACK    0x1000 // wo - master ACK/NAK state for reads
+#define TIP	0x1000 // ro - transaction in progress
+#define ACK     0x2000 // ro - slave ACK/NAK received on write
+#define LOST    0x4000 // ro - arbitration lost
+#define BUSY    0x8000 // ro - I2C bus busy
 
 /* example:  ./i2c sw:a0 w:fa sw:a1 r r r r r r p  */
 
 int main(int argc, char **argv) {
-	jconnect();
 	unsigned n,x;
 	unsigned c;
 
 	argc--;
 	argv++;
 
+	jconnect();
+
 	while (argc > 0) {
 		char *cmd = argv[0];
 		n = 0;
@@ -81,6 +85,7 @@ int main(int argc, char **argv) {
 			case 'p': case 'P': n |= STP; break;
 			case 'w': case 'W': n |= WR; break;
 			case 'r': case 'R': n |= RD; break;
+			case 'z': case 'Z': n |= RACK; break;
 			case ':':
 				cmd++;
 				n |= (strtoul(cmd, 0, 16) & 0xFF);
@@ -94,13 +99,19 @@ int main(int argc, char **argv) {
 done:
 		jwr(n);
 		c = 1;
-		while ((x = jrd()) & TIP) c++;
+		while ((x = jrd()) & TIP) {
+			c++;
+			if (c == 100000) {
+				fprintf(stderr,"timeout\n");
+				return -1;
+			}
+		}
 
 		fprintf(stderr, "%c%c%c%c %02x -> %02x %c%c%c (%d)\n",
 			(n&RD)?'R':'-', (n&WR)?'W':'-',
 			(n&STP)?'P':'-', (n&STA)?'S':'-',
 			n & 0xFF, x & 0xFF,
-			(x&ACK)?'A':'N', (x&LOST)?'L':'-',
+			(x&ACK)?'N':'A', (x&LOST)?'L':'-',
 			(x&BUSY)?'B':'-', c);
 		argc--;
 		argv++;
diff --git a/i2c.h b/i2c.h
@@ -0,0 +1,8 @@
+#ifndef _I2C_H_
+#define _I2C_H_
+
+void i2c_init(void);
+int i2c_wr16(unsigned saddr, unsigned addr, unsigned val);
+int i2c_rd16(unsigned saddr, unsigned addr, unsigned *val);
+
+#endif
diff --git a/i2c_core.c b/i2c_core.c
@@ -0,0 +1,151 @@
+/* Copyright 2014 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "jtag.h"
+#include "zynq.h"
+
+#include "i2c.h"
+
+#define TRACE_TXN 0
+
+static JTAG *jtag;
+
+void jconnect(void) {
+	if (!(jtag = jtag_open())) {
+		fprintf(stderr, "jconnect: cannot open usb jtag ifc\n");
+		exit(-1);
+	}
+	if (jtag_enumerate(jtag) <= 0) {
+		fprintf(stderr, "jconnect: cannot enumerate jtag devices\n");
+		exit(-1);
+	}
+	if (jtag_select(jtag, 0x13722093)) {
+		fprintf(stderr, "jconnect: cannot connect to ZYNQ\n");
+		exit(-1);
+	}
+
+	jtag_ir_wr(jtag, XIL_USER4);
+}
+
+u32 jrd(void) {
+	u64 u;
+	jtag_dr_io(jtag, 32, 0, &u);
+	return (u32) u;
+}
+
+u32 jwr(u32 n) {
+	u64 u;
+	u = n;
+	u |= 0x100000000ULL;
+	jtag_dr_io(jtag, 33, u, &u);
+	return (u32) u;
+}
+
+//              0x00XX // wo - data to write
+//              0x00XX // ro - last data read
+#define STA	0x0100 // rw - issue start on next rd or wr
+#define STP	0x0200 // rw - issue stop
+#define WR	0x0400 // rw - issue write
+#define RD	0x0800 // rw - issue read
+#define RACK    0x1000 // wo - master ACK/NAK state for reads
+#define TIP	0x1000 // ro - transaction in progress
+#define ACK     0x2000 // ro - slave ACK/NAK received on write
+#define LOST    0x4000 // ro - arbitration lost
+#define BUSY    0x8000 // ro - I2C bus busy
+
+static int i2c_txn(unsigned cmd, unsigned *_status) {
+	unsigned timeout = 0;
+	unsigned status;
+	jwr(cmd);
+	while ((status = jrd()) & TIP) {
+		timeout++;
+		if (timeout == 10000) {
+#if TRACE_TXN
+			fprintf(stderr,"txn: %04x XXXX\n",cmd); 
+#endif
+			fprintf(stderr, "i2c: txn timeout\n");
+			return -1;
+		}
+	}
+#if TRACE_TXN
+	fprintf(stderr,"txn: %04x %04x\n",cmd, status); 
+#endif
+	*_status = status;
+	return 0;	
+}
+
+static int i2c_start(unsigned saddr) {
+	unsigned status;
+	if (i2c_txn((saddr & 0xFF) | STA | WR, &status))
+		return -1;
+	if (status & ACK) {
+		fprintf(stderr, "i2c: slave NAK'd\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int i2c_stop(void) {
+	unsigned status;
+	return i2c_txn(STP, &status);
+}
+
+static int i2c_write(unsigned data) {
+	unsigned status;
+	if (i2c_txn((data & 0xFF) | WR, &status))
+		return -1;
+	if (status & ACK) {
+		fprintf(stderr, "i2c: slave NAK'd\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int i2c_read(unsigned *data, unsigned send_nak) {
+	unsigned status;
+	if (i2c_txn(RD | (send_nak ? RACK : 0), &status))
+		return -1;
+	*data = status & 0xFF;
+	return 0;
+}
+
+int i2c_wr16(unsigned saddr, unsigned addr, unsigned val) {
+	if (i2c_start(saddr)) return -1;
+	if (i2c_write(addr >> 8)) return -1;
+	if (i2c_write(addr)) return -1;
+	if (i2c_write(val >> 8)) return -1;
+	if (i2c_write(val)) return -1;
+	return i2c_stop();
+}
+
+int i2c_rd16(unsigned saddr, unsigned addr, unsigned *val) {
+	unsigned a, b;
+	if (i2c_start(saddr)) return -1;
+	if (i2c_write(addr >> 8)) return -1;
+	if (i2c_write(addr)) return -1;
+	if (i2c_start(saddr | 1)) return -1;
+	if (i2c_read(&a, 0)) return -1;
+	if (i2c_read(&b, 1)) return -1;
+	*val = (a << 8) | b;
+	return i2c_stop();
+}
+
+void i2c_init(void) {
+	jconnect();
+}
diff --git a/rdi2c.c b/rdi2c.c
@@ -0,0 +1,41 @@
+/* Copyright 2014 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "i2c.h"
+
+int main(int argc, char **argv) {
+	unsigned saddr, addr, val;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: rdi2c <saddr> <addr>\n");
+		return -1;
+	}
+
+	i2c_init();
+
+	saddr = strtoul(argv[1], 0, 16);
+	addr = strtoul(argv[2], 0, 16);
+
+	if (i2c_rd16(saddr, addr, &val)) {
+		fprintf(stderr, "error\n");
+		return -1;
+	}
+	printf("%04x\n", val);
+	return 0;
+}
diff --git a/wri2c.c b/wri2c.c
@@ -0,0 +1,41 @@
+/* Copyright 2014 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "i2c.h"
+
+int main(int argc, char **argv) {
+	unsigned saddr, addr, val;
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: wri2c <saddr> <addr> <value>\n");
+		return -1;
+	}
+
+	i2c_init();
+
+	saddr = strtoul(argv[1], 0, 16);
+	addr = strtoul(argv[2], 0, 16);
+	val = strtoul(argv[3], 0, 16);
+
+	if (i2c_wr16(saddr, addr, val)) {
+		fprintf(stderr, "error\n");
+		return -1;
+	}
+	return 0;
+}