]> rtime.felk.cvut.cz Git - lincan.git/blob - embedded/libs4c/i2c/i2c_c552.c
7cede723be3f117763588223b4c26abe154dd70b
[lincan.git] / embedded / libs4c / i2c / i2c_c552.c
1 /*******************************************************************
2   Components for embedded applications builded for
3   laboratory and medical instruments firmware  
4  
5   i2c_mx1.c - I2C communication automata for M9328 MX1 microcontroller
6  
7   Copyright holders and project originators
8     (C) 2001-2008 by Pavel Pisa pisa@cmp.felk.cvut.cz
9     (C) 2002-2008 by PiKRON Ltd. http://www.pikron.com
10     (C) 2007-2008 by Petr Smolik
11
12  The COLAMI components can be used and copied under next licenses
13    - MPL - Mozilla Public License
14    - GPL - GNU Public License
15    - LGPL - Lesser GNU Public License
16    - and other licenses added by project originators
17  Code can be modified and re-distributed under any combination
18  of the above listed licenses. If contributor does not agree with
19  some of the licenses, he can delete appropriate line.
20  Warning, if you delete all lines, you are not allowed to
21  distribute code or build project.
22  *******************************************************************/
23
24
25 #include <system_def.h>
26 #include <hal_intr.h>
27 #include "i2c_drv_config.h"
28 #include "i2c_drv.h"
29
30 int c552_poll(i2c_drv_t *drv);
31 void c552_irq_handler(int intno, void *dev_id);
32 static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p);
33
34 // I2C Registers
35 #define C552_CONSET(port)  (((i2cRegs_t *)(port))->conset)     /* Control Set Register */
36 #define C552_STAT(port)    (((i2cRegs_t *)(port))->stat)       /* Status Register */
37 #define C552_DAT(port)     (((i2cRegs_t *)(port))->dat)        /* Data Register */
38 #define C552_ADR(port)     (((i2cRegs_t *)(port))->adr)        /* Slave Address Register */
39 #define C552_SCLH(port)    (((i2cRegs_t *)(port))->sclh)       /* SCL Duty Cycle Register (high half word) */
40 #define C552_SCLL(port)    (((i2cRegs_t *)(port))->scll)       /* SCL Duty Cycle Register (low half word) */
41 #define C552_CONCLR(port)  (((i2cRegs_t *)(port))->conclr)     /* Control Clear Register */
42
43 #define C552CON_AA      (1 << 2)
44 #define C552CON_SI      (1 << 3)
45 #define C552CON_STO     (1 << 4)
46 #define C552CON_STA     (1 << 5)
47 #define C552CON_EN      (1 << 6)
48
49 #define C552CON_AAC     (1 << 2)
50 #define C552CON_SIC     (1 << 3)
51 #define C552CON_STAC    (1 << 5)
52 #define C552CON_ENC     (1 << 6)
53
54 /***************************************************************************/
55 int c552_init_start(struct i2c_drv *drv, int port, int irq, int bitrate, int sladr)
56 {
57   C552_ADR(port)=sladr;
58   C552_SCLH(port)=((PCLK/2)/bitrate); //minimal value
59   C552_SCLL(port)=((PCLK/2)/bitrate);
60   drv->irq=irq;
61   drv->port=port;
62   drv->sfnc_act=NULL;
63   drv->ctrl_fnc=c552_ctrl_fnc;
64   drv->poll_fnc=c552_poll;
65   drv->flags=I2C_DRV_ON;    /* todo - use atomic operation */
66   C552_CONCLR(port)=0x6C;   /* clearing all flags */
67   C552_CONSET(port)=C552CON_EN;
68   HAL_INTERRUPT_ATTACH(irq,c552_irq_handler,drv);  
69   HAL_INTERRUPT_UNMASK(irq);
70   return 0;
71 }
72
73 static int c552_sfnc_ms_end(struct i2c_drv *drv);
74 static inline i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx);
75
76 /***************************************************************************/
77 static int c552_sfnc_ms_end(struct i2c_drv *drv)
78 {
79   i2c_msg_head_t *msg=drv->msg_act;
80
81   if(msg) {
82     if(msg->flags&I2C_MSG_REPEAT){
83       drv->master_queue=msg->next;
84     }else{
85       i2c_drv_queue_msg(msg->flags&I2C_MSG_NOPROC?NULL:&drv->proc_queue,msg);
86     }
87     msg->flags|=I2C_MSG_FINISHED;
88     if((msg->flags&I2C_MSG_CB_END) && (msg->callback))
89       msg->callback(drv,I2C_MSG_CB_END,msg);
90   }
91
92   if(drv->master_queue) {
93     /* there is some more work for master*/
94     /* We need to request start of the next transfer somewhere */
95     C552_CONSET(drv->port)=C552CON_STA;
96   } else {
97     drv->flags&=~I2C_DRV_MS_INPR;
98   }
99
100   drv->msg_act = NULL;
101   return 0;
102 }
103
104 static inline
105 i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx)
106 {
107   i2c_msg_head_t *msg=drv->slave_queue;
108   if(!msg) do {
109     if((msg->flags&rxtx) && !((cmd^msg->sl_cmd)&msg->sl_msk)){
110       drv->slave_queue=msg;
111       if((msg->flags&I2C_MSG_CB_START) && (msg->callback))
112         msg->callback(drv,I2C_MSG_CB_START|rxtx,msg);
113       return msg;
114     }
115   } while((msg=msg->next)!=drv->slave_queue);
116   return NULL;
117 }
118
119 /***************************************************************************/
120 static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p)
121 {
122   unsigned long saveif;
123   switch(ctrl){
124     case I2C_CTRL_MS_RQ:
125       if(!(drv->flags&I2C_DRV_ON))
126         return -1;
127       if(!drv->master_queue)
128         return 0;
129       save_and_cli(saveif);
130       if(!(drv->flags&I2C_DRV_MS_INPR)) {
131         drv->flags|=I2C_DRV_MS_INPR;
132         drv->flags&=~I2C_DRV_NA;
133         C552_CONSET(drv->port)=C552CON_STA;
134       }
135       restore_flags(saveif);
136       return 0;
137     default:
138       return -1;
139   }
140   return 0;
141 }
142
143 /***************************************************************************/
144 int c552_poll(i2c_drv_t *drv)
145 {
146   i2c_msg_head_t *msg;
147
148   if((msg=drv->proc_queue)!=NULL){
149     i2c_drv_queue_msg(NULL,msg);
150     if((msg->flags&I2C_MSG_CB_PROC) && (msg->callback))
151       msg->callback(drv,I2C_MSG_CB_PROC,msg);
152   }  
153   return 0;
154 }
155
156 int i2c_irq_seq_num=0;
157
158 /***************************************************************************/
159 void c552_irq_handler(int intno, void *dev_id)
160 {
161   i2c_drv_t *drv;
162   i2c_msg_head_t *msg;
163   int port;
164   int stat;
165
166   drv=(i2c_drv_t*)dev_id;
167   if(drv->magic!=I2C_DRV_MAGIC)
168   {
169     #ifdef FOR_LINUX_KERNEL
170      panic("i2c_irq_handler : BAD drv magic !!!");
171     #elif defined(_WIN32)
172      I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n");
173      return FALSE;
174     #elif defined(__DJGPP__)||defined(CONFIG_OC_I2C_DRV_SYSLESS)
175      I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n");
176      return;
177     #else
178      error("i2c_irq_handler : BAD drv magic !!!");
179     #endif
180   }
181   drv->flags&=~I2C_DRV_NA;
182
183   port=drv->port;  
184   msg=drv->msg_act;
185
186   stat=C552_STAT(port);
187
188   switch(stat) {
189     case 0x00: 
190       /* Bus Error has occured */ 
191       drv->msg_act=NULL;
192       C552_CONSET(port)=C552CON_STO;
193       if(drv->master_queue) {
194         /* there is some work for master*/
195         C552_CONSET(port)=C552CON_STA;
196       }
197       break;
198     case 0x08: /* MS_STA */
199       /* the initial start condition has been sent */
200       if(!drv->master_queue) {
201         C552_CONCLR(port)=C552CON_STAC;
202         C552_CONSET(port)=C552CON_STO;
203         drv->msg_act=NULL;
204         break;
205       }
206       C552_CONCLR(port)=C552CON_STAC;
207       C552_CONSET(port)=C552CON_AA;
208
209       msg=drv->master_queue;
210       drv->msg_act=msg;
211       msg->tx_len=msg->rx_len=0;
212
213       if((msg->flags&I2C_MSG_CB_START) && (msg->callback))
214         msg->callback(drv,I2C_MSG_CB_START,msg);
215
216       if (msg->flags&I2C_MSG_MS_TX) {
217         /* proceed Tx request first */
218         C552_DAT(port) = msg->addr&~1;
219         break;
220       }
221       /* if there is no request for transmit, continue by Rx immediately */
222     case 0x10: /* MS_REPS */
223       /* the repeated start has been successfully sent, continue by Rx */
224       C552_CONCLR(port)=C552CON_STAC;
225       C552_CONSET(port)=C552CON_AA;
226       C552_DAT(port) = msg->addr|1;
227       if (!msg || !(msg->flags&I2C_MSG_MS_RX)) {
228         /* there are no data to be received */
229         C552_CONSET(port)=C552CON_STO;
230         c552_sfnc_ms_end(drv);
231       } else {
232         msg->rx_len=0;
233       }
234       break;
235     case 0x18:
236       /* sent SLA W received ACK */
237     case 0x28:
238       /* sent DATA received ACK */
239       if (msg->tx_len<msg->tx_rq) {
240         C552_DAT(port) = msg->tx_buf[msg->tx_len];
241         msg->tx_len++;
242         break;
243       }
244       /* all data has been sent */
245       if (!(msg->flags&I2C_MSG_MS_RX)) {
246         C552_CONSET(port)=C552CON_STO;
247         c552_sfnc_ms_end(drv);
248       } else {
249         C552_CONSET(port)=C552CON_STA;
250       }
251       break;
252     case 0x30:
253       /* sent DATA received NACK */
254     case 0x48:
255       /* sent SLA R received ACK */
256     case 0x20:
257       /* vyslano SLA W prijato NACK */
258       C552_CONSET(port)=C552CON_STO;
259       msg->flags|=I2C_MSG_FAIL;
260       c552_sfnc_ms_end(drv);
261       break;
262     case 0x38:
263       /* arbitration lost during Tx */
264       C552_CONSET(port)=C552CON_STA;
265       break;
266     case 0x40:
267       /* sent SLA R received ACK */
268       if (msg->rx_rq==1)
269         C552_CONCLR(port)=C552CON_AAC;
270       break;
271     case 0x50:
272       /* received DATA sent ACK */   
273       msg->rx_buf[msg->rx_len]= C552_DAT(port);
274       msg->rx_len++;
275       if (msg->rx_rq==msg->rx_len)
276         C552_CONCLR(port)=C552CON_AAC;
277       break;
278     case 0x58:
279       /* received DATA sent NACK */   
280       msg->rx_buf[msg->rx_len]= C552_DAT(port);
281       msg->rx_len++;
282       C552_CONSET(port)=C552CON_STO;
283       c552_sfnc_ms_end(drv);
284       break;
285
286     /*** slave mode ***/
287
288     case 0x68:
289       /* received own SLA W sent ACK after arbitration lost */
290
291     case 0x78:
292       /* received Generall CALL sent ACK after arbitration lost */
293       C552_CONSET(port)=C552CON_STA;
294
295     case 0x60:
296       /* received own SLA W sent ACK */
297
298     case 0x70:
299       /* received Generall CALL sent ACK */
300       if(!drv->slave_queue) {
301         C552_CONCLR(port)=C552CON_AAC;
302         break;
303       }
304       C552_CONSET(port)=C552CON_AA;
305       drv->flags|=I2C_DRV_SL_CEXP|I2C_DRV_SL_INRX;
306       break;
307
308     case 0x80:
309       /* SLA W : received DATA sent ACK */
310
311     case 0x90:
312       /* GCall : received DATA sent ACK */
313
314       if(drv->flags&I2C_DRV_SL_CEXP){
315         drv->flags&=~I2C_DRV_SL_CEXP;
316         drv->sl_last_cmd=C552_DAT(port);
317         msg=c552_sfnc_sl_prep(drv, drv->sl_last_cmd, I2C_MSG_SL_RX);
318         drv->msg_act=msg;
319       }
320       if(!msg || (msg->rx_len>=msg->rx_rq)){
321         C552_CONCLR(port)=C552CON_AAC;
322         break;
323       }
324       msg->rx_buf[msg->rx_len]= C552_DAT(port);
325       msg->rx_len++;
326       break;
327
328     case 0x88:
329       /* SLA W : received DATA sent NACK */
330       /* may it be, the handling should fall into A0 state */
331
332     case 0x98:
333       /* GCall : received DATA sent NACK */
334       /* may it be, the handling should fall into A0 state */
335
336       C552_CONSET(port)=C552CON_AA;
337       break;
338
339     case 0xA0:
340       /* Slave : Repeated START or STOP */
341       if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) {
342         int cbcode;
343         if(drv->flags&I2C_DRV_SL_INRX)
344            cbcode=I2C_MSG_CB_END|I2C_MSG_SL_RX;
345         else
346            cbcode=I2C_MSG_CB_END|I2C_MSG_SL_TX;
347         msg->callback(drv,cbcode,msg);
348       }
349       C552_CONSET(port)=C552CON_AA;
350       break;
351
352     case 0xB0:
353       /* received own SLA R sent ACK  after arbitration lost */
354       C552_CONSET(port)=C552CON_STA;
355
356     case 0xA8:
357       /* received own SLA R sent ACK */
358       drv->flags&=~I2C_DRV_SL_INRX;
359       msg=c552_sfnc_sl_prep(drv, drv->sl_last_cmd, I2C_MSG_SL_RX);
360       drv->msg_act=msg;
361       if(!msg) {
362         C552_CONCLR(port)=C552CON_AAC;
363         break;
364       }
365       C552_CONSET(port)=C552CON_AA;
366
367     case 0xB8:
368       /* SLA R : sent DATA received ACK */
369       if(!msg || (msg->tx_len>=msg->tx_rq)){
370         C552_DAT(port) = 0xff;
371         break;
372       }
373       C552_DAT(port) = msg->tx_buf[msg->tx_len];
374       msg->tx_len++;
375       break;
376
377     case 0xC0:
378       /* SLA R : sent DATA received NACK */
379       /* the A0 state is not enerred most probably */
380
381     case 0xC8:
382       /* SLA R : last data sent, DATA (AA=0) received ACK */
383       /* the A0 state is not enerred most probably */
384       C552_CONSET(port)=C552CON_AA;
385
386       if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) {
387         msg->callback(drv,I2C_MSG_CB_END|I2C_MSG_SL_TX,msg);
388       }
389       break;
390
391     default: break;
392   }
393
394   /* vymaz SI bit */
395   C552_CONCLR(port)=C552CON_SIC;
396 }