1 /*******************************************************************
2 Components for embedded applications builded for
3 laboratory and medical instruments firmware
5 i2c_mx1.c - I2C communication automata for M9328 MX1 microcontroller
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
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 *******************************************************************/
25 #include <system_def.h>
27 #include "i2c_drv_config.h"
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);
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 */
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)
49 #define C552CON_AAC (1 << 2)
50 #define C552CON_SIC (1 << 3)
51 #define C552CON_STAC (1 << 5)
52 #define C552CON_ENC (1 << 6)
54 /***************************************************************************/
55 int c552_init_start(struct i2c_drv *drv, int port, int irq, int bitrate, int sladr)
58 C552_SCLH(port)=((PCLK/2)/bitrate); //minimal value
59 C552_SCLL(port)=((PCLK/2)/bitrate);
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);
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);
76 /***************************************************************************/
77 static int c552_sfnc_ms_end(struct i2c_drv *drv)
79 i2c_msg_head_t *msg=drv->msg_act;
82 if((msg->flags&I2C_MSG_CB_END) && (msg->callback))
83 msg->callback(drv,I2C_MSG_CB_END,msg);
84 if(msg->flags&I2C_MSG_REPEAT){
85 drv->master_queue=msg->next;
87 i2c_drv_queue_msg(msg->flags&I2C_MSG_NOPROC?NULL:&drv->proc_queue,msg);
89 msg->flags|=I2C_MSG_FINISHED;
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;
97 drv->flags&=~I2C_DRV_MS_INPR;
105 i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx)
107 i2c_msg_head_t *msg=drv->slave_queue;
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);
115 } while((msg=msg->next)!=drv->slave_queue);
119 /***************************************************************************/
120 static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p)
122 unsigned long saveif;
125 if(!(drv->flags&I2C_DRV_ON))
127 if(!drv->master_queue)
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;
135 restore_flags(saveif);
143 /***************************************************************************/
144 int c552_poll(i2c_drv_t *drv)
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);
156 int i2c_irq_seq_num=0;
158 /***************************************************************************/
159 void c552_irq_handler(int intno, void *dev_id)
166 drv=(i2c_drv_t*)dev_id;
167 if(drv->magic!=I2C_DRV_MAGIC)
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");
174 #elif defined(__DJGPP__)||defined(CONFIG_OC_I2C_DRV_SYSLESS)
175 I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n");
178 error("i2c_irq_handler : BAD drv magic !!!");
181 drv->flags&=~I2C_DRV_NA;
186 stat=C552_STAT(port);
190 /* Bus Error has occured */
192 C552_CONSET(port)=C552CON_STO;
193 if(drv->master_queue) {
194 /* there is some work for master*/
195 C552_CONSET(port)=C552CON_STA;
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;
206 C552_CONCLR(port)=C552CON_STAC;
207 C552_CONSET(port)=C552CON_AA;
209 msg=drv->master_queue;
211 msg->tx_len=msg->rx_len=0;
213 if((msg->flags&I2C_MSG_CB_START) && (msg->callback))
214 msg->callback(drv,I2C_MSG_CB_START,msg);
216 if (msg->flags&I2C_MSG_MS_TX) {
217 /* proceed Tx request first */
218 C552_DAT(port) = msg->addr&~1;
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);
236 /* sent SLA W received ACK */
238 /* sent DATA received ACK */
239 if (msg->tx_len<msg->tx_rq) {
240 C552_DAT(port) = msg->tx_buf[msg->tx_len];
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);
249 C552_CONSET(port)=C552CON_STA;
253 /* sent DATA received NACK */
255 /* sent SLA R received ACK */
257 /* vyslano SLA W prijato NACK */
258 C552_CONSET(port)=C552CON_STO;
259 msg->flags|=I2C_MSG_FAIL;
260 c552_sfnc_ms_end(drv);
263 /* arbitration lost during Tx */
264 C552_CONSET(port)=C552CON_STA;
267 /* sent SLA R received ACK */
269 C552_CONCLR(port)=C552CON_AAC;
272 /* received DATA sent ACK */
273 msg->rx_buf[msg->rx_len]= C552_DAT(port);
275 if (msg->rx_rq==msg->rx_len)
276 C552_CONCLR(port)=C552CON_AAC;
279 /* received DATA sent NACK */
280 msg->rx_buf[msg->rx_len]= C552_DAT(port);
282 C552_CONSET(port)=C552CON_STO;
283 c552_sfnc_ms_end(drv);
289 /* received own SLA W sent ACK after arbitration lost */
292 /* received Generall CALL sent ACK after arbitration lost */
293 C552_CONSET(port)=C552CON_STA;
296 /* received own SLA W sent ACK */
299 /* received Generall CALL sent ACK */
300 if(!drv->slave_queue) {
301 C552_CONCLR(port)=C552CON_AAC;
304 C552_CONSET(port)=C552CON_AA;
305 drv->flags|=I2C_DRV_SL_CEXP|I2C_DRV_SL_INRX;
309 /* SLA W : received DATA sent ACK */
312 /* GCall : received DATA sent ACK */
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);
320 if(!msg || (msg->rx_len>=msg->rx_rq)){
321 C552_CONCLR(port)=C552CON_AAC;
324 msg->rx_buf[msg->rx_len]= C552_DAT(port);
329 /* SLA W : received DATA sent NACK */
330 /* may it be, the handling should fall into A0 state */
333 /* GCall : received DATA sent NACK */
334 /* may it be, the handling should fall into A0 state */
336 C552_CONSET(port)=C552CON_AA;
340 /* Slave : Repeated START or STOP */
341 if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) {
343 if(drv->flags&I2C_DRV_SL_INRX)
344 cbcode=I2C_MSG_CB_END|I2C_MSG_SL_RX;
346 cbcode=I2C_MSG_CB_END|I2C_MSG_SL_TX;
347 msg->callback(drv,cbcode,msg);
349 C552_CONSET(port)=C552CON_AA;
353 /* received own SLA R sent ACK after arbitration lost */
354 C552_CONSET(port)=C552CON_STA;
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);
362 C552_CONCLR(port)=C552CON_AAC;
365 C552_CONSET(port)=C552CON_AA;
368 /* SLA R : sent DATA received ACK */
369 if(!msg || (msg->tx_len>=msg->tx_rq)){
370 C552_DAT(port) = 0xff;
373 C552_DAT(port) = msg->tx_buf[msg->tx_len];
378 /* SLA R : sent DATA received NACK */
379 /* the A0 state is not enerred most probably */
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;
386 if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) {
387 msg->callback(drv,I2C_MSG_CB_END|I2C_MSG_SL_TX,msg);
395 C552_CONCLR(port)=C552CON_SIC;