Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:46

0001 /*
0002  *  MCF5206e MBUS module (I2C bus) driver
0003  */
0004 
0005 /*
0006  *  Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
0007  *  Author: Victor V. Vengerov <vvv@oktet.ru>
0008  *
0009  *  The license and distribution terms for this file may be
0010  *  found in the file LICENSE in this distribution or at
0011  *  http://www.rtems.org/license/LICENSE.
0012  */
0013 
0014 #include "mcf5206/mcfmbus.h"
0015 #include "mcf5206/mcf5206e.h"
0016 #include "i2c.h"
0017 
0018 /* Events of I2C machine */
0019 typedef enum i2c_event {
0020   EVENT_NONE,      /* Spurious event */
0021   EVENT_TRANSFER,  /* Start new transfer */
0022   EVENT_NEXTMSG,   /* Start processing of next message in transfer */
0023   EVENT_ACK,       /* Sending finished with ACK */
0024   EVENT_NACK,      /* Sending finished with NACK */
0025   EVENT_TIMEOUT,   /* Timeout occured */
0026   EVENT_DATA_RECV, /* Data received */
0027   EVENT_ARB_LOST,  /* Arbitration lost */
0028   EVENT_SLAVE      /* Addressed as a slave */
0029 } i2c_event;
0030 
0031 static mcfmbus *mbus;
0032 
0033 /*** Auxillary primitives ***/
0034 
0035 /* Change state of finite state machine */
0036 #define next_state(bus,new_state) \
0037     do {                             \
0038         (bus)->state = (new_state);  \
0039     } while (0)
0040 
0041 /* Initiate start condition on the I2C bus */
0042 #define mcfmbus_start(bus) \
0043     do {                                                    \
0044         *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MSTA;  \
0045     } while (0)
0046 
0047 /* Initiate stop condition on the I2C bus */
0048 #define mcfmbus_stop(bus) \
0049     do {                                                    \
0050         *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MSTA; \
0051     } while (0)
0052 
0053 /* Initiate repeat start condition on the I2C bus */
0054 #define mcfmbus_rstart(bus) \
0055     do {                                                    \
0056         *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_RSTA;  \
0057     } while (0)
0058 
0059 /* Send byte to the bus */
0060 #define mcfmbus_send(bus,byte) \
0061     do {                                      \
0062         *MCF5206E_MBDR((bus)->base) = (byte); \
0063     } while (0)
0064 
0065 /* Set transmit mode */
0066 #define mcfmbus_tx_mode(bus) \
0067     do {                                                     \
0068         *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MTX;    \
0069     } while (0)
0070 
0071 /* Set receive mode */
0072 #define mcfmbus_rx_mode(bus) \
0073     do {                                                     \
0074         *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MTX;   \
0075         (void)*MCF5206E_MBDR((bus)->base);                   \
0076     } while (0)
0077 
0078 
0079 /* Transmit acknowledge when byte received */
0080 #define mcfmbus_send_ack(bus) \
0081     do {                                                     \
0082         *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_TXAK;  \
0083     } while (0)
0084 
0085 /* DO NOT transmit acknowledge when byte received */
0086 #define mcfmbus_send_nack(bus) \
0087     do {                                                     \
0088         *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_TXAK;   \
0089     } while (0)
0090 
0091 #define mcfmbus_error(bus,err_status) \
0092     do {                                                       \
0093         do {                                                   \
0094            (bus)->cmsg->status = (err_status);                 \
0095            (bus)->cmsg++;                                      \
0096         } while (((bus)->cmsg - (bus)->msg < (bus)->nmsg) &&   \
0097                  ((bus)->cmsg->flags & I2C_MSG_ERRSKIP));      \
0098         bus->cmsg--;                                           \
0099     } while (0)
0100 
0101 /* mcfmbus_get_event --
0102  *     Read MBUS module status register, determine interrupt reason and
0103  *     return appropriate event.
0104  *
0105  * PARAMETERS:
0106  *     bus - pointer to MBUS module descriptor structure
0107  *
0108  * RETURNS:
0109  *     event code
0110  */
0111 static i2c_event
0112 mcfmbus_get_event(mcfmbus *bus)
0113 {
0114   i2c_event event;
0115   uint8_t   status, control;
0116   rtems_interrupt_level level;
0117   rtems_interrupt_disable(level);
0118   status = *MCF5206E_MBSR(bus->base);
0119   control = *MCF5206E_MBCR(bus->base);
0120 
0121   if (status & MCF5206E_MBSR_MIF) { /* Interrupt occured */
0122     if (status & MCF5206E_MBSR_MAAS) {
0123       event = EVENT_SLAVE;
0124       *MCF5206E_MBCR(bus->base) = control; /* To clear Addressed As Slave
0125                                               condition */
0126     } else if (status & MCF5206E_MBSR_MAL) { /* Arbitration lost */
0127       *MCF5206E_MBSR(bus->base) = status & ~MCF5206E_MBSR_MAL;
0128       event = EVENT_ARB_LOST;
0129     }
0130     else if (control & MCF5206E_MBCR_MTX) { /* Trasmit mode */
0131       if (status & MCF5206E_MBSR_RXAK)
0132         event = EVENT_NACK;
0133       else
0134         event = EVENT_ACK;
0135     } else { /* Received */
0136       event = EVENT_DATA_RECV;
0137     }
0138 
0139     /* Clear interrupt condition */
0140     *MCF5206E_MBSR(bus->base) &= ~MCF5206E_MBSR_MIF;
0141   } else {
0142     event = EVENT_NONE;
0143   }
0144   rtems_interrupt_enable(level);
0145   return event;
0146 }
0147 
0148 static void mcfmbus_machine_error(mcfmbus *bus, i2c_event event)
0149 {
0150 }
0151 
0152 /* mcfmbus_machine --
0153  *     finite state machine for I2C bus protocol
0154  *
0155  * PARAMETERS:
0156  *     bus - pointer to ColdFire MBUS descriptor structure
0157  *     event - I2C event
0158  *
0159  * RETURNS:
0160  *     none
0161  */
0162 static void mcfmbus_machine(mcfmbus *bus, i2c_event event)
0163 {
0164   uint8_t   b;
0165 
0166   switch (bus->state) {
0167     case STATE_IDLE:
0168       switch (event) {
0169         case EVENT_NEXTMSG:  /* Start new message processing */
0170           bus->cmsg++;
0171           /* FALLTHRU */
0172 
0173         case EVENT_TRANSFER: /* Initiate new transfer */
0174           if (bus->cmsg - bus->msg >= bus->nmsg) {
0175             mcfmbus_stop(bus);
0176             next_state(bus, STATE_IDLE);
0177             bus->msg = bus->cmsg = NULL;
0178             bus->nmsg = bus->byte = 0;
0179             bus->done((void *)bus->done_arg_ptr);
0180             break;
0181           }
0182 
0183           /* Initiate START or REPEATED START condition on the bus */
0184           if (event == EVENT_TRANSFER) {
0185             mcfmbus_start(bus);
0186           } else { /* (event == EVENT_NEXTMSG) */
0187             mcfmbus_rstart(bus);
0188           }
0189 
0190           bus->byte = 0;
0191           mcfmbus_tx_mode(bus);
0192 
0193           /* Initiate slave address sending */
0194           if (bus->cmsg->flags & I2C_MSG_ADDR_10) {
0195             i2c_address a = bus->cmsg->addr;
0196             b = 0xf0 | (((a >> 8) & 0x03) << 1);
0197             if (bus->cmsg->flags & I2C_MSG_WR) {
0198               mcfmbus_send(bus, b);
0199               next_state(bus, STATE_ADDR_1_W);
0200             } else {
0201               mcfmbus_send(bus, b | 1);
0202               next_state(bus, STATE_ADDR_1_R);
0203             }
0204           } else {
0205             b = (bus->cmsg->addr & ~0x01);
0206 
0207             if (bus->cmsg->flags & I2C_MSG_WR) {
0208               next_state(bus, STATE_SENDING);
0209             } else {
0210               next_state(bus, STATE_ADDR_7);
0211               b |= 1;
0212             }
0213 
0214             mcfmbus_send(bus, b);
0215           }
0216           break;
0217 
0218         default:
0219           mcfmbus_machine_error(bus, event);
0220             break;
0221       }
0222       break;
0223 
0224     case STATE_ADDR_7:
0225       switch (event) {
0226         case EVENT_ACK:
0227           mcfmbus_rx_mode(bus);
0228           if (bus->cmsg->len <= 1)
0229             mcfmbus_send_nack(bus);
0230           else
0231             mcfmbus_send_ack(bus);
0232           next_state(bus, STATE_RECEIVING);
0233           break;
0234 
0235         case EVENT_NACK:
0236           mcfmbus_error(bus, I2C_NO_DEVICE);
0237           next_state(bus, STATE_IDLE);
0238           mcfmbus_machine(bus, EVENT_NEXTMSG);
0239           break;
0240 
0241         case EVENT_ARB_LOST:
0242           mcfmbus_error(bus, I2C_ARBITRATION_LOST);
0243           next_state(bus, STATE_IDLE);
0244           mcfmbus_machine(bus, EVENT_NEXTMSG);
0245           break;
0246 
0247         default:
0248           mcfmbus_machine_error(bus, event);
0249           break;
0250       }
0251       break;
0252 
0253     case STATE_ADDR_1_R:
0254     case STATE_ADDR_1_W:
0255       switch (event) {
0256         case EVENT_ACK: {
0257           uint8_t   b = (bus->cmsg->addr & 0xff);
0258           mcfmbus_send(bus, b);
0259           if (bus->state == STATE_ADDR_1_W) {
0260               next_state(bus, STATE_SENDING);
0261           } else {
0262               i2c_address a;
0263               mcfmbus_rstart(bus);
0264               mcfmbus_tx_mode(bus);
0265               a = bus->cmsg->addr;
0266               b = 0xf0 | (((a >> 8) & 0x03) << 1) | 1;
0267               mcfmbus_send(bus, b);
0268               next_state(bus, STATE_ADDR_7);
0269           }
0270           break;
0271         }
0272 
0273         case EVENT_NACK:
0274           mcfmbus_error(bus, I2C_NO_DEVICE);
0275           next_state(bus, STATE_IDLE);
0276           mcfmbus_machine(bus, EVENT_NEXTMSG);
0277           break;
0278 
0279         case EVENT_ARB_LOST:
0280           mcfmbus_error(bus, I2C_ARBITRATION_LOST);
0281           next_state(bus, STATE_IDLE);
0282           mcfmbus_machine(bus, EVENT_NEXTMSG);
0283           break;
0284 
0285         default:
0286           mcfmbus_machine_error(bus, event);
0287           break;
0288     }
0289       break;
0290 
0291     case STATE_SENDING:
0292       switch (event) {
0293         case EVENT_ACK:
0294           if (bus->byte == bus->cmsg->len) {
0295             next_state(bus, STATE_IDLE);
0296             mcfmbus_machine(bus, EVENT_NEXTMSG);
0297           } else {
0298             mcfmbus_send(bus, bus->cmsg->buf[bus->byte++]);
0299             next_state(bus, STATE_SENDING);
0300           }
0301           break;
0302 
0303         case EVENT_NACK:
0304           if (bus->byte == 0) {
0305             mcfmbus_error(bus, I2C_NO_DEVICE);
0306           } else {
0307             mcfmbus_error(bus, I2C_NO_ACKNOWLEDGE);
0308           }
0309           next_state(bus, STATE_IDLE);
0310           mcfmbus_machine(bus, EVENT_NEXTMSG);
0311           break;
0312 
0313         case EVENT_ARB_LOST:
0314           mcfmbus_error(bus, I2C_ARBITRATION_LOST);
0315           next_state(bus, STATE_IDLE);
0316           mcfmbus_machine(bus, EVENT_NEXTMSG);
0317           break;
0318 
0319         default:
0320           mcfmbus_machine_error(bus, event);
0321           break;
0322       }
0323       break;
0324 
0325     case STATE_RECEIVING:
0326       switch (event) {
0327         case EVENT_DATA_RECV:
0328           if (bus->cmsg->len - bus->byte <= 2) {
0329             mcfmbus_send_nack(bus);
0330             if (bus->cmsg->len - bus->byte <= 1) {
0331                 if (bus->cmsg - bus->msg + 1 == bus->nmsg)
0332                   mcfmbus_stop(bus);
0333                 else
0334                   mcfmbus_rstart(bus);
0335             }
0336           } else {
0337             mcfmbus_send_ack(bus);
0338           }
0339           bus->cmsg->buf[bus->byte++] = *MCF5206E_MBDR(bus->base);
0340           if (bus->cmsg->len == bus->byte) {
0341             next_state(bus,STATE_IDLE);
0342             mcfmbus_machine(bus, EVENT_NEXTMSG);
0343           } else {
0344             next_state(bus,STATE_RECEIVING);
0345           }
0346           break;
0347 
0348         case EVENT_ARB_LOST:
0349           mcfmbus_error(bus, I2C_ARBITRATION_LOST);
0350           next_state(bus, STATE_IDLE);
0351           mcfmbus_machine(bus, EVENT_NEXTMSG);
0352           break;
0353 
0354         default:
0355           mcfmbus_machine_error(bus, event);
0356           break;
0357       }
0358       break;
0359   }
0360 }
0361 
0362 /* mcfmbus_interrupt_handler --
0363 *     MBUS module interrupt handler routine
0364 *
0365 * PARAMETERS:
0366 *     vector - interrupt vector number (not used)
0367 *
0368 * RETURNS:
0369 *     none
0370 */
0371 static rtems_isr mcfmbus_interrupt_handler(rtems_vector_number vector)
0372 {
0373   i2c_event event;
0374   event = mcfmbus_get_event(mbus);
0375   mcfmbus_machine(mbus, event);
0376 }
0377 
0378 /* mcfmbus_poll --
0379 *     MBUS module poll routine; used to poll events when I2C driver
0380 *     operates in poll-driven mode.
0381 *
0382 * PARAMETERS:
0383 *     none
0384 *
0385 * RETURNS:
0386 *     none
0387 */
0388 void
0389 mcfmbus_poll(mcfmbus *bus)
0390 {
0391   i2c_event event;
0392   event = mcfmbus_get_event(bus);
0393   if (event != EVENT_NONE)
0394       mcfmbus_machine(bus, event);
0395 }
0396 
0397 /* mcfmbus_select_clock_divider --
0398 *     Select divider for system clock which is used for I2C bus clock
0399 *     generation. Not each divider can be selected for I2C bus; this
0400 *     function select nearest larger or equal divider.
0401 *
0402 * PARAMETERS:
0403 *     i2c_bus - pointer to the bus descriptor structure
0404 *     divider - system frequency divider for I2C serial clock.
0405 * RETURNS:
0406 *     RTEMS_SUCCESSFUL, if operation performed successfully, or
0407 *     RTEMS error code when failed.
0408 */
0409 rtems_status_code
0410 mcfmbus_select_clock_divider(mcfmbus *i2c_bus, int divider)
0411 {
0412   int i;
0413   int mbc;
0414   struct {
0415       int divider;
0416       int mbc;
0417   } dividers[] ={
0418       { 20,   0x20 }, { 22,   0x21 }, { 24,   0x22 }, { 26,   0x23 },
0419       { 28,   0x00 }, { 30,   0x01 }, { 32,   0x25 }, { 34,   0x02 },
0420       { 36,   0x26 }, { 40,   0x03 }, { 44,   0x04 }, { 48,   0x05 },
0421       { 56,   0x06 }, { 64,   0x2a }, { 68,   0x07 }, { 72,   0x2B },
0422       { 80,   0x08 }, { 88,   0x09 }, { 96,   0x2D }, { 104,  0x0A },
0423       { 112,  0x2E }, { 128,  0x0B }, { 144,  0x0C }, { 160,  0x0D },
0424       { 192,  0x0E }, { 224,  0x32 }, { 240,  0x0F }, { 256,  0x33 },
0425       { 288,  0x10 }, { 320,  0x11 }, { 384,  0x12 }, { 448,  0x36 },
0426       { 480,  0x13 }, { 512,  0x37 }, { 576,  0x14 }, { 640,  0x15 },
0427       { 768,  0x16 }, { 896,  0x3A }, { 960,  0x17 }, { 1024, 0x3B },
0428       { 1152, 0x18 }, { 1280, 0x19 }, { 1536, 0x1A }, { 1792, 0x3E },
0429       { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
0430       { 3072, 0x1E }, { 3840, 0x1F }
0431   };
0432 
0433   if (i2c_bus == NULL)
0434     return RTEMS_INVALID_ADDRESS;
0435 
0436   for (i = 0, mbc = -1; i < sizeof(dividers)/sizeof(dividers[0]); i++) {
0437     mbc = dividers[i].mbc;
0438     if (dividers[i].divider >= divider) {
0439       break;
0440     }
0441   }
0442   *MCF5206E_MFDR(i2c_bus->base) = mbc;
0443   return RTEMS_SUCCESSFUL;
0444 }
0445 
0446 /* mcfmbus_initialize --
0447 *     Initialize ColdFire MBUS I2C bus controller.
0448 *
0449 * PARAMETERS:
0450 *     i2c_bus - pointer to the bus descriptor structure
0451 *     base    - ColdFire internal peripherial base address
0452 *
0453 * RETURNS:
0454 *     RTEMS_SUCCESSFUL, or RTEMS error code when initialization failed.
0455 */
0456 rtems_status_code mcfmbus_initialize(mcfmbus *i2c_bus, uint32_t   base)
0457 {
0458   rtems_interrupt_level level;
0459   rtems_status_code sc;
0460 
0461   if (mbus != NULL) /* Check if already initialized */
0462     return RTEMS_RESOURCE_IN_USE;
0463 
0464   if (i2c_bus == NULL)
0465     return RTEMS_INVALID_ADDRESS;
0466 
0467 
0468   i2c_bus->base = base;
0469   i2c_bus->state = STATE_IDLE;
0470   i2c_bus->msg = NULL;
0471   i2c_bus->cmsg = NULL;
0472   i2c_bus->nmsg = 0;
0473   i2c_bus->byte = 0;
0474 
0475   sc = rtems_interrupt_catch(
0476       mcfmbus_interrupt_handler,
0477       24 + ((*MCF5206E_ICR(base, MCF5206E_INTR_MBUS) & MCF5206E_ICR_IL) >>
0478                                  MCF5206E_ICR_IL_S),
0479       &i2c_bus->oldisr
0480   );
0481   if (sc != RTEMS_SUCCESSFUL)
0482     return sc;
0483 
0484   mbus = i2c_bus;
0485   rtems_interrupt_disable(level);
0486   *MCF5206E_IMR(base) &= ~MCF5206E_INTR_BIT(MCF5206E_INTR_MBUS);
0487   *MCF5206E_MBCR(base) = 0;
0488   *MCF5206E_MBSR(base) = 0;
0489   *MCF5206E_MBDR(base) = 0x1F; /* Maximum possible divider is 3840 */
0490   *MCF5206E_MBCR(base) = MCF5206E_MBCR_MEN | MCF5206E_MBCR_MIEN;
0491   rtems_interrupt_enable(level);
0492 
0493   return RTEMS_SUCCESSFUL;
0494 }
0495 
0496 /* mcfmbus_i2c_transfer --
0497 *     Initiate multiple-messages transfer over I2C bus via ColdFire MBUS
0498 *     controller.
0499 *
0500 * PARAMETERS:
0501 *     bus - pointer to MBUS controller descriptor
0502 *     nmsg - number of messages
0503 *     msg - pointer to messages array
0504 *     done - function which is called when transfer is finished
0505 *     done_arg_ptr - arbitrary argument ptr passed to done funciton
0506 *
0507 * RETURNS:
0508 *     RTEMS_SUCCESSFUL if transfer initiated successfully, or error
0509 *     code when failed.
0510 */
0511 rtems_status_code mcfmbus_i2c_transfer(
0512   mcfmbus *bus,
0513   int nmsg,
0514   i2c_message *msg,
0515   i2c_transfer_done done,
0516   void *done_arg_ptr
0517 )
0518 {
0519   if (bus != mbus)
0520     return RTEMS_NOT_CONFIGURED;
0521 
0522   bus->done = done;
0523   bus->done_arg_ptr = (uintptr_t) done_arg_ptr;
0524   bus->cmsg = bus->msg = msg;
0525   bus->nmsg = nmsg;
0526   bus->byte = 0;
0527   bus->state = STATE_IDLE;
0528   mcfmbus_machine(bus, EVENT_TRANSFER);
0529   return RTEMS_SUCCESSFUL;
0530 }
0531 
0532 
0533 /* mcfmbus_i2c_done --
0534 *     Close ColdFire MBUS I2C bus controller and release all resources.
0535 *
0536 * PARAMETERS:
0537 *     bus - pointer to MBUS controller descriptor
0538 *
0539 * RETURNS:
0540 *     RTEMS_SUCCESSFUL, if transfer initiated successfully, or error
0541 *     code when failed.
0542 */
0543 rtems_status_code mcfmbus_i2c_done(mcfmbus *i2c_bus)
0544 {
0545   rtems_status_code sc;
0546   uint32_t   base;
0547   if (mbus == NULL)
0548     return RTEMS_NOT_CONFIGURED;
0549 
0550   if (mbus != i2c_bus)
0551     return RTEMS_INVALID_ADDRESS;
0552 
0553   base = i2c_bus->base;
0554 
0555   *MCF5206E_IMR(base) |= MCF5206E_INTR_BIT(MCF5206E_INTR_MBUS);
0556   *MCF5206E_MBCR(base) = 0;
0557 
0558   sc = rtems_interrupt_catch(
0559       i2c_bus->oldisr,
0560       24 + ((*MCF5206E_ICR(base, MCF5206E_INTR_MBUS) & MCF5206E_ICR_IL) >>
0561                                  MCF5206E_ICR_IL_S),
0562       NULL
0563   );
0564   return sc;
0565 }