summaryrefslogtreecommitdiffstats
path: root/target/linux/at91/patches/100-at91_i2c.patch
blob: e78ffde08ba359a951c21270fc7ff08311384225 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -283,7 +283,7 @@ comment "I2C system bus drivers (mostly
 
 config I2C_AT91
 	tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
-	depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+	depends on ARCH_AT91 && EXPERIMENTAL
 	help
 	  This supports the use of the I2C interface on Atmel AT91
 	  processors.
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -11,8 +11,18 @@
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
+
+    D. Gilbert [20100318 AT91SAM9G20]
+	- Check for NACK, a NACK will abort current tranfser,
+          returned as errno=EREMOTEIO unless I2C_M_IGNORE_NAK is set
+        - Only supports 7 bit I2C device (slave) address
+	- clockrate adjustable (module_param).
 */
 
+
+/* Uncomment following line to see dev_dbg() output in logs */
+/* #define DEBUG 1 */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/err.h>
@@ -32,26 +42,28 @@
 #define TWI_CLOCK		100000		/* Hz. max 400 Kbits/sec */
 
 
+static unsigned int clockrate = TWI_CLOCK;
+static unsigned int prev_clockrate = TWI_CLOCK;
 static struct clk *twi_clk;
 static void __iomem *twi_base;
 
 #define at91_twi_read(reg)		__raw_readl(twi_base + (reg))
 #define at91_twi_write(reg, val)	__raw_writel((val), twi_base + (reg))
 
-
 /*
- * Initialize the TWI hardware registers.
+ * Set TWI clock dividers based on clockrate (clock rate for SCL)
  */
-static void __devinit at91_twi_hwinit(void)
+static void at91_twi_clock_dividers(void)
 {
 	unsigned long cdiv, ckdiv;
 
-	at91_twi_write(AT91_TWI_IDR, 0xffffffff);	/* Disable all interrupts */
-	at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST);	/* Reset peripheral */
-	at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);	/* Set Master mode */
+	if (clockrate < 1000)
+		clockrate = 1000;	
+	else if (clockrate > 400000)
+		clockrate = 400000;	
 
-	/* Calcuate clock dividers */
-	cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+	/* Calculate clock dividers */
+	cdiv = (clk_get_rate(twi_clk) / (2 * clockrate)) - 3;
 	cdiv = cdiv + 1;	/* round up */
 	ckdiv = 0;
 	while (cdiv > 255) {
@@ -61,41 +73,92 @@ static void __devinit at91_twi_hwinit(vo
 
 	if (cpu_is_at91rm9200()) {			/* AT91RM9200 Errata #22 */
 		if (ckdiv > 5) {
-			printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+			printk(KERN_ERR "i2c-at91: Invalid AT91RM9200 clock rate\n");
 			ckdiv = 5;
 		}
 	}
+	/* AT91SAM9G20 has 3 bits for ckdiv so it cannot exceed 7 */
+	if (cpu_is_at91sam9g20()) {
+		if (ckdiv > 7) {
+			printk(KERN_ERR "i2c-at91: Invalid AT91SAM9G20 clock "
+			       "rate, ckdiv=%lu\n", ckdiv);
+			ckdiv = 7;
+		}
+	}
 
 	at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+	prev_clockrate = clockrate;
 }
 
 /*
- * Poll the i2c status register until the specified bit is set.
- * Returns 0 if timed out (100 msec).
+ * Initialize the TWI hardware registers.
  */
-static short at91_poll_status(unsigned long bit)
+static void __devinit at91_twi_hwinit(void)
 {
-	int loop_cntr = 10000;
+	at91_twi_write(AT91_TWI_IDR, 0xffffffff);  /* Disable all interrupts */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST);     /* Reset peripheral */
+	/* Set Master mode; Atmel suggests disabling slave mode */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN | AT91_TWI_SVDIS);
 
