source: rtems/c/src/lib/libcpu/m68k/mcf5206/mbus/mcfmbus.c @ cff0d64

4.104.114.84.95
Last change on this file since cff0d64 was 00717a3, checked in by Joel Sherrill <joel.sherrill@…>, on 10/26/01 at 19:32:40

2001-10-26 Victor V. Vengerov <vvv@…>

  • New libcpu support for mcf5206e.
  • ChangeLog?, clock/ckinit.c, clock/.cvsignore, configure.ac, console/mcfuart.c, console/.cvsignore, include/mcf5206e.h, include/mcfmbus.h, include/mcfuart.h, include/.cvsignore, mbus/mcfmbus.c, mbus/.cvsignore, timer/timer.c, timer/timerisr.S, timer/.cvsignore, .cvsignore: New files.
  • Property mode set to 100644
File size: 18.9 KB
Line 
1/* MCF5206e MBUS module (I2C bus) driver
2 *
3 * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
4 * Author: Victor V. Vengerov <vvv@oktet.ru>
5 *
6 * The license and distribution terms for this file may be
7 * found in the file LICENSE in this distribution or at
8 *
9 * http://www.OARcorp.com/rtems/license.html.
10 *
11 * @(#) $Id$
12 */
13
14#include "mcf5206/mcfmbus.h"
15#include "mcf5206/mcf5206e.h"
16#include "i2c.h"
17
18/* Events of I2C machine */
19typedef enum i2c_event {
20    EVENT_NONE,      /* Spurious event */
21    EVENT_TRANSFER,  /* Start new transfer */
22    EVENT_NEXTMSG,   /* Start processing of next message in transfer */
23    EVENT_ACK,       /* Sending finished with ACK */
24    EVENT_NACK,      /* Sending finished with NACK */
25    EVENT_TIMEOUT,   /* Timeout occured */
26    EVENT_DATA_RECV, /* Data received */
27    EVENT_ARB_LOST,  /* Arbitration lost */
28    EVENT_SLAVE      /* Addressed as a slave */
29} i2c_event;
30
31static mcfmbus *mbus;
32
33/*** Auxillary primitives ***/
34
35/* Change state of finite state machine */
36#define next_state(bus,new_state) \
37    do {                             \
38        (bus)->state = (new_state);  \
39    } while (0)
40
41/* Initiate start condition on the I2C bus */
42#define mcfmbus_start(bus) \
43    do {                                                    \
44        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MSTA;  \
45    } while (0)
46
47/* Initiate stop condition on the I2C bus */
48#define mcfmbus_stop(bus) \
49    do {                                                    \
50        *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MSTA; \
51    } while (0)
52
53/* Initiate repeat start condition on the I2C bus */
54#define mcfmbus_rstart(bus) \
55    do {                                                    \
56        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_RSTA;  \
57    } while (0)
58
59/* Send byte to the bus */
60#define mcfmbus_send(bus,byte) \
61    do {                                      \
62        *MCF5206E_MBDR((bus)->base) = (byte); \
63    } while (0)
64
65/* Set transmit mode */
66#define mcfmbus_tx_mode(bus) \
67    do {                                                     \
68        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MTX;    \
69    } while (0)
70
71/* Set receive mode */
72#define mcfmbus_rx_mode(bus) \
73    do {                                                     \
74        *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MTX;   \
75        (void)*MCF5206E_MBDR((bus)->base);                   \
76    } while (0)
77
78
79/* Transmit acknowledge when byte received */
80#define mcfmbus_send_ack(bus) \
81    do {                                                     \
82        *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_TXAK;  \
83    } while (0)
84
85/* DO NOT transmit acknowledge when byte received */
86#define mcfmbus_send_nack(bus) \
87    do {                                                     \
88        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_TXAK;   \
89    } while (0)
90
91#define mcfmbus_error(bus,err_status) \
92    do {                                                       \
93        do {                                                   \
94           (bus)->cmsg->status = (err_status);                 \
95           (bus)->cmsg++;                                      \
96        } while (((bus)->cmsg - (bus)->msg < (bus)->nmsg) &&   \
97                 ((bus)->cmsg->flags & I2C_MSG_ERRSKIP));      \
98        bus->cmsg--;                                           \
99    } while (0)
100
101/* mcfmbus_get_event --
102 *     Read MBUS module status register, determine interrupt reason and
103 *     return appropriate event.
104 *
105 * PARAMETERS:
106 *     bus - pointer to MBUS module descriptor structure
107 *
108 * RETURNS:
109 *     event code
110 */
111static i2c_event
112mcfmbus_get_event(mcfmbus *bus)
113{
114    i2c_event event;
115    rtems_unsigned8 status, control;
116    rtems_interrupt_level level;
117    rtems_interrupt_disable(level);
118    status = *MCF5206E_MBSR(bus->base);
119    control = *MCF5206E_MBCR(bus->base);
120    if (status & MCF5206E_MBSR_MIF) /* Interrupt occured */
121    {
122        if (status & MCF5206E_MBSR_MAAS)
123        {
124            event = EVENT_SLAVE;
125            *MCF5206E_MBCR(bus->base) = control; /* To clear Addressed As Slave
126                                                    condition */
127        }
128        else if (status & MCF5206E_MBSR_MAL) /* Arbitration lost */
129        {
130            *MCF5206E_MBSR(bus->base) = status & ~MCF5206E_MBSR_MAL;
131            event = EVENT_ARB_LOST;
132        }
133        else if (control & MCF5206E_MBCR_MTX) /* Trasmit mode */
134        {
135            if (status & MCF5206E_MBSR_RXAK)
136                event = EVENT_NACK;
137            else
138                event = EVENT_ACK;
139        }
140        else /* Received */
141        {
142            event = EVENT_DATA_RECV;
143        }
144
145        /* Clear interrupt condition */
146        *MCF5206E_MBSR(bus->base) &= ~MCF5206E_MBSR_MIF;
147    }
148    else
149    {
150        event = EVENT_NONE;
151    }
152    rtems_interrupt_enable(level);
153    return event;
154}
155
156static void
157mcfmbus_machine_error(mcfmbus *bus, i2c_event event)
158{
159    return;
160}
161
162/* mcfmbus_machine --
163 *     finite state machine for I2C bus protocol
164 *
165 * PARAMETERS:
166 *     bus - pointer to ColdFire MBUS descriptor structure
167 *     event - I2C event
168 *
169 * RETURNS:
170 *     none
171 */
172static void
173mcfmbus_machine(mcfmbus *bus, i2c_event event)
174{
175    rtems_unsigned8 b;
176    switch (bus->state)
177    {
178        case STATE_IDLE:
179            switch (event)
180            {
181                case EVENT_NEXTMSG:  /* Start new message processing */
182                    bus->cmsg++;
183                    /* FALLTHRU */
184               
185                case EVENT_TRANSFER: /* Initiate new transfer */
186                    if (bus->cmsg - bus->msg >= bus->nmsg)
187                    {
188                        mcfmbus_stop(bus);
189                        next_state(bus, STATE_IDLE);
190                        bus->msg = bus->cmsg = NULL;
191                        bus->nmsg = bus->byte = 0;
192                        bus->done(bus->done_arg);
193                        break;
194                    }
195                   
196                    /* Initiate START or REPEATED START condition on the bus */
197                    if (event == EVENT_TRANSFER)
198                    {
199                        mcfmbus_start(bus);
200                    }
201                    else /* (event == EVENT_NEXTMSG) */
202                    {
203                        mcfmbus_rstart(bus);
204                    }
205                   
206                    bus->byte = 0;
207                    mcfmbus_tx_mode(bus);
208                   
209                    /* Initiate slave address sending */
210                    if (bus->cmsg->flags & I2C_MSG_ADDR_10)
211                    {
212                        i2c_address a = bus->cmsg->addr;
213                        b = 0xf0 | (((a >> 8) & 0x03) << 1);
214                        if (bus->cmsg->flags & I2C_MSG_WR)
215                        {
216                            mcfmbus_send(bus, b);
217                            next_state(bus, STATE_ADDR_1_W);
218                        }
219                        else
220                        {
221                            mcfmbus_send(bus, b | 1);
222                            next_state(bus, STATE_ADDR_1_R);
223                        }
224                    }
225                    else
226                    {
227                        b = (bus->cmsg->addr & ~0x01);
228                        if (!(bus->cmsg->flags & I2C_MSG_WR))
229                        {
230                            b |= 1;
231                        }
232                        mcfmbus_send(bus, b);
233
234                        if (bus->cmsg->flags & I2C_MSG_WR)
235                        {
236                            next_state(bus, STATE_SENDING);
237                        }
238                        else
239                        {
240                            next_state(bus, STATE_ADDR_7);
241                        }
242                    }
243                    break;
244               
245                default:
246                    mcfmbus_machine_error(bus, event);
247                    break;
248            }
249            break;
250       
251        case STATE_ADDR_7:
252            switch (event)
253            {
254                case EVENT_ACK:
255                    mcfmbus_rx_mode(bus);
256                    if (bus->cmsg->len <= 1)
257                        mcfmbus_send_nack(bus);
258                    else
259                        mcfmbus_send_ack(bus);
260                    next_state(bus, STATE_RECEIVING);
261                    break;
262               
263                case EVENT_NACK:
264                    mcfmbus_error(bus, I2C_NO_DEVICE);
265                    next_state(bus, STATE_IDLE);
266                    mcfmbus_machine(bus, EVENT_NEXTMSG);
267                    break;
268
269                case EVENT_ARB_LOST:
270                    mcfmbus_error(bus, I2C_ARBITRATION_LOST);
271                    next_state(bus, STATE_IDLE);
272                    mcfmbus_machine(bus, EVENT_NEXTMSG);
273                    break;
274                   
275                default:
276                    mcfmbus_machine_error(bus, event);
277                    break;
278            }
279            break;
280
281        case STATE_ADDR_1_R:         
282        case STATE_ADDR_1_W:
283            switch (event)
284            {
285                case EVENT_ACK:
286                {
287                    rtems_unsigned8 b = (bus->cmsg->addr & 0xff);
288                    mcfmbus_send(bus, b);
289                    if (bus->state == STATE_ADDR_1_W)
290                    {
291                        next_state(bus, STATE_SENDING);
292                    }
293                    else
294                    {
295                        i2c_address a;
296                        mcfmbus_rstart(bus);
297                        mcfmbus_tx_mode(bus);
298                        a = bus->cmsg->addr;
299                        b = 0xf0 | (((a >> 8) & 0x03) << 1) | 1;
300                        mcfmbus_send(bus, b);
301                        next_state(bus, STATE_ADDR_7);
302                    }
303                    break;
304                }
305               
306                case EVENT_NACK:
307                    mcfmbus_error(bus, I2C_NO_DEVICE);
308                    next_state(bus, STATE_IDLE);
309                    mcfmbus_machine(bus, EVENT_NEXTMSG);
310                    break;
311               
312                case EVENT_ARB_LOST:
313                    mcfmbus_error(bus, I2C_ARBITRATION_LOST);
314                    next_state(bus, STATE_IDLE);
315                    mcfmbus_machine(bus, EVENT_NEXTMSG);
316                    break;
317               
318                default:
319                    mcfmbus_machine_error(bus, event);
320                    break;
321            }
322            break;
323             
324        case STATE_SENDING:
325            switch (event)
326            {
327                case EVENT_ACK:
328                    if (bus->byte == bus->cmsg->len)
329                    {
330                        next_state(bus, STATE_IDLE);
331                        mcfmbus_machine(bus, EVENT_NEXTMSG);
332                    }
333                    else
334                    {
335                        mcfmbus_send(bus, bus->cmsg->buf[bus->byte++]);
336                        next_state(bus, STATE_SENDING);
337                    }
338                    break;
339                   
340                case EVENT_NACK:
341                    if (bus->byte == 0)
342                    {
343                        mcfmbus_error(bus, I2C_NO_DEVICE);
344                    }
345                    else
346                    {
347                        mcfmbus_error(bus, I2C_NO_ACKNOWLEDGE);
348                    }
349                    next_state(bus, STATE_IDLE);
350                    mcfmbus_machine(bus, EVENT_NEXTMSG);
351                    break;
352                   
353                case EVENT_ARB_LOST:
354                    mcfmbus_error(bus, I2C_ARBITRATION_LOST);
355                    next_state(bus, STATE_IDLE);
356                    mcfmbus_machine(bus, EVENT_NEXTMSG);
357                    break;
358               
359                default:
360                    mcfmbus_machine_error(bus, event);
361                    break;
362                   
363            }
364            break;
365               
366        case STATE_RECEIVING:
367            switch (event)
368            {
369                case EVENT_DATA_RECV:
370                    if (bus->cmsg->len - bus->byte <= 2)
371                    {
372                        mcfmbus_send_nack(bus);
373                        if (bus->cmsg->len - bus->byte <= 1)
374                        {
375                            if (bus->cmsg - bus->msg + 1 == bus->nmsg)
376                                mcfmbus_stop(bus);
377                            else
378                                mcfmbus_rstart(bus);
379                        }
380                    }
381                    else
382                    {
383                        mcfmbus_send_ack(bus);
384                    }
385                    bus->cmsg->buf[bus->byte++] = *MCF5206E_MBDR(bus->base);
386                    if (bus->cmsg->len == bus->byte)
387                    {
388                        next_state(bus,STATE_IDLE);
389                        mcfmbus_machine(bus, EVENT_NEXTMSG);
390                    }
391                    else
392                    {
393                        next_state(bus,STATE_RECEIVING);
394                    }
395                    break;
396
397                case EVENT_ARB_LOST:
398                    mcfmbus_error(bus, I2C_ARBITRATION_LOST);
399                    next_state(bus, STATE_IDLE);
400                    mcfmbus_machine(bus, EVENT_NEXTMSG);
401                    break;
402
403                default:
404                    mcfmbus_machine_error(bus, event);
405                    break;
406            }
407            break;
408    }
409}
410
411/* mcfmbus_interrupt_handler --
412 *     MBUS module interrupt handler routine
413 *
414 * PARAMETERS:
415 *     vector - interrupt vector number (not used)
416 *
417 * RETURNS:
418 *     none
419 */
420rtems_isr
421mcfmbus_interrupt_handler(rtems_vector_number vector)
422{
423    i2c_event event;
424    event = mcfmbus_get_event(mbus);
425    mcfmbus_machine(mbus, event);
426}
427
428/* mcfmbus_poll --
429 *     MBUS module poll routine; used to poll events when I2C driver
430 *     operates in poll-driven mode.
431 *
432 * PARAMETERS:
433 *     none
434 *
435 * RETURNS:
436 *     none
437 */
438void
439mcfmbus_poll(mcfmbus *bus)
440{
441    i2c_event event;
442    event = mcfmbus_get_event(bus);
443    if (event != EVENT_NONE)
444        mcfmbus_machine(bus, event);
445}
446
447/* mcfmbus_select_clock_divider --
448 *     Select divider for system clock which is used for I2C bus clock
449 *     generation. Not each divider can be selected for I2C bus; this
450 *     function select nearest larger or equal divider.
451 *
452 * PARAMETERS:
453 *     i2c_bus - pointer to the bus descriptor structure
454 *     divider - system frequency divider for I2C serial clock.
455 * RETURNS:
456 *     RTEMS_SUCCESSFUL, if operation performed successfully, or
457 *     RTEMS error code when failed.
458 */
459rtems_status_code
460mcfmbus_select_clock_divider(mcfmbus *i2c_bus, int divider)
461{
462    int i;
463    int mbc;
464    struct {
465        int divider;
466        int mbc;
467    } dividers[] ={
468        { 20,   0x20 }, { 22,   0x21 }, { 24,   0x22 }, { 26,   0x23 },
469        { 28,   0x00 }, { 30,   0x01 }, { 32,   0x25 }, { 34,   0x02 },
470        { 36,   0x26 }, { 40,   0x03 }, { 44,   0x04 }, { 48,   0x05 },
471        { 56,   0x06 }, { 64,   0x2a }, { 68,   0x07 }, { 72,   0x2B },
472        { 80,   0x08 }, { 88,   0x09 }, { 96,   0x2D }, { 104,  0x0A },
473        { 112,  0x2E }, { 128,  0x0B }, { 144,  0x0C }, { 160,  0x0D },
474        { 192,  0x0E }, { 224,  0x32 }, { 240,  0x0F }, { 256,  0x33 },
475        { 288,  0x10 }, { 320,  0x11 }, { 384,  0x12 }, { 448,  0x36 },
476        { 480,  0x13 }, { 512,  0x37 }, { 576,  0x14 }, { 640,  0x15 },
477        { 768,  0x16 }, { 896,  0x3A }, { 960,  0x17 }, { 1024, 0x3B },
478        { 1152, 0x18 }, { 1280, 0x19 }, { 1536, 0x1A }, { 1792, 0x3E },
479        { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
480        { 3072, 0x1E }, { 3840, 0x1F }
481    };
482
483    if (i2c_bus == NULL)
484        return RTEMS_INVALID_ADDRESS;
485   
486    for (i = 0, mbc = -1; i < sizeof(dividers)/sizeof(dividers[0]); i++)
487    {
488        mbc = dividers[i].mbc;
489        if (dividers[i].divider >= divider)
490        {
491            break;
492        }
493    }
494    *MCF5206E_MFDR(i2c_bus->base) = mbc;
495    return RTEMS_SUCCESSFUL;
496}
497
498/* mcfmbus_initialize --
499 *     Initialize ColdFire MBUS I2C bus controller.
500 *
501 * PARAMETERS:
502 *     i2c_bus - pointer to the bus descriptor structure
503 *     base    - ColdFire internal peripherial base address
504 *
505 * RETURNS:
506 *     RTEMS_SUCCESSFUL, or RTEMS error code when initialization failed.
507 */
508rtems_status_code
509mcfmbus_initialize(mcfmbus *i2c_bus, rtems_unsigned32 base)
510{
511    rtems_interrupt_level level;
512    rtems_status_code sc;
513
514    if (mbus != NULL) /* Check if already initialized */
515        return RTEMS_RESOURCE_IN_USE;
516       
517    if (i2c_bus == NULL)
518        return RTEMS_INVALID_ADDRESS;
519
520   
521    i2c_bus->base = base;
522    i2c_bus->state = STATE_IDLE;
523    i2c_bus->msg = NULL;
524    i2c_bus->cmsg = NULL;
525    i2c_bus->nmsg = 0;
526    i2c_bus->byte = 0;
527   
528    sc = rtems_interrupt_catch(
529        mcfmbus_interrupt_handler,
530        24 + ((*MCF5206E_ICR(base, MCF5206E_INTR_MBUS) & MCF5206E_ICR_IL) >>
531                                   MCF5206E_ICR_IL_S),
532        &i2c_bus->oldisr
533    );
534    if (sc != RTEMS_SUCCESSFUL)
535        return sc;
536
537    mbus = i2c_bus;
538    rtems_interrupt_disable(level);
539    *MCF5206E_IMR(base) &= ~MCF5206E_INTR_BIT(MCF5206E_INTR_MBUS);
540    *MCF5206E_MBCR(base) = 0;
541    *MCF5206E_MBSR(base) = 0;
542    *MCF5206E_MBDR(base) = 0x1F; /* Maximum possible divider is 3840 */
543    *MCF5206E_MBCR(base) = MCF5206E_MBCR_MEN | MCF5206E_MBCR_MIEN;
544    rtems_interrupt_enable(level);
545   
546    return RTEMS_SUCCESSFUL;
547}
548
549/* mcfmbus_i2c_transfer --
550 *     Initiate multiple-messages transfer over I2C bus via ColdFire MBUS
551 *     controller.
552 *
553 * PARAMETERS:
554 *     bus - pointer to MBUS controller descriptor
555 *     nmsg - number of messages
556 *     msg - pointer to messages array
557 *     done - function which is called when transfer is finished
558 *     done_arg - arbitrary argument passed to done funciton
559 *
560 * RETURNS:
561 *     RTEMS_SUCCESSFUL if transfer initiated successfully, or error
562 *     code when failed.
563 */
564rtems_status_code
565mcfmbus_i2c_transfer(mcfmbus *bus, int nmsg, i2c_message *msg,
566                     i2c_transfer_done done, rtems_unsigned32 done_arg)
567{
568    if (bus != mbus)
569        return RTEMS_NOT_CONFIGURED;
570   
571    bus->done = done;
572    bus->done_arg = done_arg;
573    bus->cmsg = bus->msg = msg;
574    bus->nmsg = nmsg;
575    bus->byte = 0;
576    bus->state = STATE_IDLE;
577    mcfmbus_machine(bus, EVENT_TRANSFER);
578    return RTEMS_SUCCESSFUL;
579}
580
581
582/* mcfmbus_i2c_done --
583 *     Close ColdFire MBUS I2C bus controller and release all resources.
584 *
585 * PARAMETERS:
586 *     bus - pointer to MBUS controller descriptor
587 *
588 * RETURNS:
589 *     RTEMS_SUCCESSFUL, if transfer initiated successfully, or error
590 *     code when failed.
591 */
592rtems_status_code
593mcfmbus_i2c_done(mcfmbus *i2c_bus)
594{
595    rtems_status_code sc;
596    rtems_unsigned32 base;
597    if (mbus == NULL)
598        return RTEMS_NOT_CONFIGURED;
599   
600    if (mbus != i2c_bus)
601        return RTEMS_INVALID_ADDRESS;
602   
603    base = i2c_bus->base;
604   
605    *MCF5206E_IMR(base) |= MCF5206E_INTR_BIT(MCF5206E_INTR_MBUS);
606    *MCF5206E_MBCR(base) = 0;
607
608    sc = rtems_interrupt_catch(
609        i2c_bus->oldisr,
610        24 + ((*MCF5206E_ICR(base, MCF5206E_INTR_MBUS) & MCF5206E_ICR_IL) >>
611                                   MCF5206E_ICR_IL_S),
612        NULL
613    );
614    return sc;
615}
Note: See TracBrowser for help on using the repository browser.