source: rtems/bsps/powerpc/gen5200/i2c/mpc5200mbus.c @ 3fb2a815

Last change on this file since 3fb2a815 was 3fb2a815, checked in by Christian Mauderer <christian.mauderer@…>, on 03/03/22 at 08:17:22

bsps/powerpc/gen5200: Manual file header clean up

Updates #4625.

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