]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/I2C/i2c.c
Create directory structure to hold the (not yet created) Keil and IAR demo projects...
[freertos] / Demo / CORTEX_A2F200_IAR_and_Keil / MicroSemi_Code / drivers / I2C / i2c.c
1 /*******************************************************************************\r
2  * (c) Copyright 2007-2008 Actel Corporation.  All rights reserved.\r
3  *\r
4  * SmartFusion microcontroller subsystem I2C bare metal software driver\r
5  * implementation.\r
6  *\r
7  * SVN $Revision: 2152 $\r
8  * SVN $Date: 2010-02-11 14:44:11 +0000 (Thu, 11 Feb 2010) $\r
9  */\r
10 #include "i2c.h"\r
11 #include "../../CMSIS/mss_assert.h"\r
12 \r
13 #ifdef __cplusplus\r
14 extern "C" {\r
15 #endif\r
16 \r
17 /*------------------------------------------------------------------------------\r
18  * I2C transaction direction.\r
19  */\r
20 #define WRITE_DIR       0\r
21 #define READ_DIR        1\r
22 \r
23 /* -- TRANSACTIONS TYPES -- */\r
24 #define NO_TRANSACTION                                          0\r
25 #define MASTER_WRITE_TRANSACTION                        1\r
26 #define MASTER_READ_TRANSACTION                         2\r
27 #define MASTER_RANDOM_READ_TRANSACTION          3\r
28 #define WRITE_SLAVE_TRANSACTION                         4\r
29 #define READ_SLAVE_TRANSACTION                          5\r
30 #define RANDOM_READ_SLAVE_TRANSACTION           6\r
31 \r
32 \r
33 /* -- SMBUS H/W STATES -- */\r
34 /* -- MASTER STATES -- */\r
35 #define ST_START                0x08            /* start condition sent */\r
36 #define ST_RESTART              0x10            /* repeated start */\r
37 #define ST_SLAW_ACK     0x18            /* SLA+W sent, ack received */\r
38 #define ST_SLAW_NACK    0x20            /* SLA+W sent, nack received */\r
39 #define ST_TX_DATA_ACK  0x28            /* Data sent, ACK'ed */\r
40 #define ST_TX_DATA_NACK 0x30            /* Data sent, NACK'ed */\r
41 #define ST_LOST_ARB     0x38            /* Master lost arbitration */\r
42 #define ST_SLAR_ACK     0x40            /* SLA+R sent, ACK'ed */\r
43 #define ST_SLAR_NACK    0x48            /* SLA+R sent, NACK'ed */\r
44 #define ST_RX_DATA_ACK  0x50            /* Data received, ACK sent */\r
45 #define ST_RX_DATA_NACK 0x58            /* Data received, NACK sent */\r
46 \r
47 /* -- SLAVE STATES -- */\r
48 #define ST_SLAVE_SLAW       0x60                        /* SLA+W received */\r
49 #define ST_SLAVE_SLAR_ACK   0xA8                        /* SLA+R received, ACK returned */\r
50 #define ST_SLV_LA           0x68                        /* Slave lost arbitration */\r
51 #define ST_GCA              0x70                        /* GCA received */\r
52 #define ST_GCA_LA           0x78                        /* GCA lost arbitration */\r
53 #define ST_RDATA            0x80                        /* Data received */\r
54 #define ST_SLA_NACK         0x88                        /* Slave addressed, NACK returned */\r
55 #define ST_GCA_ACK          0x90                        /* Previously addresses with GCA, data ACKed */\r
56 #define ST_GCA_NACK         0x98                        /* GCA addressed, NACK returned */\r
57 #define ST_RSTOP            0xA0                        /* Stop received */\r
58 #define ST_REPEAT           0xA0                        /* Repeated start received */\r
59 #define ST_SLAR_ACKS        0xA8                        /* Slave read received, ACKed */\r
60 #define ST_SLARW_LA         0xB0                        /* Arbitration lost */\r
61 #define ST_RACK             0xB8                        /* Byte sent, ACK received */\r
62 #define ST_SLAVE_RNACK      0xC0                        /* Byte sent, NACK received */\r
63 #define ST_FINAL            0xC8                        /* Final byte sent, ACK received */\r
64 #define ST_BERR             0x00                        /* Error on the bus */\r
65 #define ST_SLV_RST          0xD8                        /* Slave reset state */\r
66 \r
67 /*------------------------------------------------------------------------------\r
68  *\r
69  */\r
70 static uint32_t disable_interrupts( void );\r
71 static void restore_interrupts( uint32_t primask );\r
72 static void mss_i2c_isr( mss_i2c_instance_t * this_i2c );\r
73 \r
74 /*------------------------------------------------------------------------------\r
75  *\r
76  *------------------------------------------------------------------------------\r
77  *\r
78  */\r
79 mss_i2c_instance_t g_mss_i2c0;\r
80 mss_i2c_instance_t g_mss_i2c1;\r
81 \r
82 /*------------------------------------------------------------------------------\r
83  * MSS_I2C_init()\r
84  * See "mss_i2c.h" for details of how to use this function.\r
85  */\r
86 void MSS_I2C_init\r
87 (\r
88         mss_i2c_instance_t * this_i2c,\r
89         uint8_t ser_address,\r
90         mss_i2c_clock_divider_t ser_clock_speed\r
91 )\r
92 {\r
93     uint_fast16_t clock_speed = ser_clock_speed;\r
94 \r
95     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
96 \r
97     if ( this_i2c == &g_mss_i2c0 )\r
98     {\r
99         this_i2c->irqn = I2C0_IRQn;\r
100         this_i2c->hw_reg = I2C0;\r
101         this_i2c->hw_reg_bit = I2C0_BITBAND;\r
102 \r
103         /* reset I2C0 */\r
104         SYSREG->SOFT_RST_CR |= SYSREG_I2C0_SOFTRESET_MASK;\r
105         /* Clear any previously pended I2C0 interrupt */\r
106         NVIC_ClearPendingIRQ( I2C0_IRQn );\r
107         /* Take I2C0 out of reset. */\r
108         SYSREG->SOFT_RST_CR &= ~SYSREG_I2C0_SOFTRESET_MASK;\r
109     }\r
110     else\r
111     {\r
112         this_i2c->irqn = I2C1_IRQn;\r
113         this_i2c->hw_reg = I2C1;\r
114         this_i2c->hw_reg_bit = I2C1_BITBAND;\r
115 \r
116         /* reset I2C1 */\r
117         SYSREG->SOFT_RST_CR |= SYSREG_I2C1_SOFTRESET_MASK;\r
118         /* Clear any previously pended I2C1 interrupt */\r
119         NVIC_ClearPendingIRQ( I2C1_IRQn );\r
120         /* Take I2C1 out of reset. */\r
121         SYSREG->SOFT_RST_CR &= ~SYSREG_I2C1_SOFTRESET_MASK;\r
122     }\r
123 \r
124         this_i2c->transaction = NO_TRANSACTION;\r
125 \r
126         this_i2c->ser_address = ser_address;\r
127 \r
128         this_i2c->tx_buffer = 0;\r
129         this_i2c->tx_size = 0;\r
130         this_i2c->tx_idx = 0;\r
131 \r
132         this_i2c->rx_buffer = 0;\r
133         this_i2c->rx_size = 0;\r
134         this_i2c->rx_idx = 0;\r
135 \r
136     this_i2c->status = MSS_I2C_SUCCESS;\r
137 \r
138         this_i2c->random_read_addr = 0;\r
139 \r
140         this_i2c->slave_write_handler = 0;\r
141         this_i2c->slave_mem_offset_length = 0;\r
142 \r
143     this_i2c->hw_reg_bit->CTRL_ENS1 = 0x01; /* set enable bit */\r
144     this_i2c->hw_reg_bit->CTRL_CR2 = (clock_speed >> 2) & 0x01;\r
145     this_i2c->hw_reg_bit->CTRL_CR1 = (clock_speed >> 1) & 0x01;\r
146     this_i2c->hw_reg_bit->CTRL_CR0 = clock_speed & 0x01;\r
147     this_i2c->hw_reg->ADDR = this_i2c->ser_address;\r
148 }\r
149 \r
150 /*------------------------------------------------------------------------------\r
151  * MSS_I2C_set_slave_mem_offset_length()\r
152  * See "mss_i2c.h" for details of how to use this function.\r
153  */\r
154 void MSS_I2C_set_slave_mem_offset_length\r
155 (\r
156         mss_i2c_instance_t * this_i2c,\r
157         uint8_t offset_length\r
158 )\r
159 {\r
160     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
161 \r
162         this_i2c->slave_mem_offset_length = offset_length;\r
163 }\r
164 \r
165 /*------------------------------------------------------------------------------\r
166  * MSS_I2C_register_write_handler()\r
167  * See "mss_i2c.h" for details of how to use this function.\r
168  */\r
169 void MSS_I2C_register_write_handler\r
170 (\r
171         mss_i2c_instance_t * this_i2c,\r
172         mss_i2c_slave_wr_handler_t handler\r
173 )\r
174 {\r
175     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
176 \r
177         this_i2c->slave_write_handler = handler;\r
178 }\r
179 \r
180 /*------------------------------------------------------------------------------\r
181  * MSS_I2C_write()\r
182  * See "mss_i2c.h" for details of how to use this function.\r
183  */\r
184 void MSS_I2C_write\r
185 (\r
186         mss_i2c_instance_t * this_i2c,\r
187         uint8_t serial_addr,\r
188         const uint8_t * write_buffer,\r
189         uint16_t write_size,\r
190     uint8_t options\r
191 )\r
192 {\r
193     volatile uint8_t stat_ctrl;\r
194     uint8_t serial_interrupt;\r
195 \r
196         uint32_t primask;\r
197 \r
198     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
199 \r
200         primask = disable_interrupts();\r
201 \r
202         this_i2c->transaction = MASTER_WRITE_TRANSACTION;\r
203 \r
204         this_i2c->target_addr = serial_addr;\r
205         this_i2c->dir = WRITE_DIR;\r
206         this_i2c->tx_buffer = write_buffer;\r
207         this_i2c->tx_size = write_size;\r
208         this_i2c->tx_idx = 0;\r
209 \r
210     this_i2c->status = MSS_I2C_IN_PROGRESS;\r
211     this_i2c->options = options;\r
212 \r
213     /* Clear interrupts if required (depends on repeated starts).*/\r
214     serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;\r
215     this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
216 \r
217     if ( serial_interrupt != 0 )\r
218     {\r
219         this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
220         NVIC_ClearPendingIRQ( this_i2c->irqn );\r
221     }\r
222 \r
223     stat_ctrl = this_i2c->hw_reg->STATUS;\r
224 \r
225     NVIC_EnableIRQ( this_i2c->irqn );\r
226 \r
227     restore_interrupts( primask );\r
228 }\r
229 \r
230 /*------------------------------------------------------------------------------\r
231  * MSS_I2C_read()\r
232  * See "mss_i2c.h" for details of how to use this function.\r
233  */\r
234 void MSS_I2C_read\r
235 (\r
236         mss_i2c_instance_t * this_i2c,\r
237         uint8_t serial_addr,\r
238         uint8_t * read_buffer,\r
239         uint16_t read_size,\r
240     uint8_t options\r
241 )\r
242 {\r
243         uint32_t primask;\r
244 \r
245     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
246 \r
247         if ( read_size > 0 )\r
248         {\r
249         volatile uint8_t stat_ctrl;\r
250         uint8_t serial_interrupt;\r
251 \r
252                 primask = disable_interrupts();\r
253 \r
254                 this_i2c->transaction = MASTER_READ_TRANSACTION;\r
255 \r
256                 this_i2c->target_addr = serial_addr;\r
257                 this_i2c->dir = READ_DIR;\r
258                 this_i2c->rx_buffer = read_buffer;\r
259                 this_i2c->rx_size = read_size;\r
260                 this_i2c->rx_idx = 0;\r
261 \r
262         this_i2c->status = MSS_I2C_IN_PROGRESS;\r
263 \r
264         this_i2c->options = options;\r
265 \r
266         /* Clear interrupts if required (depends on repeated starts).*/\r
267         serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;\r
268         this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
269 \r
270         if ( serial_interrupt != 0 )\r
271         {\r
272             this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
273             NVIC_ClearPendingIRQ( this_i2c->irqn );\r
274         }\r
275 \r
276         stat_ctrl = this_i2c->hw_reg->STATUS;\r
277 \r
278         NVIC_EnableIRQ( this_i2c->irqn );\r
279 \r
280         restore_interrupts( primask );\r
281         }\r
282 }\r
283 \r
284 /*------------------------------------------------------------------------------\r
285  * MSS_I2C_write_read()\r
286  * See "mss_i2c.h" for details of how to use this function.\r
287  */\r
288 void MSS_I2C_write_read\r
289 (\r
290         mss_i2c_instance_t * this_i2c,\r
291         uint8_t serial_addr,\r
292         const uint8_t * addr_offset,\r
293         uint16_t offset_size,\r
294         uint8_t * read_buffer,\r
295         uint16_t read_size,\r
296     uint8_t options\r
297 )\r
298 {\r
299     volatile uint8_t stat_ctrl;\r
300     uint8_t serial_interrupt;\r
301         uint32_t primask;\r
302 \r
303     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
304 \r
305         primask = disable_interrupts();\r
306 \r
307         this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION;\r
308         this_i2c->target_addr = serial_addr;\r
309         this_i2c->dir = WRITE_DIR;\r
310         this_i2c->tx_buffer = addr_offset;\r
311         this_i2c->tx_size = offset_size;\r
312         this_i2c->tx_idx = 0;\r
313 \r
314         this_i2c->rx_buffer = read_buffer;\r
315         this_i2c->rx_size = read_size;\r
316         this_i2c->rx_idx = 0;\r
317 \r
318     this_i2c->status = MSS_I2C_IN_PROGRESS;\r
319     this_i2c->options = options;\r
320 \r
321     /* Clear interrupts if required (depends on repeated starts).*/\r
322     serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;\r
323     this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
324 \r
325     if ( serial_interrupt != 0 )\r
326     {\r
327         this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
328         NVIC_ClearPendingIRQ( this_i2c->irqn );\r
329     }\r
330 \r
331     stat_ctrl = this_i2c->hw_reg->STATUS;\r
332 \r
333     NVIC_EnableIRQ( this_i2c->irqn );\r
334 \r
335     restore_interrupts( primask );\r
336 }\r
337 \r
338 /*------------------------------------------------------------------------------\r
339  * MSS_I2C_set_slave_rx_buffer()\r
340  * See "mss_i2c.h" for details of how to use this function.\r
341  */\r
342 void MSS_I2C_set_slave_rx_buffer\r
343 (\r
344         mss_i2c_instance_t * this_i2c,\r
345         uint8_t * rx_buffer,\r
346         uint16_t rx_size\r
347 )\r
348 {\r
349         uint32_t primask;\r
350 \r
351     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
352 \r
353         primask = disable_interrupts();\r
354 \r
355         this_i2c->rx_buffer = rx_buffer;\r
356         this_i2c->rx_size = rx_size;\r
357         this_i2c->rx_idx = 0;\r
358 \r
359         restore_interrupts( primask );\r
360 }\r
361 \r
362 \r
363 /*------------------------------------------------------------------------------\r
364  * MSS_I2C_get_status()\r
365  * See "mss_i2c.h" for details of how to use this function.\r
366  */\r
367 mss_i2c_status_t MSS_I2C_get_status\r
368 (\r
369     mss_i2c_instance_t * this_i2c\r
370 )\r
371 {\r
372     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
373 \r
374     return this_i2c->status;\r
375 }\r
376 \r
377 /*------------------------------------------------------------------------------\r
378  * MSS_I2C_set_slave_tx_buffer()\r
379  * See "mss_i2c.h" for details of how to use this function.\r
380  */\r
381 void MSS_I2C_set_slave_tx_buffer\r
382 (\r
383         mss_i2c_instance_t * this_i2c,\r
384         uint8_t * tx_buffer,\r
385         uint16_t tx_size\r
386 )\r
387 {\r
388         uint32_t primask;\r
389 \r
390     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
391 \r
392         primask = disable_interrupts();\r
393 \r
394         this_i2c->tx_buffer = tx_buffer;\r
395         this_i2c->tx_size = tx_size;\r
396         this_i2c->tx_idx = 0;\r
397 \r
398         restore_interrupts( primask );\r
399 \r
400         /* Set the assert acknowledge bit. */\r
401     this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
402 }\r
403 \r
404 /*------------------------------------------------------------------------------\r
405  * MSS_I2C_enable_slave_rx()\r
406  * See "mss_i2c.h" for details of how to use this function.\r
407  */\r
408 void MSS_I2C_enable_slave_rx\r
409 (\r
410         mss_i2c_instance_t * this_i2c\r
411 )\r
412 {\r
413     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
414 \r
415         /* Set the assert acknowledge bit. */\r
416     this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
417         /* accept GC addressing. */\r
418     this_i2c->hw_reg_bit->ADDR_GC = 0x01;\r
419 \r
420     NVIC_EnableIRQ( this_i2c->irqn );\r
421 }\r
422 \r
423 /*------------------------------------------------------------------------------\r
424  * MSS_I2C_wait_complete()\r
425  * See "mss_i2c.h" for details of how to use this function.\r
426  */\r
427 mss_i2c_status_t MSS_I2C_wait_complete\r
428 (\r
429     mss_i2c_instance_t * this_i2c\r
430 )\r
431 {\r
432     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
433 \r
434     while ( this_i2c->status == MSS_I2C_IN_PROGRESS )\r
435     {\r
436         /* Wait for transaction to compltete.*/\r
437         ;\r
438     }\r
439     return this_i2c->status;\r
440 }\r
441 \r
442 /*------------------------------------------------------------------------------\r
443  * MSS I2C interrupt service routine.\r
444  *------------------------------------------------------------------------------\r
445  * Parameters:\r
446  *\r
447  *      mss_i2c_instance_t * this_i2c:\r
448  *              Pointer to the mss_i2c_instance_t data structure holding all data related to\r
449  *              the     MSS I2C instance that generated the interrupt.\r
450  */\r
451 static void mss_i2c_isr\r
452 (\r
453         mss_i2c_instance_t * this_i2c\r
454 )\r
455 {\r
456         volatile uint8_t status;\r
457         uint8_t data;\r
458     uint8_t hold_bus;\r
459     uint8_t clear_irq = 1;\r
460 \r
461     ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
462 \r
463     status = this_i2c->hw_reg->STATUS;\r
464 \r
465         switch( status )\r
466         {\r
467             /************** MASTER TRANSMITTER / RECEIVER *******************/\r
468 \r
469             case ST_START: /* start has been xmt'd */\r
470             case ST_RESTART: /* repeated start has been xmt'd */\r
471             this_i2c->hw_reg_bit->CTRL_STA = 0x0;\r
472             this_i2c->hw_reg->DATA = this_i2c->target_addr;\r
473             this_i2c->hw_reg_bit->DATA_DIR = this_i2c->dir;\r
474 \r
475                 this_i2c->tx_idx = 0;\r
476                 this_i2c->rx_idx = 0;\r
477                 break;\r
478 \r
479             case ST_LOST_ARB:\r
480                         /* Set start bit.  Let's keep trying!  Don't give up! */\r
481             this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
482                         break;\r
483 \r
484             /******************* MASTER TRANSMITTER *************************/\r
485             case ST_SLAW_ACK:\r
486                 /* call address has been xmt'd with ACK, time to send data byte and increment index. */\r
487             if ( this_i2c->tx_idx < this_i2c->tx_size )\r
488             {\r
489                 /* load data byte */\r
490                 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
491             }\r
492             else\r
493             {\r
494                 NVIC_DisableIRQ( this_i2c->irqn );\r
495             }\r
496                 break;\r
497 \r
498             case ST_SLAW_NACK:\r
499 #if 0\r
500                 /* SLA+W has been transmitted; not ACK has been received - let's stop. */\r
501             this_i2c->hw_reg_bit->CTRL_STO = 0x01;\r
502             this_i2c->status = MSS_I2C_FAILED;\r
503 #endif\r
504                 /* call address has been xmt'd with ACK, time to send data byte and increment index. */\r
505             if ( this_i2c->tx_idx < this_i2c->tx_size )\r
506             {\r
507                 /* load data byte */\r
508                 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
509             }\r
510             else\r
511             {\r
512                 NVIC_DisableIRQ( this_i2c->irqn );\r
513             }\r
514                         break;\r
515 \r
516             case ST_TX_DATA_ACK:\r
517                         /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */\r
518                         if (this_i2c->tx_idx < this_i2c->tx_size)\r
519                         {\r
520                 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
521                         }\r
522                         else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )\r
523                         {\r
524                                 /* We are finished sending the address offset part of a random read transaction.\r
525                                  * It is is time to send a restart in order to change direction. */\r
526                                  this_i2c->dir = READ_DIR;\r
527                  this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
528                         }\r
529                         else /* done sending. let's stop */\r
530                         {\r
531                 hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;\r
532                 if ( hold_bus == 0 )\r
533                 {\r
534                     this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */\r
535                 }\r
536                 else\r
537                 {\r
538                     NVIC_DisableIRQ( this_i2c->irqn );\r
539                     clear_irq = 0;\r
540                 }\r
541                 this_i2c->status = MSS_I2C_SUCCESS;\r
542                         }\r
543                         break;\r
544 \r
545                   case ST_TX_DATA_NACK:\r
546 #if 0\r
547                          /* data byte SENT, ACK to be received\r
548                      * In fact, this means we've received a NACK (This may not be\r
549              * obvious, but if we've rec'd an ACK then we would be in state\r
550              * 0x28!) hence, let's send a stop bit\r
551              */\r
552             this_i2c->hw_reg_bit->CTRL_STO = 0x01;\r
553             this_i2c->status = MSS_I2C_FAILED;\r
554 #endif\r
555                         /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */\r
556                         if (this_i2c->tx_idx < this_i2c->tx_size)\r
557                         {\r
558                 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
559                         }\r
560                         else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )\r
561                         {\r
562                                 /* We are finished sending the address offset part of a random read transaction.\r
563                                  * It is is time to send a restart in order to change direction. */\r
564                                  this_i2c->dir = READ_DIR;\r
565                  this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
566                         }\r
567                         else /* done sending. let's stop */\r
568                         {\r
569                 hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;\r
570                 if ( hold_bus == 0 )\r
571                 {\r
572                     this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */\r
573                 }\r
574                 else\r
575                 {\r
576                     NVIC_DisableIRQ( this_i2c->irqn );\r
577                     clear_irq = 0;\r
578                 }\r
579                 this_i2c->status = MSS_I2C_SUCCESS;\r
580                         }\r
581             break;\r
582 \r
583           /********************* MASTER (or slave?) RECEIVER *************************/\r
584 \r
585           /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */\r
586                 case ST_SLAR_ACK: /* SLA+R tx'ed. */\r
587                         /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless\r
588                          * the next byte is the last byte of the read transaction.\r
589              */\r
590                         if( this_i2c->rx_size > 1 )\r
591                         {\r
592                 this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
593                         }\r
594                         else\r
595                         {\r
596                 this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
597                         }\r
598                         break;\r
599 \r
600                 case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */\r
601             this_i2c->hw_reg_bit->CTRL_STO = 0x01;\r
602             this_i2c->status = MSS_I2C_FAILED;\r
603                         break;\r
604 \r
605                 case ST_RX_DATA_ACK: /* Data byte received, ACK returned */\r
606                         /* First, get the data */\r
607             this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;\r
608 \r
609                         if( this_i2c->rx_idx >= this_i2c->rx_size - 1)\r
610                         {\r
611                                 /* If we're at the second last byte, let's set AA to 0 so\r
612                                  * we return a NACK at the last byte. */\r
613                 this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
614                         }\r
615                         break;\r
616 \r
617             case ST_RX_DATA_NACK: /* Data byte received, NACK returned */\r
618             /* Get the data, then send a stop condition */\r
619             this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;\r
620 \r
621             hold_bus = this_i2c->options &  MSS_I2C_HOLD_BUS;\r
622             if ( hold_bus == 0 )\r
623             {\r
624                 this_i2c->hw_reg_bit->CTRL_STO = 0x01;  /*xmt stop condition */\r
625             }\r
626             else\r
627             {\r
628                 NVIC_DisableIRQ( this_i2c->irqn );\r
629                 clear_irq = 0;\r
630             }\r
631 \r
632             this_i2c->status = MSS_I2C_SUCCESS;\r
633             break;\r
634 \r
635                 /******************** SLAVE RECEIVER **************************/\r
636                 case ST_GCA_NACK: /* NACK after, GCA addressing */\r
637                 case ST_SLA_NACK: /* Get Data, but also re-enable AA (assert ack) bit for future transmissions */\r
638                         if ( this_i2c->rx_buffer != 0 )\r
639                         {\r
640                 this_i2c->rx_buffer[this_i2c->rx_idx] = this_i2c->hw_reg->DATA;\r
641                         }\r
642             this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
643                         break;\r
644 \r
645                 case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */\r
646                         this_i2c->transaction = WRITE_SLAVE_TRANSACTION;\r
647                         this_i2c->rx_idx = 0;\r
648                         this_i2c->random_read_addr = 0;\r
649 #ifndef INCLUDE_SLA_IN_RX_PAYLOAD\r
650                         /* Only break from this case if the slave address must NOT be included at the\r
651                          * beginning of the received write data. */\r
652                         break;\r
653 #endif\r
654                 case ST_GCA_ACK: /* DATA received; ACK sent after GCA */\r
655                 case ST_RDATA: /* DATA received; must clear DATA register */\r
656                         if (this_i2c->rx_idx >= this_i2c->rx_size - 2)\r
657                         {\r
658                 this_i2c->hw_reg_bit->CTRL_AA = 0x00;   /* send a NACK when done (next reception) */\r
659                         }\r
660             data = this_i2c->hw_reg->DATA;\r
661                         this_i2c->rx_buffer[this_i2c->rx_idx++] = data;\r
662                         this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data;\r
663 \r
664                         break;\r
665 \r
666                 case ST_RSTOP:\r
667                         /* STOP or repeated START occured. */\r
668                         /* We cannot be sure if the transaction has actually completed as\r
669                          * this hardware state reports that either a STOP or repeated START\r
670                          * condition has occured. We assume that this is a repeated START\r
671                          * if the transaction was a write from the master to this point.*/\r
672                         if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION )\r
673                         {\r
674                                 if ( this_i2c->rx_idx == this_i2c->slave_mem_offset_length )\r
675                                 {\r
676                                         this_i2c->transaction = RANDOM_READ_SLAVE_TRANSACTION;\r
677                                         this_i2c->tx_idx = this_i2c->random_read_addr;\r
678                                 }\r
679                                 else\r
680                                 {\r
681                                         /* Call the slave's write transaction handler if it exists. */\r
682                                         if ( this_i2c->slave_write_handler != 0 )\r
683                                         {\r
684                                                 mss_i2c_slave_handler_ret_t h_ret;\r
685                                                 h_ret = this_i2c->slave_write_handler( this_i2c->rx_buffer, (uint16_t)this_i2c->rx_idx );\r
686                                                 if ( MSS_I2C_REENABLE_SLAVE_RX == h_ret )\r
687                                                 {\r
688                             this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
689                                                 }\r
690                                                 else\r
691                                                 {\r
692                             this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
693                                                 }\r
694                                         }\r
695                                 }\r
696                         }\r
697                         /* Mark any previous master write transaction as complete. */\r
698             this_i2c->status = MSS_I2C_SUCCESS;\r
699                         break;\r
700 \r
701                 case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */\r
702                 case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */\r
703                 case ST_GCA: /* General call address received, ACK returned */\r
704                 case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */\r
705                         /* do nothing */\r
706                         break;\r
707 \r
708                 /****************** SLAVE TRANSMITTER **************************/\r
709                 case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */\r
710                 case ST_SLARW_LA: /* Arbitration lost, and: */\r
711                 case ST_RACK: /* Data tx'ed, ACK received */\r
712             if ( status == ST_SLAVE_SLAR_ACK )\r
713             {\r
714                 this_i2c->transaction = READ_SLAVE_TRANSACTION;\r
715                 this_i2c->random_read_addr = 0;\r
716             }\r
717                         /* Load the data, and determine if it is the last one */\r
718             this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
719                         if (this_i2c->tx_idx >= this_i2c->tx_size - 1) /* last byte? */\r
720                         {\r
721                 this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
722                                 /* Next read transaction will result in slave's transmit buffer\r
723                                  * being sent from the first byte. */\r
724                                 this_i2c->tx_idx = 0;\r
725                         }\r
726                         break;\r
727 \r
728                 case ST_SLAVE_RNACK:    /* Data byte has been transmitted; not-ACK has been received. */\r
729                         /* We assume that the transaction will be stopped by the master.\r
730                          * Reset tx_idx so that a subsequent read will result in the slave's\r
731                          * transmit buffer being sent from the first byte. */\r
732                         this_i2c->tx_idx = 0;\r
733                         break;\r
734 \r
735                 case ST_FINAL: /* Last Data byte tx'ed, ACK recieved */\r
736                 default:\r
737                         /* do nothing */\r
738                         break;\r
739         }\r
740 \r
741     if ( clear_irq )\r
742     {\r
743         /* clear interrupt. */\r
744         this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
745     }\r
746 \r
747     /* Read the status register to ensure the last I2C registers write took place\r
748      * in a system built around a bus making use of posted writes. */\r
749     status = this_i2c->hw_reg->STATUS;\r
750 }\r
751 \r
752 /*------------------------------------------------------------------------------\r
753  *\r
754  */\r
755 uint32_t disable_interrupts( void )\r
756 {\r
757     uint32_t primask;\r
758     primask = __get_PRIMASK();\r
759     return primask;\r
760 }\r
761 \r
762 /*------------------------------------------------------------------------------\r
763  *\r
764  */\r
765 void restore_interrupts( uint32_t primask )\r
766 {\r
767     __set_PRIMASK( primask );\r
768 }\r
769 \r
770 /*------------------------------------------------------------------------------\r
771  *\r
772  */\r
773 #if defined(__GNUC__)\r
774 __attribute__((__interrupt__)) void I2C0_IRQHandler( void )\r
775 #else\r
776 void I2C0_IRQHandler( void )\r
777 #endif\r
778 {\r
779         mss_i2c_isr( &g_mss_i2c0 );\r
780     NVIC_ClearPendingIRQ( I2C0_IRQn );\r
781 }\r
782 \r
783 /*------------------------------------------------------------------------------\r
784  *\r
785  */\r
786 #if defined(__GNUC__)\r
787 __attribute__((__interrupt__)) void I2C1_IRQHandler( void )\r
788 #else\r
789 void I2C1_IRQHandler( void )\r
790 #endif\r
791 {\r
792         mss_i2c_isr( &g_mss_i2c1 );\r
793     NVIC_ClearPendingIRQ( I2C1_IRQn );\r
794 }\r
795 \r
796 #ifdef __cplusplus\r
797 }\r
798 #endif\r