]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_Renode_Emulator_SoftConsole/Microsemi_Code/drivers/CoreI2C/core_i2c.c
Update to the latest atomic.h.
[freertos] / FreeRTOS / Demo / RISC-V_Renode_Emulator_SoftConsole / Microsemi_Code / drivers / CoreI2C / core_i2c.c
1 /*******************************************************************************\r
2  * (c) Copyright 2009-2015 Microsemi  SoC Products Group.  All rights reserved.\r
3  * \r
4  * CoreI2C software driver implementation.\r
5  * \r
6  * SVN $Revision: 7984 $\r
7  * SVN $Date: 2015-10-12 12:07:40 +0530 (Mon, 12 Oct 2015) $\r
8  */\r
9 #include <stdint.h>\r
10 #include <stdlib.h>\r
11 #include <stddef.h>\r
12 #include <unistd.h>\r
13 #include <errno.h>\r
14 #include <sys/stat.h>\r
15 #include <sys/times.h>\r
16 #include <stdio.h>\r
17 #include <string.h>\r
18 #include "cpu_types.h"\r
19 #include "core_smbus_regs.h"\r
20 #include "core_i2c.h"\r
21 #include "hal.h"\r
22 #include "hal_assert.h"\r
23 \r
24 \r
25 #include <string.h>\r
26 \r
27 #ifdef __cplusplus\r
28 extern "C" {\r
29 #endif\r
30 \r
31 /*------------------------------------------------------------------------------\r
32  * I2C transaction direction.\r
33  */\r
34 #define WRITE_DIR    0u\r
35 #define READ_DIR     1u\r
36 \r
37 /* -- TRANSACTIONS TYPES -- */\r
38 #define NO_TRANSACTION                      0u\r
39 #define MASTER_WRITE_TRANSACTION            1u\r
40 #define MASTER_READ_TRANSACTION             2u\r
41 #define MASTER_RANDOM_READ_TRANSACTION      3u\r
42 #define WRITE_SLAVE_TRANSACTION             4u\r
43 #define READ_SLAVE_TRANSACTION              5u\r
44 \r
45 /* -- SMBUS H/W STATES -- */\r
46 /* -- MASTER STATES -- */\r
47 #define ST_BUS_ERROR        0x00u           /* Bus error during MST or selected slave modes */\r
48 #define ST_I2C_IDLE         0xF8u           /* No activity and no interrupt either... */\r
49 #define ST_START            0x08u           /* start condition sent */\r
50 #define ST_RESTART          0x10u           /* repeated start */\r
51 #define ST_SLAW_ACK         0x18u           /* SLA+W sent, ack received */\r
52 #define ST_SLAW_NACK        0x20u           /* SLA+W sent, nack received */\r
53 #define ST_TX_DATA_ACK      0x28u           /* Data sent, ACK'ed */\r
54 #define ST_TX_DATA_NACK     0x30u           /* Data sent, NACK'ed */\r
55 #define ST_LOST_ARB         0x38u           /* Master lost arbitration */\r
56 #define ST_SLAR_ACK         0x40u           /* SLA+R sent, ACK'ed */\r
57 #define ST_SLAR_NACK        0x48u           /* SLA+R sent, NACK'ed */\r
58 #define ST_RX_DATA_ACK      0x50u           /* Data received, ACK sent */\r
59 #define ST_RX_DATA_NACK     0x58u           /* Data received, NACK sent */\r
60 #define ST_RESET_ACTIVATED  0xD0u           /* Master reset is activated */\r
61 #define ST_STOP_TRANSMIT    0xE0u           /* Stop has been transmitted */\r
62 \r
63 /* -- SLAVE STATES -- */\r
64 #define ST_SLAVE_SLAW       0x60u           /* SLA+W received */\r
65 #define ST_SLAVE_SLAR_ACK   0xA8u           /* SLA+R received, ACK returned */\r
66 #define ST_SLV_LA           0x68u           /* Slave lost arbitration */\r
67 #define ST_GCA              0x70u           /* GCA received */\r
68 #define ST_GCA_LA           0x78u           /* GCA lost arbitration */\r
69 #define ST_RDATA            0x80u           /* Data received */\r
70 #define ST_SLA_NACK         0x88u           /* Slave addressed, NACK returned */\r
71 #define ST_GCA_ACK          0x90u           /* Previously addresses with GCA, data ACKed */\r
72 #define ST_GCA_NACK         0x98u           /* GCA addressed, NACK returned */\r
73 #define ST_RSTOP            0xA0u           /* Stop received */\r
74 #define ST_SLARW_LA         0xB0u           /* Arbitration lost */\r
75 #define ST_RACK             0xB8u           /* Byte sent, ACK received */\r
76 #define ST_SLAVE_RNACK      0xC0u           /* Byte sent, NACK received */\r
77 #define ST_FINAL            0xC8u           /* Final byte sent, ACK received */\r
78 #define ST_SLV_RST          0xD8u           /* Slave reset state */\r
79 \r
80 \r
81 /* I2C Channel base offset */\r
82 #define CHANNEL_BASE_SHIFT    5u\r
83 #define CHANNEL_MASK        0x1E0u\r
84 \r
85 /*\r
86  * Maximum address offset length in slave write-read transactions.\r
87  * A maximum of two bytes will be interpreted as address offset within the slave\r
88  * tx buffer.\r
89  */\r
90 #define MAX_OFFSET_LENGTH       2u\r
91 \r
92 /*------------------------------------------------------------------------------\r
93  * I2C interrupts control functions implemented "i2c_interrupt.c".\r
94  * the implementation of these functions depend on the underlying hardware\r
95  * design and how the CoreI2C interrupt line is connected to the system's\r
96  * interrupt controller.\r
97  */\r
98 void I2C_enable_irq( i2c_instance_t * this_i2c );\r
99 void I2C_disable_irq( i2c_instance_t * this_i2c );\r
100 static void enable_slave_if_required(i2c_instance_t * this_i2c);\r
101 \r
102 /*------------------------------------------------------------------------------\r
103  * I2C_init()\r
104  * See "core_i2c.h" for details of how to use this function.\r
105  */\r
106 void I2C_init\r
107 (\r
108     i2c_instance_t * this_i2c,\r
109     addr_t base_address,\r
110     uint8_t ser_address,\r
111     i2c_clock_divider_t ser_clock_speed\r
112 )\r
113 {\r
114     psr_t saved_psr;\r
115     uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed;\r
116     \r
117     /*\r
118      * We need to disable ints while doing this as there is no guarantee we\r
119      * have not been called already and the ISR is active.\r
120      */\r
121 \r
122    saved_psr=HAL_disable_interrupts();\r
123     \r
124     /*\r
125      * Initialize all items of the this_i2c data structure to zero. This\r
126      * initializes all state variables to their init value. It relies on\r
127      * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all\r
128      * have an actual value of zero.\r
129      */\r
130     memset(this_i2c, 0, sizeof(i2c_instance_t));\r
131     \r
132     /*\r
133      * Set base address of I2C hardware used by this instance.\r
134      */\r
135     this_i2c->base_address = base_address;\r
136 \r
137     /*\r
138      * Update Serial address of the device\r
139      */\r
140     this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u);\r
141     \r
142     /*\r
143      * Configure hardware.\r
144      */\r
145     HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */\r
146     HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */\r
147     HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) );\r
148     HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) );\r
149     HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) );\r
150 \r
151     HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address);\r
152     HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address);\r
153     \r
154     /*\r
155      * Finally safe to enable interrupts.\r
156      */\r
157 \r
158         HAL_restore_interrupts( saved_psr );\r
159 }\r
160 /*------------------------------------------------------------------------------\r
161  * I2C_channel_init()\r
162  * See "core_i2c.h" for details of how to use this function.\r
163  */\r
164 void I2C_channel_init\r
165 (\r
166     i2c_instance_t * this_i2c_channel,\r
167     i2c_instance_t * this_i2c,\r
168     i2c_channel_number_t channel_number,\r
169     i2c_clock_divider_t ser_clock_speed\r
170 )\r
171 {\r
172     psr_t saved_psr;\r
173     uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed;\r
174     \r
175     HAL_ASSERT(channel_number < I2C_MAX_CHANNELS);\r
176     HAL_ASSERT(I2C_CHANNEL_0 != channel_number);\r
177 \r
178     /* \r
179      * Cannot allow channel 0 in this function as we will trash the hardware\r
180      * base address and slave address.\r
181      */\r
182     if ((channel_number < I2C_MAX_CHANNELS) &&\r
183         (I2C_CHANNEL_0 != channel_number))\r
184     {\r
185         /*\r
186          * We need to disable ints while doing this as the hardware should already\r
187          * be active at this stage.\r
188          */\r
189 \r
190         saved_psr=HAL_disable_interrupts();\r
191         /*\r
192          * Initialize channel data.\r
193          */\r
194         memset(this_i2c_channel, 0, sizeof(i2c_instance_t));\r
195         \r
196         this_i2c_channel->base_address =\r
197                ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) \r
198             | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT);\r
199 \r
200         this_i2c_channel->ser_address = this_i2c->ser_address;\r
201 \r
202         HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */\r
203         HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */\r
204         HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) );\r
205         HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) );\r
206         HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) );\r
207         /*\r
208          * Finally safe to enable interrupts.\r
209          */\r
210 \r
211         HAL_restore_interrupts( saved_psr );\r
212     }\r
213 }\r
214 \r
215 /*------------------------------------------------------------------------------\r
216  * I2C_write()\r
217  * See "core_i2c.h" for details of how to use this function.\r
218  */\r
219 void I2C_write\r
220 (\r
221     i2c_instance_t * this_i2c,\r
222     uint8_t serial_addr,\r
223     const uint8_t * write_buffer,\r
224     uint16_t write_size,\r
225     uint8_t options\r
226 )\r
227 {\r
228     psr_t saved_psr;\r
229     volatile uint8_t stat_ctrl;\r
230 \r
231 \r
232         saved_psr=HAL_disable_interrupts();\r
233 \r
234     /* Update the transaction only when there is no transaction going on I2C */\r
235     if( this_i2c->transaction == NO_TRANSACTION)\r
236     {\r
237       this_i2c->transaction = MASTER_WRITE_TRANSACTION;\r
238     }\r
239 \r
240     /* Update the Pending transaction information so that transaction can restarted */\r
241     this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ;\r
242 \r
243     /* Update target address */\r
244     this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u;\r
245     this_i2c->dir = WRITE_DIR;\r
246     this_i2c->master_tx_buffer = write_buffer;\r
247     this_i2c->master_tx_size = write_size;\r
248     this_i2c->master_tx_idx = 0u;\r
249 \r
250     /* Set I2C status in progress */\r
251     this_i2c->master_status = I2C_IN_PROGRESS;\r
252     this_i2c->options = options;\r
253 \r
254     if(I2C_IN_PROGRESS == this_i2c->slave_status)\r
255     {\r
256         this_i2c->is_transaction_pending = 1u;\r
257     }\r
258     else\r
259     {\r
260         HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
261     }\r
262 \r
263     /*\r
264      * Clear interrupts if required (depends on repeated starts).\r
265      * Since the Bus is on hold, only then prior status needs to\r
266      * be cleared.\r
267      */\r
268     if ( I2C_HOLD_BUS == this_i2c->bus_status )\r
269     {\r
270         HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u);\r
271     }\r
272 \r
273     stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS);\r
274     stat_ctrl = stat_ctrl;  /* Avoids lint warning. */\r
275 \r
276     /* Enable the interrupt. ( Re-enable) */\r
277     I2C_enable_irq( this_i2c );\r
278 \r
279 \r
280         HAL_restore_interrupts(saved_psr);\r
281 }\r
282 \r
283 /*------------------------------------------------------------------------------\r
284  * I2C_read()\r
285  * See "core_i2c.h" for details of how to use this function.\r
286  */\r
287 void I2C_read\r
288 (\r
289     i2c_instance_t * this_i2c,\r
290     uint8_t serial_addr,\r
291     uint8_t * read_buffer,\r
292     uint16_t read_size,\r
293     uint8_t options\r
294 )\r
295 {\r
296     psr_t saved_psr;\r
297     volatile uint8_t stat_ctrl;\r
298 \r
299 \r
300         saved_psr=HAL_disable_interrupts();\r
301     \r
302     /* Update the transaction only when there is no transaction going on I2C */\r
303     if( this_i2c->transaction == NO_TRANSACTION)\r
304     {\r
305       this_i2c->transaction = MASTER_READ_TRANSACTION;\r
306     }\r
307 \r
308     /* Update the Pending transaction information so that transaction can restarted */\r
309     this_i2c->pending_transaction = MASTER_READ_TRANSACTION ;\r
310 \r
311     /* Update target address */\r
312     this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u;\r
313 \r
314     this_i2c->dir = READ_DIR;\r
315 \r
316     this_i2c->master_rx_buffer = read_buffer;\r
317     this_i2c->master_rx_size = read_size;\r
318     this_i2c->master_rx_idx = 0u;\r
319 \r
320     /* Set I2C status in progress */\r
321     this_i2c->master_status = I2C_IN_PROGRESS;\r
322 \r
323     this_i2c->options = options;\r
324     \r
325     if(I2C_IN_PROGRESS == this_i2c->slave_status)\r
326     {\r
327         this_i2c->is_transaction_pending = 1u;\r
328     }\r
329     else\r
330     {\r
331         HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
332     }\r
333 \r
334     /*\r
335      * Clear interrupts if required (depends on repeated starts).\r
336      * Since the Bus is on hold, only then prior status needs to\r
337      * be cleared.\r
338      */\r
339     if ( I2C_HOLD_BUS == this_i2c->bus_status )\r
340     {\r
341         HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u);\r
342     }\r
343 \r
344     stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS);\r
345     stat_ctrl = stat_ctrl;  /* Avoids lint warning. */\r
346 \r
347     /* Enable the interrupt. ( Re-enable) */\r
348     I2C_enable_irq( this_i2c );\r
349 \r
350         HAL_restore_interrupts( saved_psr );\r
351 \r
352 }\r
353 \r
354 /*------------------------------------------------------------------------------\r
355  * I2C_write_read()\r
356  * See "core_i2c.h" for details of how to use this function.\r
357  */\r
358 void I2C_write_read\r
359 (\r
360     i2c_instance_t * this_i2c,\r
361     uint8_t serial_addr,\r
362     const uint8_t * addr_offset,\r
363     uint16_t offset_size,\r
364     uint8_t * read_buffer,\r
365     uint16_t read_size,\r
366     uint8_t options\r
367 )\r
368 {\r
369     HAL_ASSERT(offset_size > 0u);\r
370     HAL_ASSERT(addr_offset != (uint8_t *)0);\r
371     HAL_ASSERT(read_size > 0u);\r
372     HAL_ASSERT(read_buffer != (uint8_t *)0);\r
373     \r
374     this_i2c->master_status = I2C_FAILED;\r
375     \r
376     if((read_size > 0u) && (offset_size > 0u))\r
377     {\r
378         psr_t saved_psr;\r
379         volatile uint8_t stat_ctrl;\r
380 \r
381 \r
382         saved_psr=HAL_disable_interrupts();\r
383 \r
384         /* Update the transaction only when there is no transaction going on I2C */\r
385         if( this_i2c->transaction == NO_TRANSACTION)\r
386         {\r
387             this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION;\r
388         }\r
389 \r
390         /* Update the Pending transaction information so that transaction can restarted */\r
391         this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ;\r
392 \r
393         /* Update target address */\r
394         this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u;\r
395 \r
396         this_i2c->dir = WRITE_DIR;\r
397 \r
398         this_i2c->master_tx_buffer = addr_offset;\r
399         this_i2c->master_tx_size = offset_size;\r
400         this_i2c->master_tx_idx = 0u;\r
401 \r
402         this_i2c->master_rx_buffer = read_buffer;\r
403         this_i2c->master_rx_size = read_size;\r
404         this_i2c->master_rx_idx = 0u;\r
405         \r
406         /* Set I2C status in progress */\r
407         this_i2c->master_status = I2C_IN_PROGRESS;\r
408         this_i2c->options = options;\r
409         \r
410         if(I2C_IN_PROGRESS == this_i2c->slave_status)\r
411         {\r
412             this_i2c->is_transaction_pending = 1u;\r
413         }\r
414         else\r
415         {\r
416             HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
417         }\r
418 \r
419         /*\r
420          * Clear interrupts if required (depends on repeated starts).\r
421          * Since the Bus is on hold, only then prior status needs to\r
422          * be cleared.\r
423          */\r
424         if ( I2C_HOLD_BUS == this_i2c->bus_status )\r
425         {\r
426             HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u);\r
427         }\r
428 \r
429         stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS);\r
430         stat_ctrl = stat_ctrl;  /* Avoids lint warning. */\r
431             \r
432         /* Enable the interrupt. ( Re-enable) */\r
433         I2C_enable_irq( this_i2c );\r
434 \r
435 \r
436         HAL_restore_interrupts( saved_psr );\r
437     }\r
438 }\r
439 \r
440 /*------------------------------------------------------------------------------\r
441  * I2C_get_status()\r
442  * See "core_i2c.h" for details of how to use this function.\r
443  */\r
444 i2c_status_t I2C_get_status\r
445 (\r
446     i2c_instance_t * this_i2c\r
447 )\r
448 {\r
449     i2c_status_t i2c_status ;\r
450 \r
451     i2c_status = this_i2c->master_status ;\r
452 \r
453     return i2c_status;\r
454 }\r
455 \r
456 /*------------------------------------------------------------------------------\r
457  * I2C_wait_complete()\r
458  * See "core_i2c.h" for details of how to use this function.\r
459  */\r
460 i2c_status_t I2C_wait_complete\r
461 (\r
462     i2c_instance_t * this_i2c,\r
463     uint32_t timeout_ms\r
464 )\r
465 {\r
466     i2c_status_t i2c_status;\r
467     psr_t saved_psr;\r
468     /*\r
469      * Because we have no idea of what CPU we are supposed to be running on\r
470      * we need to guard this write to the timeout value to avoid ISR/user code\r
471      * interaction issues. Checking the status below should be fine as only a\r
472      * single byte should change in that.\r
473      */\r
474 \r
475         saved_psr=HAL_disable_interrupts();\r
476     this_i2c->master_timeout_ms = timeout_ms;\r
477 \r
478         HAL_restore_interrupts( saved_psr );\r
479 \r
480     /* Run the loop until state returns I2C_FAILED  or I2C_SUCESS*/\r
481     do {\r
482         i2c_status = this_i2c->master_status;\r
483     } while(I2C_IN_PROGRESS == i2c_status);\r
484     return i2c_status;\r
485 }\r
486 \r
487 /*------------------------------------------------------------------------------\r
488  * I2C_system_tick()\r
489  * See "core_i2c.h" for details of how to use this function.\r
490  */\r
491 void I2C_system_tick\r
492 (\r
493     i2c_instance_t * this_i2c,\r
494     uint32_t ms_since_last_tick\r
495 )\r
496 {\r
497     if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT)\r
498     {\r
499        if(this_i2c->master_timeout_ms > ms_since_last_tick)\r
500         {\r
501             this_i2c->master_timeout_ms -= ms_since_last_tick;\r
502         }\r
503         else\r
504         {\r
505             psr_t saved_psr;\r
506             /*\r
507              * We need to disable interrupts here to ensure we can update the\r
508              * shared data without the I2C ISR interrupting us.\r
509              */\r
510 \r
511         saved_psr=HAL_disable_interrupts();\r
512 \r
513             /*\r
514              * Mark current transaction as having timed out.\r
515              */\r
516             this_i2c->master_status = I2C_TIMED_OUT;\r
517             this_i2c->transaction = NO_TRANSACTION;\r
518             this_i2c->is_transaction_pending = 0;\r
519 \r
520 \r
521         HAL_restore_interrupts( saved_psr );\r
522             \r
523             /*\r
524              * Make sure we do not incorrectly signal a timeout for subsequent\r
525              * transactions.\r
526              */\r
527             this_i2c->master_timeout_ms = I2C_NO_TIMEOUT;\r
528         }\r
529     }\r
530 }\r
531 \r
532 /*------------------------------------------------------------------------------\r
533  * I2C_set_slave_tx_buffer()\r
534  * See "core_i2c.h" for details of how to use this function.\r
535  */\r
536 void I2C_set_slave_tx_buffer\r
537 (\r
538     i2c_instance_t * this_i2c,\r
539     const uint8_t * tx_buffer,\r
540     uint16_t tx_size\r
541 )\r
542 {\r
543     psr_t saved_psr;\r
544 \r
545     /*\r
546      * We need to disable interrupts here to ensure we can update the\r
547      * shared data without the I2C ISR interrupting us.\r
548      */\r
549 \r
550         saved_psr=HAL_disable_interrupts();\r
551     \r
552     this_i2c->slave_tx_buffer = tx_buffer;\r
553     this_i2c->slave_tx_size = tx_size;\r
554     this_i2c->slave_tx_idx = 0u;\r
555     \r
556 \r
557         HAL_restore_interrupts( saved_psr );\r
558 }\r
559 \r
560 /*------------------------------------------------------------------------------\r
561  * I2C_set_slave_rx_buffer()\r
562  * See "core_i2c.h" for details of how to use this function.\r
563  */\r
564 void I2C_set_slave_rx_buffer\r
565 (\r
566     i2c_instance_t * this_i2c,\r
567     uint8_t * rx_buffer,\r
568     uint16_t rx_size\r
569 )\r
570 {\r
571     psr_t saved_psr;\r
572 \r
573     /*\r
574      * We need to disable interrupts here to ensure we can update the\r
575      * shared data without the I2C ISR interrupting us.\r
576      */\r
577 \r
578         saved_psr=HAL_disable_interrupts();\r
579 \r
580     this_i2c->slave_rx_buffer = rx_buffer;\r
581     this_i2c->slave_rx_size = rx_size;\r
582     this_i2c->slave_rx_idx = 0u;\r
583 \r
584 \r
585         HAL_restore_interrupts( saved_psr );\r
586 }\r
587 \r
588 /*------------------------------------------------------------------------------\r
589  * I2C_set_slave_mem_offset_length()\r
590  * See "core_i2c.h" for details of how to use this function.\r
591  */\r
592 void I2C_set_slave_mem_offset_length\r
593 (\r
594     i2c_instance_t * this_i2c,\r
595     uint8_t offset_length\r
596 )\r
597 {\r
598     HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH);\r
599     \r
600     /*\r
601      * Single byte update, should be interrupt safe\r
602      */\r
603     if(offset_length > MAX_OFFSET_LENGTH)\r
604     {\r
605         this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH;\r
606     }\r
607     else\r
608     {\r
609         this_i2c->slave_mem_offset_length = offset_length;\r
610     }\r
611 }\r
612 \r
613 /*------------------------------------------------------------------------------\r
614  * I2C_register_write_handler()\r
615  * See "core_i2c.h" for details of how to use this function.\r
616  */\r
617 void I2C_register_write_handler\r
618 (\r
619     i2c_instance_t * this_i2c,\r
620     i2c_slave_wr_handler_t handler\r
621 )\r
622 {\r
623     psr_t saved_psr;\r
624 \r
625     /*\r
626      * We need to disable interrupts here to ensure we can update the\r
627      * shared data without the I2C ISR interrupting us.\r
628      */\r
629 \r
630         saved_psr=HAL_disable_interrupts();\r
631 \r
632     this_i2c->slave_write_handler = handler;\r
633 \r
634 \r
635         HAL_restore_interrupts( saved_psr );\r
636 }\r
637 \r
638 /*------------------------------------------------------------------------------\r
639  * I2C_enable_slave()\r
640  * See "core_i2c.h" for details of how to use this function.\r
641  */\r
642 void I2C_enable_slave\r
643 (\r
644     i2c_instance_t * this_i2c\r
645 )\r
646 {\r
647     psr_t saved_psr;\r
648 \r
649     /*\r
650      * We need to disable interrupts here to ensure we can update the\r
651      * hardware register and slave mode flag without the I2C ISR interrupting\r
652      * us.\r
653      */\r
654 \r
655         saved_psr=HAL_disable_interrupts();\r
656 \r
657     /* Set the Assert Acknowledge bit. */\r
658     HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u);\r
659 \r
660     /* Enable slave mode */\r
661     this_i2c->is_slave_enabled = 1u;\r
662 \r
663 \r
664         HAL_restore_interrupts( saved_psr );\r
665 \r
666     /* Enable I2C IRQ*/\r
667     I2C_enable_irq( this_i2c );\r
668 }\r
669 \r
670 /*------------------------------------------------------------------------------\r
671  * I2C_disable_slave()\r
672  * See "core_i2c.h" for details of how to use this function.\r
673  */\r
674 void I2C_disable_slave\r
675 (\r
676     i2c_instance_t * this_i2c\r
677 )\r
678 {\r
679     psr_t saved_psr;\r
680 \r
681     /*\r
682      * We need to disable interrupts here to ensure we can update the\r
683      * hardware register without the I2C ISR interrupting us.\r
684      */\r
685 \r
686         saved_psr=HAL_disable_interrupts();\r
687     \r
688     /* Reset the assert acknowledge bit. */\r
689     HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u);\r
690 \r
691     /* Disable slave mode with IRQ blocked to make whole change atomic */\r
692     this_i2c->is_slave_enabled = 0u;\r
693 \r
694 \r
695         HAL_restore_interrupts( saved_psr );\r
696 }\r
697 \r
698 /*------------------------------------------------------------------------------\r
699  * \r
700  */\r
701 static void enable_slave_if_required\r
702 (\r
703     i2c_instance_t * this_i2c\r
704 )\r
705 {\r
706     /*\r
707      * This function is only called from within the ISR and so does not need\r
708      * guarding on the register access.\r
709      */\r
710     if( 0 != this_i2c->is_slave_enabled )\r
711     {\r
712         HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u );\r
713     }\r
714 }\r
715 /*------------------------------------------------------------------------------\r
716  * I2C_set_slave_second_addr()\r
717  * See "i2c.h" for details of how to use this function.\r
718  */\r
719 void I2C_set_slave_second_addr\r
720 (\r
721     i2c_instance_t * this_i2c,\r
722     uint8_t second_slave_addr\r
723 )\r
724 {\r
725     uint8_t second_slave_address;\r
726     \r
727     /*\r
728       This function does not support CoreI2C hardware configured with a fixed \r
729       second slave address.  The current implementation of the ADDR1[0] register\r
730       bit makes it difficult for the driver to support both programmable and\r
731       fixed second slave address, so we choose to support programmable only.\r
732       With the programmable configuration, ADDR1[0] and ADDR0[0] both control\r
733       enable/disable of GCA recognition, as an effective OR of the 2 bit fields.\r
734       Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA.\r
735      */\r
736     second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK));\r
737 \r
738     /*\r
739      * Single byte register write, should be interrupt safe\r
740      */\r
741     HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address);\r
742 }\r
743 \r
744 /*------------------------------------------------------------------------------\r
745  * I2C_disable_slave_second_addr()\r
746  * See "i2c.h" for details of how to use this function.\r
747  */\r
748 void I2C_disable_slave_second_addr\r
749 (\r
750     i2c_instance_t * this_i2c\r
751 )\r
752 {\r
753     /*\r
754       We are disabling the second slave address by setting the value of the 2nd\r
755       slave address to the primary slave address. The reason for using this method\r
756       of disabling 2nd slave address is that ADDRESS1[0] has different meaning \r
757       depending on hardware configuration. Its use would likely interfere with\r
758       the intended GCA setting.\r
759      */\r
760     /*\r
761      * Single byte register write, should be interrupt safe\r
762      */\r
763     HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address);\r
764 }\r
765 \r
766 /*------------------------------------------------------------------------------\r
767  * i2C_set_gca()\r
768  * See "i2c.h" for details of how to use this function.\r
769  */\r
770 \r
771 void I2C_set_gca\r
772 (\r
773     i2c_instance_t * this_i2c\r
774 )\r
775 {\r
776     /* \r
777      * This read modify write access should be interrupt safe as the address\r
778      * register is not written to in the ISR.\r
779      */\r
780     /* accept GC addressing. */\r
781     HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u);\r
782 }\r
783 \r
784 /*------------------------------------------------------------------------------\r
785  * I2C_clear_gca()\r
786  * See "i2c.h" for details of how to use this function.\r
787  */\r
788 void I2C_clear_gca\r
789 (\r
790     i2c_instance_t * this_i2c\r
791 )\r
792 {\r
793     /* \r
794      * This read modify write access should be interrupt safe as the address\r
795      * register is not written to in the ISR.\r
796      */\r
797     /* Clear GC addressing. */\r
798     HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u);\r
799 }\r
800 \r
801 /*------------------------------------------------------------------------------\r
802  * I2C_isr()\r
803  * See "core_i2c.h" for details of how to use this function.\r
804  */\r
805 void I2C_isr\r
806 (\r
807     i2c_instance_t * this_i2c\r
808 )\r
809 {\r
810     volatile uint8_t status;\r
811     uint8_t data;\r
812     uint8_t hold_bus;\r
813     uint8_t clear_irq = 1u;\r
814 \r
815     status = HAL_get_8bit_reg( this_i2c->base_address, STATUS);\r
816     \r
817     switch( status )\r
818     {\r
819         /************** MASTER TRANSMITTER / RECEIVER *******************/\r
820       \r
821         case ST_START: /* start has been xmt'd */\r
822         case ST_RESTART: /* repeated start has been xmt'd */\r
823             //write_hex(STDOUT_FILENO, status);\r
824             HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u);\r
825             HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */\r
826             HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */\r
827             if(this_i2c->dir == WRITE_DIR)\r
828             {\r
829                  this_i2c->master_tx_idx = 0u;\r
830             }\r
831             else\r
832             {\r
833                  this_i2c->master_rx_idx = 0u;\r
834             }\r
835 \r
836             /*\r
837              * Clear the pending transaction. This condition will be true if the slave \r
838              * has acquired the bus to carry out pending master transaction which \r
839              * it had received during its slave transmission or reception mode. \r
840              */\r
841             if(this_i2c->is_transaction_pending)\r
842             {\r
843                 this_i2c->is_transaction_pending = 0u;\r
844             }\r
845 \r
846             /*\r
847              * Make sure to update proper transaction after master START\r
848              * or RESTART\r
849              */\r
850             if(this_i2c->transaction != this_i2c->pending_transaction)\r
851             {\r
852                 this_i2c->transaction = this_i2c->pending_transaction;\r
853             }\r
854             break;\r
855             \r
856         case ST_LOST_ARB:\r
857               /* Set start bit.  Let's keep trying!  Don't give up! */\r
858               HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
859               break;\r
860 \r
861         case ST_STOP_TRANSMIT:\r
862              /* Stop has been transmitted. Do nothing */\r
863               break;\r
864 \r
865         /******************* MASTER TRANSMITTER *************************/\r
866         case ST_SLAW_NACK:\r
867             //write_hex(STDOUT_FILENO, status);\r
868             /* SLA+W has been transmitted; not ACK has been received - let's stop. */\r
869             HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);\r
870             this_i2c->master_status = I2C_FAILED;\r
871             this_i2c->transaction = NO_TRANSACTION;\r
872             enable_slave_if_required(this_i2c);\r
873             break;\r
874             \r
875         case ST_SLAW_ACK:\r
876         case ST_TX_DATA_ACK:\r
877             //write_hex(STDOUT_FILENO, status);\r
878             /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */\r
879             if (this_i2c->master_tx_idx < this_i2c->master_tx_size)\r
880             {    \r
881                 HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]);\r
882             }\r
883             else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )\r
884             {\r
885                 /* We are finished sending the address offset part of a random read transaction.\r
886                  * It is is time to send a restart in order to change direction. */\r
887                  this_i2c->dir = READ_DIR;\r
888                  HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
889             }\r
890             else /* done sending. let's stop */\r
891             {\r
892                 /*\r
893                  * Set the transaction back to NO_TRANSACTION to allow user to do further\r
894                  * transaction\r
895                  */\r
896                 this_i2c->transaction = NO_TRANSACTION;\r
897                 hold_bus = this_i2c->options & I2C_HOLD_BUS;\r
898 \r
899                 /* Store the information of current I2C bus status in the bus_status*/\r
900                 this_i2c->bus_status  = hold_bus;\r
901                 if ( hold_bus == 0u )\r
902                 { \r
903                     HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);  /*xmt stop condition */\r
904                     enable_slave_if_required(this_i2c);\r
905                 }\r
906                 else\r
907                 {\r
908                     I2C_disable_irq( this_i2c );\r
909                     clear_irq = 0u;\r
910                 }\r
911                 this_i2c->master_status = I2C_SUCCESS;\r
912             }\r
913             break;\r
914 \r
915           case ST_TX_DATA_NACK:\r
916             //write_hex(STDOUT_FILENO, status);\r
917             /* data byte SENT, ACK to be received\r
918              * In fact, this means we've received a NACK (This may not be \r
919              * obvious, but if we've rec'd an ACK then we would be in state \r
920              * 0x28!) hence, let's send a stop bit\r
921              */\r
922             HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */\r
923             this_i2c->master_status = I2C_FAILED;\r
924 \r
925             /*\r
926              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
927              * transaction\r
928              */\r
929             this_i2c->transaction = NO_TRANSACTION;\r
930             enable_slave_if_required(this_i2c);\r
931             break;\r
932               \r
933       /********************* MASTER (or slave?) RECEIVER *************************/\r
934       \r
935       /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */\r
936         case ST_SLAR_ACK: /* SLA+R tx'ed. */\r
937 //          //write_hex(STDOUT_FILENO, status);\r
938             /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless\r
939              * the next byte is the last byte of the read transaction.\r
940              */\r
941             if(this_i2c->master_rx_size > 1u)\r
942             {\r
943                 HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u);\r
944             }\r
945             else if(1u == this_i2c->master_rx_size)\r
946             {\r
947                 HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u);\r
948             }\r
949             else /* this_i2c->master_rx_size == 0u */\r
950             {\r
951                 HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u);\r
952                 HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);\r
953                 this_i2c->master_status = I2C_SUCCESS;\r
954                 this_i2c->transaction = NO_TRANSACTION;\r
955             }\r
956             break;\r
957             \r
958         case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */\r
959 //          //write_hex(STDOUT_FILENO, status);\r
960             HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);\r
961             this_i2c->master_status = I2C_FAILED;\r
962 \r
963             /*\r
964              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
965              * transaction\r
966              */\r
967             this_i2c->transaction = NO_TRANSACTION;\r
968             enable_slave_if_required(this_i2c);\r
969             break;\r
970           \r
971         case ST_RX_DATA_ACK: /* Data byte received, ACK returned */\r
972 //          //write_hex(STDOUT_FILENO, status);\r
973             /* First, get the data */\r
974             this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA);\r
975             if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u))\r
976             {\r
977                 /* If we're at the second last byte, let's set AA to 0 so\r
978                  * we return a NACK at the last byte. */\r
979                 HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u);\r
980             }\r
981             break;\r
982             \r
983         case ST_RX_DATA_NACK: /* Data byte received, NACK returned */\r
984 //          //write_hex(STDOUT_FILENO, status);\r
985             /* Get the data, then send a stop condition */\r
986             this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA);\r
987           \r
988             hold_bus = this_i2c->options & I2C_HOLD_BUS; \r
989 \r
990             /* Store the information of current I2C bus status in the bus_status*/\r
991             this_i2c->bus_status  = hold_bus;\r
992             if ( hold_bus == 0u )\r
993             { \r
994                 HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);  /*xmt stop condition */\r
995 \r
996                 /* Bus is released, now we can start listening to bus, if it is slave */\r
997                    enable_slave_if_required(this_i2c);\r
998             }\r
999             else\r
1000             {\r
1001                 I2C_disable_irq( this_i2c );\r
1002                 clear_irq = 0u;\r
1003             }\r
1004             /*\r
1005              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
1006              * transaction\r
1007              */\r
1008             this_i2c->transaction = NO_TRANSACTION;\r
1009             this_i2c->master_status = I2C_SUCCESS;\r
1010             break;\r
1011         \r
1012         /******************** SLAVE RECEIVER **************************/\r
1013         case ST_GCA_NACK: /* NACK after, GCA addressing */\r
1014         case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */\r
1015             //write_hex(STDOUT_FILENO, status);\r
1016             HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u);\r
1017 \r
1018             this_i2c->transaction = NO_TRANSACTION;\r
1019             this_i2c->slave_status = I2C_SUCCESS;\r
1020             \r
1021             /* Check if transaction was pending. If yes, set the START bit */\r
1022             if(this_i2c->is_transaction_pending)\r
1023             {\r
1024                 HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
1025             }\r
1026             break;\r
1027             \r
1028         case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */\r
1029         case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */\r
1030             //write_hex(STDOUT_FILENO, status);\r
1031             /*\r
1032              *  We lost arbitration and either the GCE or our address was the\r
1033              *  one received so pend the master operation we were starting.\r
1034              */\r
1035             this_i2c->is_transaction_pending = 1u;\r
1036             /* Fall through to normal ST processing as we are now in slave mode */\r
1037 \r
1038         case ST_GCA: /* General call address received, ACK returned */\r
1039         case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */\r
1040             //write_hex(STDOUT_FILENO, status);\r
1041             this_i2c->transaction = WRITE_SLAVE_TRANSACTION;\r
1042             this_i2c->slave_rx_idx = 0u;\r
1043             this_i2c->random_read_addr = 0u;\r
1044             /*\r
1045              * If Start Bit is set clear it, but store that information since it is because of\r
1046              * pending transaction\r
1047              */\r
1048             if(HAL_get_8bit_reg_field(this_i2c->base_address, STA))\r
1049             {\r
1050                 HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u);\r
1051                 this_i2c->is_transaction_pending = 1u;\r
1052             }\r
1053             this_i2c->slave_status = I2C_IN_PROGRESS;\r
1054 #ifdef INCLUDE_SLA_IN_RX_PAYLOAD\r
1055             /* Fall through to put address as first byte in payload buffer */\r
1056 #else\r
1057             /* Only break from this case if the slave address must NOT be included at the\r
1058              * beginning of the received write data. */\r
1059             break;\r
1060 #endif            \r
1061         case ST_GCA_ACK: /* DATA received; ACK sent after GCA */\r
1062         case ST_RDATA: /* DATA received; must clear DATA register */\r
1063             //write_hex(STDOUT_FILENO, status);\r
1064             if((this_i2c->slave_rx_buffer != (uint8_t *)0)\r
1065                && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size))\r
1066             {\r
1067                 data = HAL_get_8bit_reg(this_i2c->base_address, DATA);\r
1068                 this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data;\r
1069                 \r
1070 #ifdef INCLUDE_SLA_IN_RX_PAYLOAD\r
1071                 if((ST_RDATA == status) || (ST_GCA_ACK == status))\r
1072                 {\r
1073                     /* Ignore the slave address byte in the random read address\r
1074                        computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD\r
1075                        is defined. */\r
1076 #endif\r
1077                     this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data;\r
1078 #ifdef INCLUDE_SLA_IN_RX_PAYLOAD\r
1079                 }\r
1080 #endif\r
1081             }\r
1082             \r
1083             if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size)\r
1084             {\r
1085                 /* Rx buffer is full. NACK next received byte. */\r
1086                 HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); \r
1087             }\r
1088             break;\r
1089             \r
1090         case ST_RSTOP:\r
1091             //write_hex(STDOUT_FILENO, status);\r
1092             /* STOP or repeated START occurred. */\r
1093             /* We cannot be sure if the transaction has actually completed as\r
1094              * this hardware state reports that either a STOP or repeated START\r
1095              * condition has occurred. We assume that this is a repeated START\r
1096              * if the transaction was a write from the master to this point.*/\r
1097             if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION )\r
1098             {\r
1099                 if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length )\r
1100                 {\r
1101                     this_i2c->slave_tx_idx = this_i2c->random_read_addr;\r
1102                 }\r
1103                 /* Call the slave's write transaction handler if it exists. */\r
1104                 if ( this_i2c->slave_write_handler != 0u )\r
1105                 {\r
1106                     i2c_slave_handler_ret_t h_ret;\r
1107                     h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx );\r
1108                     if ( I2C_REENABLE_SLAVE_RX == h_ret )\r
1109                     {\r
1110                         /* There is a small risk that the write handler could\r
1111                          * call I2C_disable_slave() but return\r
1112                          * I2C_REENABLE_SLAVE_RX in error so we only enable\r
1113                          * ACKs if still in slave mode. */\r
1114                          enable_slave_if_required(this_i2c);\r
1115                     }\r
1116                     else\r
1117                     {\r
1118                         HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u );\r
1119                         /* Clear slave mode flag as well otherwise in mixed\r
1120                          * master/slave applications, the AA bit will get set by\r
1121                          * subsequent master operations. */\r
1122                         this_i2c->is_slave_enabled = 0u;\r
1123                     }\r
1124                 }\r
1125                 else\r
1126                 {\r
1127                     /* Re-enable address acknowledge in case we were ready to nack the next received byte. */\r
1128                     HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u );\r
1129                 }\r
1130             }\r
1131             else /* A stop or repeated start outside a write/read operation */\r
1132             {\r
1133                 /*\r
1134                  * Reset slave_tx_idx so that a subsequent read will result in the slave's\r
1135                  * transmit buffer being sent from the first byte.\r
1136                  */\r
1137                 this_i2c->slave_tx_idx = 0u;\r
1138                 /*\r
1139                  * See if we need to re-enable acknowledgement as some error conditions, such\r
1140                  * as a master prematurely ending a transfer, can see us get here with AA set\r
1141                  * to 0 which will disable slave operation if we are not careful.\r
1142                  */\r
1143                 enable_slave_if_required(this_i2c);\r
1144             }\r
1145 \r
1146             /* Mark any previous master write transaction as complete. */\r
1147             this_i2c->slave_status = I2C_SUCCESS;\r
1148             \r
1149             /* Check if transaction was pending. If yes, set the START bit */\r
1150             if(this_i2c->is_transaction_pending)\r
1151             {\r
1152                 HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
1153             }\r
1154 \r
1155             /*\r
1156              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
1157              * transaction\r
1158              */\r
1159             this_i2c->transaction = NO_TRANSACTION;\r
1160 \r
1161             break;\r
1162             \r
1163         case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */\r
1164             //write_hex(STDOUT_FILENO, status);\r
1165             /*\r
1166              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
1167              * transaction.\r
1168              */\r
1169             this_i2c->transaction = NO_TRANSACTION;\r
1170             /*\r
1171              * Reset slave_tx_idx so that a subsequent read will result in the slave's\r
1172              * transmit buffer being sent from the first byte.\r
1173              */\r
1174             this_i2c->slave_tx_idx = 0u;\r
1175             /*\r
1176              * Clear status to I2C_FAILED only if there was an operation in progress.\r
1177              */\r
1178             if(I2C_IN_PROGRESS == this_i2c->slave_status)\r
1179             {\r
1180                 this_i2c->slave_status = I2C_FAILED;\r
1181             }\r
1182 \r
1183             enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */\r
1184 \r
1185             break;\r
1186             \r
1187         /****************** SLAVE TRANSMITTER **************************/\r
1188         case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */\r
1189         case ST_SLARW_LA:       /* Arbitration lost, and: */\r
1190         case ST_RACK:           /* Data tx'ed, ACK received */\r
1191             //write_hex(STDOUT_FILENO, status);\r
1192             if ( status == ST_SLAVE_SLAR_ACK )\r
1193             {\r
1194                 this_i2c->transaction = READ_SLAVE_TRANSACTION;\r
1195                 this_i2c->random_read_addr = 0u;\r
1196                 this_i2c->slave_status = I2C_IN_PROGRESS;\r
1197                 /* If Start Bit is set clear it, but store that information since it is because of\r
1198                  * pending transaction\r
1199                  */\r
1200                 if(HAL_get_8bit_reg_field(this_i2c->base_address, STA))\r
1201                 {\r
1202                     HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u);\r
1203                     this_i2c->is_transaction_pending = 1u;\r
1204                  }\r
1205             }\r
1206             if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size)\r
1207             {\r
1208                 /* Ensure 0xFF is returned to the master when the slave specifies\r
1209                  * an empty transmit buffer. */\r
1210                 HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu);\r
1211             }\r
1212             else\r
1213             {\r
1214                 /* Load the data the data byte to be sent to the master. */\r
1215                 HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]);\r
1216             }\r
1217             /* Determine if this is the last data byte to send to the master. */\r
1218             if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */\r
1219             {\r
1220                  HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); \r
1221                 /* Next read transaction will result in slave's transmit buffer\r
1222                  * being sent from the first byte. */\r
1223                 this_i2c->slave_tx_idx = 0u;\r
1224             }\r
1225             break;\r
1226         \r
1227         case ST_SLAVE_RNACK:    /* Data byte has been transmitted; not-ACK has been received. */\r
1228         case ST_FINAL: /* Last Data byte tx'ed, ACK received */\r
1229             //write_hex(STDOUT_FILENO, status);\r
1230             /* We assume that the transaction will be stopped by the master.\r
1231              * Reset slave_tx_idx so that a subsequent read will result in the slave's\r
1232              * transmit buffer being sent from the first byte. */\r
1233             this_i2c->slave_tx_idx = 0u;\r
1234             HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); \r
1235 \r
1236             /*  Mark previous state as complete */\r
1237             this_i2c->slave_status = I2C_SUCCESS;\r
1238             /* Check if transaction was pending. If yes, set the START bit */\r
1239             if(this_i2c->is_transaction_pending)\r
1240             {\r
1241                 HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u);\r
1242             }\r
1243             /*\r
1244              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
1245              * transaction\r
1246              */\r
1247             this_i2c->transaction = NO_TRANSACTION;\r
1248 \r
1249             break;\r
1250 \r
1251         /* Master Reset has been activated Wait 35 ms for interrupt to be set,\r
1252          * clear interrupt and proceed to 0xF8 state. */\r
1253         case ST_RESET_ACTIVATED:\r
1254         case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */\r
1255         default:\r
1256             //write_hex(STDOUT_FILENO, status);\r
1257             /* Some undefined state has encountered. Clear Start bit to make\r
1258              * sure, next good transaction happen */\r
1259             HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u);\r
1260             /*\r
1261              * Set the transaction back to NO_TRANSACTION to allow user to do further\r
1262              * transaction.\r
1263              */\r
1264             this_i2c->transaction = NO_TRANSACTION;\r
1265             /*\r
1266              * Reset slave_tx_idx so that a subsequent read will result in the slave's\r
1267              * transmit buffer being sent from the first byte.\r
1268              */\r
1269             this_i2c->slave_tx_idx = 0u;\r
1270             /*\r
1271              * Clear statuses to I2C_FAILED only if there was an operation in progress.\r
1272              */\r
1273             if(I2C_IN_PROGRESS == this_i2c->master_status)\r
1274             {\r
1275                 this_i2c->master_status = I2C_FAILED;\r
1276             }\r
1277 \r
1278             if(I2C_IN_PROGRESS == this_i2c->slave_status)\r
1279             {\r
1280                 this_i2c->slave_status = I2C_FAILED;\r
1281             }\r
1282 \r
1283             break;\r
1284     }\r
1285     \r
1286     if ( clear_irq )\r
1287     {\r
1288         /* clear interrupt. */\r
1289         HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u);\r
1290     }\r
1291     \r
1292     /* Read the status register to ensure the last I2C registers write took place\r
1293      * in a system built around a bus making use of posted writes. */\r
1294 //    status = HAL_get_8bit_reg( this_i2c->base_address, STATUS);\r
1295 }\r
1296 \r
1297 /*------------------------------------------------------------------------------\r
1298  * I2C_smbus_init()\r
1299  * See "i2c.h" for details of how to use this function.\r
1300  */\r
1301  \r
1302 /*\r
1303  * SMBSUS_NO    = 1\r
1304  * SMBALERT_NO  = 1\r
1305  * SMBus enable = 1\r
1306  */\r
1307 #define INIT_AND_ENABLE_SMBUS   0x54u\r
1308 void I2C_smbus_init\r
1309 (\r
1310     i2c_instance_t * this_i2c\r
1311 )\r
1312 {\r
1313     /*\r
1314      * Single byte register write, should be interrupt safe\r
1315      */\r
1316     /* Enable SMBUS */\r
1317     HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS);\r
1318 }\r
1319 \r
1320 /*------------------------------------------------------------------------------\r
1321  * I2C_enable_smbus_irq()\r
1322  * See "i2c.h" for details of how to use this function.\r
1323  */\r
1324 void I2C_enable_smbus_irq\r
1325 (\r
1326     i2c_instance_t * this_i2c,\r
1327     uint8_t  irq_type\r
1328 )\r
1329 {\r
1330     psr_t saved_psr;\r
1331 \r
1332     /*\r
1333      * We need to disable interrupts here to ensure we can update the\r
1334      * hardware register without the SMBUS IRQs interrupting us.\r
1335      */\r
1336 \r
1337         saved_psr=HAL_disable_interrupts();\r
1338 \r
1339     if ( irq_type & I2C_SMBALERT_IRQ)\r
1340     {\r
1341         HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u);\r
1342     }\r
1343     if ( irq_type & I2C_SMBSUS_IRQ)\r
1344     {\r
1345         HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u);\r
1346     }\r
1347     \r
1348 \r
1349         HAL_restore_interrupts( saved_psr );\r
1350 }\r
1351 \r
1352 /*------------------------------------------------------------------------------\r
1353  * I2C_disable_smbus_irq()\r
1354  * See "i2c.h" for details of how to use this function.\r
1355  */\r
1356 void I2C_disable_smbus_irq\r
1357 (\r
1358     i2c_instance_t * this_i2c,\r
1359     uint8_t  irq_type\r
1360 )\r
1361 {\r
1362     psr_t saved_psr;\r
1363 \r
1364     /*\r
1365      * We need to disable interrupts here to ensure we can update the\r
1366      * hardware register without the SMBUS IRQs interrupting us.\r
1367      */\r
1368 \r
1369         saved_psr=HAL_disable_interrupts();\r
1370 \r
1371     if ( irq_type & I2C_SMBALERT_IRQ)\r
1372     {\r
1373         HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u);\r
1374     }\r
1375     if (irq_type & I2C_SMBSUS_IRQ )\r
1376     {\r
1377         HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u);\r
1378     }\r
1379     \r
1380 \r
1381         HAL_restore_interrupts( saved_psr );\r
1382 }\r
1383 \r
1384 /*------------------------------------------------------------------------------\r
1385  * I2C_suspend_smbus_slave()\r
1386  * See "i2c.h" for details of how to use this function.\r
1387  */\r
1388 void I2C_suspend_smbus_slave\r
1389 (\r
1390     i2c_instance_t * this_i2c\r
1391 )\r
1392 {\r
1393     psr_t saved_psr;\r
1394 \r
1395     /*\r
1396      * We need to disable interrupts here to ensure we can update the\r
1397      * hardware register without the SMBUS IRQs interrupting us.\r
1398      */\r
1399 \r
1400         saved_psr=HAL_disable_interrupts();\r
1401 \r
1402     HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u);\r
1403 \r
1404 \r
1405         HAL_restore_interrupts( saved_psr );\r
1406 }\r
1407 \r
1408 /*------------------------------------------------------------------------------\r
1409  * I2C_resume_smbus_slave()\r
1410  * See "i2c.h" for details of how to use this function.\r
1411  */\r
1412 void I2C_resume_smbus_slave\r
1413 (\r
1414     i2c_instance_t * this_i2c\r
1415 )\r
1416 {\r
1417     psr_t saved_psr;\r
1418 \r
1419     /*\r
1420      * We need to disable interrupts here to ensure we can update the\r
1421      * hardware register without the SMBUS IRQs interrupting us.\r
1422      */\r
1423 \r
1424         saved_psr=HAL_disable_interrupts();\r
1425 \r
1426     HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u);\r
1427 \r
1428 \r
1429         HAL_restore_interrupts( saved_psr );\r
1430 }\r
1431 \r
1432 /*------------------------------------------------------------------------------\r
1433  * I2C_reset_smbus()\r
1434  * See "i2c.h" for details of how to use this function.\r
1435  */\r
1436 void I2C_reset_smbus\r
1437 (\r
1438     i2c_instance_t * this_i2c\r
1439 )\r
1440 {\r
1441     psr_t saved_psr;\r
1442 \r
1443     /*\r
1444      * We need to disable interrupts here to ensure we can update the\r
1445      * hardware register without the SMBUS IRQs interrupting us.\r
1446      */\r
1447 \r
1448         saved_psr=HAL_disable_interrupts();\r
1449     HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u);\r
1450     \r
1451 \r
1452         HAL_restore_interrupts( saved_psr );\r
1453 }\r
1454 \r
1455 /*------------------------------------------------------------------------------\r
1456  * I2C_set_smbus_alert()\r
1457  * See "i2c.h" for details of how to use this function.\r
1458  */\r
1459 void I2C_set_smbus_alert\r
1460 (\r
1461     i2c_instance_t * this_i2c\r
1462 )\r
1463 {\r
1464     psr_t saved_psr;\r
1465 \r
1466     /*\r
1467      * We need to disable interrupts here to ensure we can update the\r
1468      * hardware register without the SMBUS IRQs interrupting us.\r
1469      */\r
1470 \r
1471         saved_psr=HAL_disable_interrupts();\r
1472     HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u);\r
1473 \r
1474 \r
1475         HAL_restore_interrupts( saved_psr );\r
1476 }\r
1477 \r
1478 /*------------------------------------------------------------------------------\r
1479  * I2C_clear_smbus_alert()\r
1480  * See "i2c.h" for details of how to use this function.\r
1481  */\r
1482 void I2C_clear_smbus_alert\r
1483 (\r
1484     i2c_instance_t * this_i2c\r
1485 )\r
1486 {\r
1487     psr_t saved_psr;\r
1488 \r
1489     /*\r
1490      * We need to disable interrupts here to ensure we can update the\r
1491      * hardware register without the SMBUS IRQs interrupting us.\r
1492      */\r
1493 \r
1494         saved_psr=HAL_disable_interrupts();\r
1495 \r
1496     HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u);\r
1497 \r
1498 \r
1499         HAL_restore_interrupts( saved_psr );\r
1500 }\r
1501 \r
1502 /*------------------------------------------------------------------------------\r
1503  * I2C_get_irq_status()\r
1504  * See "i2c.h" for details of how to use this function.\r
1505  */\r
1506 uint8_t I2C_get_irq_status\r
1507 (\r
1508     i2c_instance_t * this_i2c\r
1509 )\r
1510 {\r
1511     uint8_t status ;\r
1512     uint8_t irq_type = I2C_NO_IRQ ;\r
1513 \r
1514     status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS);\r
1515 \r
1516     if( status & (uint8_t)SMBALERT_NI_STATUS_MASK )\r
1517     {\r
1518         irq_type |= I2C_SMBALERT_IRQ ;\r
1519     }\r
1520 \r
1521     if( status & (uint8_t)SMBSUS_NI_STATUS_MASK )\r
1522     {\r
1523         irq_type |= I2C_SMBSUS_IRQ ;\r
1524     }\r
1525 \r
1526     status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL);\r
1527 \r
1528     if( status & (uint8_t)SI_MASK )\r
1529     {\r
1530         irq_type |= I2C_INTR_IRQ ;\r
1531     }\r
1532     return(irq_type);\r
1533 }\r
1534 \r
1535 /*------------------------------------------------------------------------------\r
1536  * I2C_set_slave_addr2()\r
1537  * See "i2c.h" for details of how to use this function.\r
1538  */\r
1539 void I2C_set_user_data\r
1540 (\r
1541     i2c_instance_t * this_i2c,\r
1542     void * p_user_data\r
1543 )\r
1544 {\r
1545     this_i2c->p_user_data = p_user_data ;\r
1546 }\r
1547 \r
1548 /*------------------------------------------------------------------------------\r
1549  * I2C_get_user_data()\r
1550  * See "i2c.h" for details of how to use this function.\r
1551  */\r
1552 void * I2C_get_user_data\r
1553 (\r
1554     i2c_instance_t * this_i2c\r
1555 )\r
1556 {\r
1557     return( this_i2c->p_user_data);\r
1558 }\r
1559 \r
1560 #ifdef __cplusplus\r
1561 }\r
1562 #endif\r
1563 \r