+	at91_twi_clock_dividers();
+}
+
+/*
+ * Poll the i2c status register until the specified bit is set or a NACK
+ * occurs. Returns 0 if timed out (50 msec). If nack_seen_p is non-NULL
+ * then write 0 to it first, then if the NACK bit is set in the status
+ * register then write 1 to it and immediately return with a value of 1.
+ */
+static short at91_poll_status(unsigned long bit, int * nack_seen_p)
+{
+	int loop_cntr = 5000;
+	unsigned long stat;
+
+	if (nack_seen_p)
+		*nack_seen_p = 0;
+	if (clockrate <= 20000)
+		loop_cntr = 100;
 	do {
-		udelay(10);
-	} while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+		if (clockrate <= 20000)
+			udelay(100);
+		else if (clockrate <= 100000)
+			udelay(10);
+		else
+			udelay(3);
+		stat = at91_twi_read(AT91_TWI_SR);
+		if ((stat & AT91_TWI_NACK) && nack_seen_p) {
+			*nack_seen_p = 1;
+			return 1;
+		}
+	} while (!(stat & bit) && (--loop_cntr > 0));
 
 	return (loop_cntr > 0);
 }
 
 static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
 {
+	int nack_seen = 0;
+	int sent_stop = 0;
+
 	/* Send Start */
-	at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+	if (1 == length) {
+	    at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP);
+	    sent_stop = 1;
+	} else
+	    at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
 
 	/* Read data */
 	while (length--) {
-		if (!length)	/* need to send Stop before reading last byte */
+		/* send Stop before reading last byte (if not already done) */
+		if ((0 == length) && (0 == sent_stop))
 			at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
-		if (!at91_poll_status(AT91_TWI_RXRDY)) {
+		if (!at91_poll_status(AT91_TWI_RXRDY, &nack_seen)) {
 			dev_dbg(&adap->dev, "RXRDY timeout\n");
 			return -ETIMEDOUT;
+		} else if (nack_seen) {
+			dev_dbg(&adap->dev, "read NACKed\n");
+			/* NACK supplies Stop */
+			return -EREMOTEIO;
 		}
 		*buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
 	}
@@ -105,16 +168,24 @@ static int xfer_read(struct i2c_adapter
 
 static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
 {
+	int nack_seen = 0;
+
 	/* Load first byte into transmitter */
 	at91_twi_write(AT91_TWI_THR, *buf++);
 
-	/* Send Start */
+	/* Send Start [AT91SAM9G20 does not need this on write] */
 	at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
 
 	do {
-		if (!at91_poll_status(AT91_TWI_TXRDY)) {
+		if (!at91_poll_status(AT91_TWI_TXRDY, &nack_seen)) {
 			dev_dbg(&adap->dev, "TXRDY timeout\n");
+			/* Set Master mode again */
+			at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);
 			return -ETIMEDOUT;
+		} else if (nack_seen) {
+			dev_dbg(&adap->dev, "write NACKed\n");
+			/* NACK supplies Stop */
+			return -EREMOTEIO;
 		}
 
 		length--;	/* byte was transmitted */
@@ -123,7 +194,7 @@ static int xfer_write(struct i2c_adapter
 			at91_twi_write(AT91_TWI_THR, *buf++);
 	} while (length);
 
-	/* Send Stop */
+	/* Send Stop [AT91SAM9G20 does not need this on write] */
 	at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
 
 	return 0;
@@ -136,11 +207,19 @@ static int xfer_write(struct i2c_adapter
  * Instead the "internal device address" has to be written using a separate
  * i2c message.
  * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+ * [dpg] By 2010 silicon bugs should be fixed, will need IADR for 10 bit device address
  */
 static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
 {
 	int i, ret;
+	int nack_seen = 0;
 
+	if (prev_clockrate != clockrate) {
+		dev_dbg(&adap->dev, "at91_xfer: prev_clockrate=%u "
+			"clockrate=%u, change\n", prev_clockrate, clockrate);
+		at91_twi_clock_dividers();
+		msleep(1);	/* let things settle */
+	}
 	dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
 
 	for (i = 0; i < num; i++) {
@@ -158,13 +237,23 @@ static int at91_xfer(struct i2c_adapter
 			else
 				ret = xfer_write(adap, pmsg->buf, pmsg->len);
 
-			if (ret)
-				return ret;
-
+			if (ret) {
+				if ((I2C_M_IGNORE_NAK & pmsg->flags) &&
+				    (-EREMOTEIO == ret)) {
+					dev_dbg(&adap->dev, "transfer "
+						"NACKed, skip to next\n");
+					pmsg++;
+					continue;
+				} else
+					return ret;
+			}
 			/* Wait until transfer is finished */
-			if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+			if (!at91_poll_status(AT91_TWI_TXCOMP, &nack_seen)) {
 				dev_dbg(&adap->dev, "TXCOMP timeout\n");
 				return -ETIMEDOUT;
+			} else if (nack_seen) {
+				dev_dbg(&adap->dev, "TXCOMP NACKed\n");
+				return -EREMOTEIO;
 			}
 		}
 		dev_dbg(&adap->dev, "transfer complete\n");
@@ -239,7 +328,8 @@ static int __devinit at91_i2c_probe(stru
 		goto fail3;
 	}
 
-	dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+	dev_info(&pdev->dev, "AT91 TWI (I2C) bus driver [SCL %d Hz]\n",
+		 clockrate);
 	return 0;
 
 fail3:
@@ -295,6 +385,11 @@ static int at91_i2c_resume(struct platfo
 #define at91_i2c_resume		NULL
 #endif
 
+/* I2C clock speed, in Hz 0-400kHz*/
+module_param(clockrate, uint,  S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(clockrate,
+		 "SCL clock rate, 1000 to 400000 Hz (def: 100 kHz)");
+
 /* work with "modprobe at91_i2c" from hotplugging or coldplugging */
 MODULE_ALIAS("platform:at91_i2c");
 
@@ -323,5 +418,5 @@ module_init(at91_i2c_init);
 module_exit(at91_i2c_exit);
 
 MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_DESCRIPTION("I2C (TWI) master driver for Atmel AT91");
 MODULE_LICENSE("GPL");