80f0bdf706e5cb970306d26d77eff8aadd152776
[fw/openalt] / i2c / i2cInt.c
1 #include "FreeRTOS.h"
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/times.h>
6
7 #include "i2c.h"
8
9 //
10 //  Default timeout, in milliseconds for generic read/write
11 //
12 #define I2C_DEFAULT_TIMEOUT 100
13 #undef  I2C_DEBUG
14
15 //
16 //
17 //
18 typedef enum
19 {
20   ACKPOLL_NO = 0,
21   ACKPOLL_YES
22 }
23 ackPoll_e;
24
25 //
26 //
27 //
28 static volatile int i2cBusInUse;
29 static U8 i2cAddress;
30 static U8 *i2cDataBuffer;
31 static int i2cDataLenWrite;
32 static int i2cDataLenRead;
33 static unsigned int i2cTimeoutInTicks = I2C_DEFAULT_TIMEOUT / portTICK_RATE_MS;
34 static int i2cDataCnt;
35 static ackPoll_e i2cAckPoll = ACKPOLL_NO;
36
37 //
38 //
39 //
40 #ifdef I2C_DEBUG
41 static U8 i2cTransactions [64];
42 static int i2cTransactionsIndex;
43 #define i2cDebug(x) do { if (i2cAckPoll && (i2cTransactionsIndex < (int) sizeof (i2cTransactions))) i2cTransactions [i2cTransactionsIndex++] = x; } while (0)
44 #define i2cDebugReset() do { i2cTransactionsIndex = 0; } while (0)
45 #else
46 #define i2cDebug(x) do { } while (0)
47 #define i2cDebugReset() do { } while (0)
48 #endif
49
50 static void i2cISR (void) __attribute__ ((interrupt ("IRQ")));
51 static void i2cISR (void)
52 {
53   i2cErrno = (I2C0_STAT & I2C_STAT_STATMASK);
54   i2cDebug (i2cErrno);
55
56   switch (i2cErrno)
57   {
58     //
59     //  Transmit conditions
60     //
61     case I2CERR_BUSERRORx : // 0x00
62       {
63         I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
64         i2cAckPoll = ACKPOLL_NO;
65         i2cBusInUse = FALSE;
66       }
67       break;
68
69     case I2CERR_STARTTX : // 0x08
70     case I2CERR_REPEATEDSTARTTX : // 0x10
71       {
72         i2cDebug (i2cAddress);
73         I2C0_DAT = i2cAddress;
74       }
75       break;
76
77     case I2CERR_SLAWTX_ACKRX : // 0x18
78     case I2CERR_DATTX_ACKRX : // 0x28
79       {
80         i2cAckPoll = ACKPOLL_NO;
81
82         if (i2cDataLenWrite && (i2cDataCnt < i2cDataLenWrite))
83         {
84           i2cDebug (i2cDataBuffer [i2cDataCnt]);
85           I2C0_DAT = i2cDataBuffer [i2cDataCnt++];
86           I2C0_CONCLR = I2C_CONCLR_STAC;
87         }
88         else
89         {
90           if (!i2cDataLenRead)
91           {
92             i2cDebug (0xff);
93             I2C0_CONCLR = I2C_CONCLR_STAC;
94             I2C0_CONSET = I2C_CONSET_STO;
95             i2cErrno = I2CERR_NONE;
96             i2cBusInUse = FALSE;
97           }
98           else
99           {
100             i2cDebug (0xfe);
101             i2cAddress |= 0x01;
102             i2cDataCnt = 0;
103             I2C0_CONSET = I2C_CONSET_STA;
104           }
105         }
106       }
107       break;
108
109     case I2CERR_DATRX_NACKTX : // 0x58
110       {
111         i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
112         i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
113         i2cErrno = I2CERR_NONE;
114       }
115
116     case I2CERR_SLAWTX_NACKRX : // 0x20
117     case I2CERR_SLARTX_NACKRX : // 0x48
118       {
119         if (i2cAckPoll)
120           break;
121       }
122
123     case I2CERR_DATTX_NACKRX : // 0x30
124       {
125         I2C0_CONCLR = I2C_CONCLR_STAC;
126         I2C0_CONSET = I2C_CONSET_STO;
127         i2cBusInUse = FALSE;
128       }
129       break;
130
131     case I2CERR_ARBLOST : // 0x38
132       {
133         I2C0_CONSET = I2C_CONSET_STA;
134       }
135       break;
136
137     //
138     //  Receive byte conditions (fall through is intentional)
139     //
140     case I2CERR_DATRX_ACKTX : // 0x50
141       {
142         i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
143         i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
144       }
145
146     case I2CERR_SLARTX_ACKRX : // 0x40
147       {
148         if (i2cDataCnt < i2cDataLenRead - 1)
149         {
150           I2C0_CONCLR = I2C_CONCLR_STAC;
151           I2C0_CONSET = I2C_CONSET_AA;
152         }
153         else
154           I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_AAC;
155       }
156       break;
157
158     case I2CERR_NOINFO :
159       break;
160
161     default:
162       {
163         I2C0_CONCLR = I2C_CONCLR_I2ENC;
164         i2cAckPoll = ACKPOLL_NO;
165         i2cBusInUse = FALSE;
166       }
167       break;
168   }
169
170   I2C0_CONCLR = I2C_CONSET_SI;
171   VIC_VectAddr = 0;
172 }
173
174 //
175 // i2c1Init
176 //
177 void i2cInit (void)
178 {
179   i2cBusInUse = FALSE;
180   i2cAckPoll = ACKPOLL_NO;
181
182   SCB_PCONP |= SCB_PCONP_PCI2C0;
183
184   PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
185
186   I2C0_CONCLR = I2C_CONCLR_MASK;
187   I2C0_CONSET = I2C_CONSET_I2EN;
188   I2C0_SCLL   = 240;
189   I2C0_SCLH   = 240;
190
191   //
192   //  Initialize the interrupt vector
193   //
194   VIC_IntSelect &= ~VIC_IntSelect_I2C0;
195   VIC_VectCntl7 = VIC_VectCntl_ENABLE | VIC_Channel_I2C0;
196   VIC_VectAddr7 = (int) i2cISR;
197   VIC_IntEnable = VIC_IntEnable_I2C0;
198 }
199
200 //
201 //
202 //
203 static int i2cWaitComplete (int ticks)
204 {
205   if (i2cBusInUse)
206   {
207     clock_t theFuture;
208
209     for (theFuture = times (NULL) + ticks; i2cBusInUse; )
210     {
211       if (times (NULL) > theFuture)
212       {
213         I2C0_CONCLR = I2C_CONCLR_I2ENC;
214         i2cErrno = I2CERR_TIMEOUTWC;
215         return -1;
216       }
217     }
218   }
219
220   return (i2cErrno == I2CERR_NONE) ? 0 : -1;
221 }
222
223 static int i2cPoll (U8 address)
224 {
225   clock_t theFuture = times (NULL) + 10;
226
227   VIC_IntEnClr = VIC_IntEnClr_I2C0;
228
229   while (times (NULL) < theFuture)
230   {
231     I2C0_CONCLR = I2C_CONSET_SI;
232     I2C0_CONSET = I2C_CONSET_STA;
233
234     while (!(I2C0_CONSET & I2C_CONSET_SI))
235       ;
236
237     I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC;
238     I2C0_DAT = address & ~0x01;
239
240     while (!(I2C0_CONSET & I2C_CONSET_SI))
241       ;
242
243     if ((i2cErrno = I2C0_STAT) == I2CERR_SLAWTX_ACKRX)
244       break;
245   }
246
247   if (i2cErrno != I2CERR_SLAWTX_ACKRX)
248     i2cErrno = I2CERR_TIMEOUTACKPOLL;
249
250   I2C0_CONCLR = I2C_CONCLR_SIC;
251   I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
252
253   while (I2C0_CONSET & I2C_CONSET_STO)
254     ;
255
256   VIC_IntEnable = VIC_IntEnable_I2C0;
257
258   return (i2cErrno == I2CERR_SLAWTX_ACKRX) ? 0 : -1;
259 }
260
261 //
262 //
263 //
264 static int i2cKickOff (U8 address, U8 *buffer, int bufferLenWrite, int bufferLenRead, ackPoll_e ackPoll)
265 {
266   //
267   //  Determine if our first operation will be a write or read.  If both, the
268   //  write always occurs first.
269   //
270   if (bufferLenWrite)
271     address &= ~0x01;
272   else if (bufferLenRead)
273     address |= 0x01;
274   else
275     address &= ~0x01;
276
277   //
278   //  Wait until last I2C operation has finished.  
279   //
280   if (i2cBusInUse && i2cWaitComplete (i2cTimeoutInTicks))
281   {
282     i2cErrno = I2CERR_TIMEOUT;
283     return -1;
284   }
285
286   //
287   //  Mark bus as in use, save the address, buffer and length
288   //
289   i2cBusInUse = TRUE;
290   i2cAddress = address;
291   i2cDataBuffer = buffer;
292   i2cDataLenWrite = bufferLenWrite;
293   i2cDataLenRead = bufferLenRead;
294   i2cDataCnt = 0;
295   i2cAckPoll = ackPoll;
296   i2cDebugReset ();
297
298   //
299   //  Clear any outstanding bits, enable the interface, and send a start bit.
300   //  Once the start bit goes out, the interrupt drive state machine begins.
301   //
302   I2C0_CONCLR = I2C_CONCLR_MASK;
303   I2C0_CONSET = I2C_CONSET_I2EN;
304   I2C0_CONSET = I2C_CONSET_STA;
305
306   return 0;
307 }
308
309 //
310 //
311 //
312 static int i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
313 {
314   int r;
315
316   if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
317     r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
318
319   return r;
320 }
321
322 static int i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
323 {
324   int r;
325
326   if (!(r = i2cKickOff (address, buffer, 0, bufferLength, ACKPOLL_NO)))
327     r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
328
329   return r;
330 }
331
332 static int i2cWriteReadBufferEx (U8 address, U8 *buffer, U32 putLength, U32 getLength, int milliseconds)
333 {
334   int r;
335
336   if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
337     r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
338
339   return r;
340 }
341
342 //
343 //
344 //
345 void i2cSetTimeout (unsigned int timeoutInMilliseconds)
346 {
347   if (timeoutInMilliseconds < portTICK_RATE_MS)
348     timeoutInMilliseconds = portTICK_RATE_MS;
349
350   i2cTimeoutInTicks = timeoutInMilliseconds / portTICK_RATE_MS;
351 }
352
353 void i2cDump (void)
354 {
355 #ifdef I2C_DEBUG
356   int i;
357
358   for (i = 0; i < i2cTransactionsIndex; i++)
359     printf ("0x%02x ", i2cTransactions [i]);
360
361   printf ("\n");
362 #else
363   printf ("Not compiled for i2c debugging\n");
364 #endif
365 }
366
367 //
368 //  DANGER, WILL ROBINSON!  The callers buffer must persist until we're done
369 //
370 int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
371 {
372   return i2cWriteBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
373 }
374
375 int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
376 {
377   return i2cReadBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
378 }
379
380 int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
381 {
382   return i2cWriteReadBufferEx (address, buffer, putLength, getLength, i2cTimeoutInTicks);
383 }
384
385 int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength)
386 {
387   int r;
388
389   if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
390     if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
391       r = i2cPoll (address);
392
393   return r;
394 }
395
396 int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength)
397 {
398   int r;
399
400   if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
401     if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
402       r = i2cPoll (address);
403
404   return r;
405 }