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 <hal_machperiph.h> /* for PCLK on LPC17xx */
28 #include "i2c_drv_config.h"
31 int c552_poll(i2c_drv_t *drv);
32 IRQ_HANDLER_FNC(c552_irq_handler);
33 static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p);
34 int c552_stroke(i2c_drv_t *drv);
40 #define C552_CONSET(port) (((I2C_TypeDef *)(port))->I2CONSET) /* Control Set Register */
41 #define C552_STAT(port) (((I2C_TypeDef *)(port))->I2STAT) /* Status Register */
42 #define C552_DAT(port) (((I2C_TypeDef *)(port))->I2DAT) /* Data Register */
43 #define C552_ADR(port) (((I2C_TypeDef *)(port))->I2ADR0) /* Slave Address Register */
44 #define C552_SCLH(port) (((I2C_TypeDef *)(port))->I2SCLH) /* SCL Duty Cycle Register (high half word) */
45 #define C552_SCLL(port) (((I2C_TypeDef *)(port))->I2SCLL) /* SCL Duty Cycle Register (low half word) */
46 #define C552_CONCLR(port) (((I2C_TypeDef *)(port))->I2CONCLR) /* Control Clear Register */
47 #define C552_MMCTRL(port) (((I2C_TypeDef *)(port))->MMCTRL) /* Monitor Mode Control */
49 #else /*__LPC17xx_H__*/
51 #define C552_CONSET(port) (((i2cRegs_t *)(port))->conset) /* Control Set Register */
52 #define C552_STAT(port) (((i2cRegs_t *)(port))->stat) /* Status Register */
53 #define C552_DAT(port) (((i2cRegs_t *)(port))->dat) /* Data Register */
54 #define C552_ADR(port) (((i2cRegs_t *)(port))->adr) /* Slave Address Register */
55 #define C552_SCLH(port) (((i2cRegs_t *)(port))->sclh) /* SCL Duty Cycle Register (high half word) */
56 #define C552_SCLL(port) (((i2cRegs_t *)(port))->scll) /* SCL Duty Cycle Register (low half word) */
57 #define C552_CONCLR(port) (((i2cRegs_t *)(port))->conclr) /* Control Clear Register */
59 #endif /*__LPC17xx_H__*/
61 #define C552CON_AA (1 << 2)
62 #define C552CON_SI (1 << 3)
63 #define C552CON_STO (1 << 4)
64 #define C552CON_STA (1 << 5)
65 #define C552CON_EN (1 << 6)
67 #define C552CON_AAC (1 << 2)
68 #define C552CON_SIC (1 << 3)
69 #define C552CON_STAC (1 << 5)
70 #define C552CON_ENC (1 << 6)
72 /***************************************************************************/
73 int c552_init_start(struct i2c_drv *drv, int port, int irq, int bitrate, int sladr)
75 unsigned long clock_base;
80 C552_SCLH(port)=clock_base/bitrate; //minimal value
81 C552_SCLL(port)=clock_base/bitrate;
85 drv->ctrl_fnc=c552_ctrl_fnc;
86 drv->poll_fnc=c552_poll;
87 drv->stroke_fnc=c552_stroke;
88 drv->flags=I2C_DRV_ON; /* todo - use atomic operation */
89 C552_CONCLR(port)=0x6C; /* clearing all flags */
90 C552_CONSET(port)=C552CON_EN;
91 request_irq(irq, c552_irq_handler, 0, "i2c", drv);
95 static int c552_sfnc_ms_end(struct i2c_drv *drv);
96 static inline i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx);
98 /***************************************************************************/
99 static int c552_sfnc_ms_end(struct i2c_drv *drv)
101 i2c_msg_head_t *msg=drv->msg_act;
104 if(msg->flags&I2C_MSG_REPEAT){
105 drv->master_queue=msg->next;
107 i2c_drv_queue_msg(msg->flags&I2C_MSG_NOPROC?NULL:&drv->proc_queue,msg);
109 msg->flags|=I2C_MSG_FINISHED;
110 if((msg->flags&I2C_MSG_CB_END) && (msg->callback))
111 msg->callback(drv,I2C_MSG_CB_END,msg);
114 if(drv->master_queue) {
115 /* there is some more work for master*/
116 /* We need to request start of the next transfer somewhere */
117 C552_CONSET(drv->port)=C552CON_STA;
119 drv->flags&=~I2C_DRV_MS_INPR;
127 i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx)
129 i2c_msg_head_t *msg=drv->slave_queue;
131 if((msg->flags&rxtx) && !((cmd^msg->sl_cmd)&msg->sl_msk)){
132 drv->slave_queue=msg;
133 if((msg->flags&I2C_MSG_CB_START) && (msg->callback))
134 msg->callback(drv,I2C_MSG_CB_START|rxtx,msg);
137 } while((msg=msg->next)!=drv->slave_queue);
141 /***************************************************************************/
142 static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p)
144 unsigned long saveif;
147 if(!(drv->flags&I2C_DRV_ON))
149 if(!drv->master_queue)
151 save_and_cli(saveif);
152 if(!(drv->flags&I2C_DRV_MS_INPR)) {
153 drv->flags|=I2C_DRV_MS_INPR;
154 drv->flags&=~I2C_DRV_NA;
155 C552_CONSET(drv->port)=C552CON_STA;
157 restore_flags(saveif);
165 /***************************************************************************/
166 int c552_poll(i2c_drv_t *drv)
170 if((msg=drv->proc_queue)!=NULL){
171 i2c_drv_queue_msg(NULL,msg);
172 if((msg->flags&I2C_MSG_CB_PROC) && (msg->callback))
173 msg->callback(drv,I2C_MSG_CB_PROC,msg);
178 int c552_stroke(i2c_drv_t *drv)
184 C552_CONSET(port)=C552CON_STO;
185 C552_CONSET(port)=C552CON_STA;
187 C552_CONSET(port)=C552CON_STA;
192 int i2c_irq_seq_num=0;
194 /***************************************************************************/
195 IRQ_HANDLER_FNC(c552_irq_handler)
202 drv=(i2c_drv_t*)irq_handler_get_context();
203 if(drv->magic!=I2C_DRV_MAGIC)
205 #ifdef FOR_LINUX_KERNEL
206 panic("i2c_irq_handler : BAD drv magic !!!");
207 #elif defined(_WIN32)
208 I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n");
210 #elif defined(__DJGPP__)||defined(CONFIG_OC_I2C_DRV_SYSLESS)
211 I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n");
214 error("i2c_irq_handler : BAD drv magic !!!");
217 drv->flags&=~I2C_DRV_NA;
222 stat=C552_STAT(port);
226 /* Bus Error has occured */
228 C552_CONSET(port)=C552CON_STO;
229 if(drv->master_queue) {
230 /* there is some work for master*/
231 C552_CONSET(port)=C552CON_STA;
234 case 0x08: /* MS_STA */
235 /* the initial start condition has been sent */
236 if(!drv->master_queue) {
237 C552_CONCLR(port)=C552CON_STAC;
238 C552_CONSET(port)=C552CON_STO;
242 C552_CONCLR(port)=C552CON_STAC;
243 C552_CONSET(port)=C552CON_AA;
245 msg=drv->master_queue;
247 msg->tx_len=msg->rx_len=0;
249 if((msg->flags&I2C_MSG_CB_START) && (msg->callback))
250 msg->callback(drv,I2C_MSG_CB_START,msg);
252 if (msg->flags&I2C_MSG_MS_TX) {
253 /* proceed Tx request first */
254 C552_DAT(port) = msg->addr&~1;
257 /* if there is no request for transmit, continue by Rx immediately */
258 case 0x10: /* MS_REPS */
259 /* the repeated start has been successfully sent, continue by Rx */
260 C552_CONCLR(port)=C552CON_STAC;
261 C552_CONSET(port)=C552CON_AA;
262 C552_DAT(port) = msg->addr|1;
263 if (!msg || !(msg->flags&I2C_MSG_MS_RX)) {
264 /* there are no data to be received */
265 C552_CONSET(port)=C552CON_STO;
266 c552_sfnc_ms_end(drv);
272 /* sent SLA W received ACK */
274 /* sent DATA received ACK */
275 if (msg->tx_len<msg->tx_rq) {
276 C552_DAT(port) = msg->tx_buf[msg->tx_len];
280 /* all data has been sent */
281 if (!(msg->flags&I2C_MSG_MS_RX)) {
282 C552_CONSET(port)=C552CON_STO;
283 c552_sfnc_ms_end(drv);
285 C552_CONSET(port)=C552CON_STA;
289 /* sent DATA received NACK */
291 /* sent SLA R received ACK */
293 /* vyslano SLA W prijato NACK */
294 C552_CONSET(port)=C552CON_STO;
295 msg->flags|=I2C_MSG_FAIL;
296 c552_sfnc_ms_end(drv);
299 /* arbitration lost during Tx */
300 C552_CONSET(port)=C552CON_STA;
303 /* sent SLA R received ACK */
305 C552_CONCLR(port)=C552CON_AAC;
308 /* received DATA sent ACK */
309 msg->rx_buf[msg->rx_len]= C552_DAT(port);
311 if (msg->rx_len+1>=msg->rx_rq)
312 C552_CONCLR(port)=C552CON_AAC;
315 /* received DATA sent NACK */
316 msg->rx_buf[msg->rx_len]= C552_DAT(port);
318 C552_CONSET(port)=C552CON_STO;
319 c552_sfnc_ms_end(drv);
325 /* received own SLA W sent ACK after arbitration lost */
328 /* received Generall CALL sent ACK after arbitration lost */
329 C552_CONSET(port)=C552CON_STA;
332 /* received own SLA W sent ACK */
335 /* received Generall CALL sent ACK */
336 if(!drv->slave_queue) {
337 C552_CONCLR(port)=C552CON_AAC;
340 C552_CONSET(port)=C552CON_AA;
341 drv->flags|=I2C_DRV_SL_CEXP|I2C_DRV_SL_INRX;
345 /* SLA W : received DATA sent ACK */
348 /* GCall : received DATA sent ACK */
350 if(drv->flags&I2C_DRV_SL_CEXP){
351 drv->flags&=~I2C_DRV_SL_CEXP;
352 drv->sl_last_cmd=C552_DAT(port);
353 msg=c552_sfnc_sl_prep(drv, drv->sl_last_cmd, I2C_MSG_SL_RX);
356 if(!msg || (msg->rx_len>=msg->rx_rq)){
357 C552_CONCLR(port)=C552CON_AAC;
360 msg->rx_buf[msg->rx_len]= C552_DAT(port);
365 /* SLA W : received DATA sent NACK */
366 /* may it be, the handling should fall into A0 state */
369 /* GCall : received DATA sent NACK */
370 /* may it be, the handling should fall into A0 state */
372 C552_CONSET(port)=C552CON_AA;
376 /* Slave : Repeated START or STOP */
377 if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) {
379 if(drv->flags&I2C_DRV_SL_INRX)
380 cbcode=I2C_MSG_CB_END|I2C_MSG_SL_RX;
382 cbcode=I2C_MSG_CB_END|I2C_MSG_SL_TX;
383 msg->callback(drv,cbcode,msg);
385 C552_CONSET(port)=C552CON_AA;
389 /* received own SLA R sent ACK after arbitration lost */
390 C552_CONSET(port)=C552CON_STA;
393 /* received own SLA R sent ACK */
394 drv->flags&=~I2C_DRV_SL_INRX;
395 msg=c552_sfnc_sl_prep(drv, drv->sl_last_cmd, I2C_MSG_SL_RX);
398 C552_CONCLR(port)=C552CON_AAC;
401 C552_CONSET(port)=C552CON_AA;
404 /* SLA R : sent DATA received ACK */
405 if(!msg || (msg->tx_len>=msg->tx_rq)){
406 C552_DAT(port) = 0xff;
409 C552_DAT(port) = msg->tx_buf[msg->tx_len];
414 /* SLA R : sent DATA received NACK */
415 /* the A0 state is not enerred most probably */
418 /* SLA R : last data sent, DATA (AA=0) received ACK */
419 /* the A0 state is not enerred most probably */
420 C552_CONSET(port)=C552CON_AA;
422 if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) {
423 msg->callback(drv,I2C_MSG_CB_END|I2C_MSG_SL_TX,msg);
431 C552_CONCLR(port)=C552CON_SIC;