source: rtems/bsps/m68k/mcf5206elite/dev/mcfmbus.c @ 2190bc6

5
Last change on this file since 2190bc6 was 2190bc6, checked in by Sebastian Huber <sebastian.huber@…>, on 03/26/18 at 10:20:45

bsps/mcf5206elite: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 15.7 KB
Line 
1/*
2 *  MCF5206e MBUS module (I2C bus) driver
3 */
4
5/*
6 *  Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
7 *  Author: Victor V. Vengerov <vvv@oktet.ru>
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.rtems.org/license/LICENSE.
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  uint8_t   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
121  if (status & MCF5206E_MBSR_MIF) { /* Interrupt occured */
122    if (status & MCF5206E_MBSR_MAAS) {
123      event = EVENT_SLAVE;
124      *MCF5206E_MBCR(bus->base) = control; /* To clear Addressed As Slave
125                                              condition */
126    } else if (status & MCF5206E_MBSR_MAL) { /* Arbitration lost */
127      *MCF5206E_MBSR(bus->base) = status & ~MCF5206E_MBSR_MAL;
128      event = EVENT_ARB_LOST;
129    }
130    else if (control & MCF5206E_MBCR_MTX) { /* Trasmit mode */
131      if (status & MCF5206E_MBSR_RXAK)
132        event = EVENT_NACK;
133      else
134        event = EVENT_ACK;
135    } else { /* Received */
136      event = EVENT_DATA_RECV;
137    }
138
139    /* Clear interrupt condition */
140    *MCF5206E_MBSR(bus->base) &= ~MCF5206E_MBSR_MIF;
141  } else {
142    event = EVENT_NONE;
143  }
144  rtems_interrupt_enable(level);
145  return event;
146}
147
148static void mcfmbus_machine_error(mcfmbus *bus, i2c_event event)
149{
150}
151
152/* mcfmbus_machine --
153 *     finite state machine for I2C bus protocol
154 *
155 * PARAMETERS:
156 *     bus - pointer to ColdFire MBUS descriptor structure
157 *     event - I2C event
158 *
159 * RETURNS:
160 *     none
161 */
162static void mcfmbus_machine(mcfmbus *bus, i2c_event event)
163{
164  uint8_t   b;
165
166  switch (bus->state) {
167    case STATE_IDLE:
168      switch (event) {
169        case EVENT_NEXTMSG:  /* Start new message processing */
170          bus->cmsg++;
171          /* FALLTHRU */
172
173        case EVENT_TRANSFER: /* Initiate new transfer */
174          if (bus->cmsg - bus->msg >= bus->nmsg) {
175            mcfmbus_stop(bus);
176            next_state(bus, STATE_IDLE);
177            bus->msg = bus->cmsg = NULL;
178            bus->nmsg = bus->byte = 0;
179            bus->done((void *)bus->done_arg_ptr);
180            break;
181          }
182
183          /* Initiate START or REPEATED START condition on the bus */
184          if (event == EVENT_TRANSFER) {
185            mcfmbus_start(bus);
186          } else { /* (event == EVENT_NEXTMSG) */
187            mcfmbus_rstart(bus);
188          }
189
190          bus->byte = 0;
191          mcfmbus_tx_mode(bus);
192
193          /* Initiate slave address sending */
194          if (bus->cmsg->flags & I2C_MSG_ADDR_10) {
195            i2c_address a = bus->cmsg->addr;
196            b = 0xf0 | (((a >> 8) & 0x03) << 1);
197            if (bus->cmsg->flags & I2C_MSG_WR) {
198              mcfmbus_send(bus, b);
199              next_state(bus, STATE_ADDR_1_W);
200            } else {
201              mcfmbus_send(bus, b | 1);
202              next_state(bus, STATE_ADDR_1_R);
203            }
204          } else {
205            b = (bus->cmsg->addr & ~0x01);
206
207            if (bus->cmsg->flags & I2C_MSG_WR) {
208              next_state(bus, STATE_SENDING);
209            } else {
210              next_state(bus, STATE_ADDR_7);
211              b |= 1;
212            }
213
214            mcfmbus_send(bus, b);
215          }
216          break;
217
218        default:
219          mcfmbus_machine_error(bus, event);
220            break;
221      }
222      break;
223
224    case STATE_ADDR_7:
225      switch (event) {
226        case EVENT_ACK:
227          mcfmbus_rx_mode(bus);
228          if (bus->cmsg->len <= 1)
229            mcfmbus_send_nack(bus);
230          else
231            mcfmbus_send_ack(bus);
232          next_state(bus, STATE_RECEIVING);
233          break;
234
235        case EVENT_NACK:
236          mcfmbus_error(bus, I2C_NO_DEVICE);
237          next_state(bus, STATE_IDLE);
238          mcfmbus_machine(bus, EVENT_NEXTMSG);
239          break;
240
241        case EVENT_ARB_LOST:
242          mcfmbus_error(bus, I2C_ARBITRATION_LOST);
243          next_state(bus, STATE_IDLE);
244          mcfmbus_machine(bus, EVENT_NEXTMSG);
245          break;
246
247        default:
248          mcfmbus_machine_error(bus, event);
249          break;
250      }
251      break;
252
253    case STATE_ADDR_1_R:
254    case STATE_ADDR_1_W:
255      switch (event) {
256        case EVENT_ACK: {
257          uint8_t   b = (bus->cmsg->addr & 0xff);
258          mcfmbus_send(bus, b);
259          if (bus->state == STATE_ADDR_1_W) {
260              next_state(bus, STATE_SENDING);
261          } else {
262              i2c_address a;
263              mcfmbus_rstart(bus);
264              mcfmbus_tx_mode(bus);
265              a = bus->cmsg->addr;
266              b = 0xf0 | (((a >> 8) & 0x03) << 1) | 1;
267              mcfmbus_send(bus, b);
268              next_state(bus, STATE_ADDR_7);
269          }
270          break;
271        }
272
273        case EVENT_NACK:
274          mcfmbus_error(bus, I2C_NO_DEVICE);
275          next_state(bus, STATE_IDLE);
276          mcfmbus_machine(bus, EVENT_NEXTMSG);
277          break;
278
279        case EVENT_ARB_LOST:
280          mcfmbus_error(bus, I2C_ARBITRATION_LOST);
281          next_state(bus, STATE_IDLE);
282          mcfmbus_machine(bus, EVENT_NEXTMSG);
283          break;
284
285        default:
286          mcfmbus_machine_error(bus, event);
287          break;
288    }
289      break;
290
291    case STATE_SENDING:
292      switch (event) {
293        case EVENT_ACK:
294          if (bus->byte == bus->cmsg->len) {
295            next_state(bus, STATE_IDLE);
296            mcfmbus_machine(bus, EVENT_NEXTMSG);
297          } else {
298            mcfmbus_send(bus, bus->cmsg->buf[bus->byte++]);
299            next_state(bus, STATE_SENDING);
300          }
301          break;
302
303        case EVENT_NACK:
304          if (bus->byte == 0) {
305            mcfmbus_error(bus, I2C_NO_DEVICE);
306          } else {
307            mcfmbus_error(bus, I2C_NO_ACKNOWLEDGE);
308          }
309          next_state(bus, STATE_IDLE);
310          mcfmbus_machine(bus, EVENT_NEXTMSG);
311          break;
312
313        case EVENT_ARB_LOST:
314          mcfmbus_error(bus, I2C_ARBITRATION_LOST);
315          next_state(bus, STATE_IDLE);
316          mcfmbus_machine(bus, EVENT_NEXTMSG);
317          break;
318
319        default:
320          mcfmbus_machine_error(bus, event);
321          break;
322      }
323      break;
324
325    case STATE_RECEIVING:
326      switch (event) {
327        case EVENT_DATA_RECV:
328          if (bus->cmsg->len - bus->byte <= 2) {
329            mcfmbus_send_nack(bus);
330            if (bus->cmsg->len - bus->byte <= 1) {
331                if (bus->cmsg - bus->msg + 1 == bus->nmsg)
332                  mcfmbus_stop(bus);
333                else
334                  mcfmbus_rstart(bus);
335            }
336          } else {
337            mcfmbus_send_ack(bus);
338          }
339          bus->cmsg->buf[bus->byte++] = *MCF5206E_MBDR(bus->base);
340          if (bus->cmsg->len == bus->byte) {
341            next_state(bus,STATE_IDLE);
342            mcfmbus_machine(bus, EVENT_NEXTMSG);
343          } else {
344            next_state(bus,STATE_RECEIVING);
345          }
346          break;
347
348        case EVENT_ARB_LOST:
349          mcfmbus_error(bus, I2C_ARBITRATION_LOST);
350          next_state(bus, STATE_IDLE);
351          mcfmbus_machine(bus, EVENT_NEXTMSG);
352          break;
353
354        default:
355          mcfmbus_machine_error(bus, event);
356          break;
357      }
358      break;
359  }
360}
361
362/* mcfmbus_interrupt_handler --
363*     MBUS module interrupt handler routine
364*
365* PARAMETERS:
366*     vector - interrupt vector number (not used)
367*
368* RETURNS:
369*     none
370*/
371static rtems_isr mcfmbus_interrupt_handler(rtems_vector_number vector)
372{
373  i2c_event event;
374  event = mcfmbus_get_event(mbus);
375  mcfmbus_machine(mbus, event);
376}
377
378/* mcfmbus_poll --
379*     MBUS module poll routine; used to poll events when I2C driver
380*     operates in poll-driven mode.
381*
382* PARAMETERS:
383*     none
384*
385* RETURNS:
386*     none
387*/
388void
389mcfmbus_poll(mcfmbus *bus)
390{
391  i2c_event event;
392  event = mcfmbus_get_event(bus);
393  if (event != EVENT_NONE)
394      mcfmbus_machine(bus, event);
395}
396
397/* mcfmbus_select_clock_divider --
398*     Select divider for system clock which is used for I2C bus clock
399*     generation. Not each divider can be selected for I2C bus; this
400*     function select nearest larger or equal divider.
401*
402* PARAMETERS:
403*     i2c_bus - pointer to the bus descriptor structure
404*     divider - system frequency divider for I2C serial clock.
405* RETURNS:
406*     RTEMS_SUCCESSFUL, if operation performed successfully, or
407*     RTEMS error code when failed.
408*/
409rtems_status_code
410mcfmbus_select_clock_divider(mcfmbus *i2c_bus, int divider)
411{
412  int i;
413  int mbc;
414  struct {
415      int divider;
416      int mbc;
417  } dividers[] ={
418      { 20,   0x20 }, { 22,   0x21 }, { 24,   0x22 }, { 26,   0x23 },
419      { 28,   0x00 }, { 30,   0x01 }, { 32,   0x25 }, { 34,   0x02 },
420      { 36,   0x26 }, { 40,   0x03 }, { 44,   0x04 }, { 48,   0x05 },
421      { 56,   0x06 }, { 64,   0x2a }, { 68,   0x07 }, { 72,   0x2B },
422      { 80,   0x08 }, { 88,   0x09 }, { 96,   0x2D }, { 104,  0x0A },
423      { 112,  0x2E }, { 128,  0x0B }, { 144,  0x0C }, { 160,  0x0D },
424      { 192,  0x0E }, { 224,  0x32 }, { 240,  0x0F }, { 256,  0x33 },
425      { 288,  0x10 }, { 320,  0x11 }, { 384,  0x12 }, { 448,  0x36 },
426      { 480,  0x13 }, { 512,  0x37 }, { 576,  0x14 }, { 640,  0x15 },
427      { 768,  0x16 }, { 896,  0x3A }, { 960,  0x17 }, { 1024, 0x3B },
428      { 1152, 0x18 }, { 1280, 0x19 }, { 1536, 0x1A }, { 1792, 0x3E },
429      { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
430      { 3072, 0x1E }, { 3840, 0x1F }
431  };
432
433  if (i2c_bus == NULL)
434    return RTEMS_INVALID_ADDRESS;
435
436  for (i = 0, mbc = -1; i < sizeof(dividers)/sizeof(dividers[0]); i++) {
437    mbc = dividers[i].mbc;
438    if (dividers[i].divider >= divider) {
439      break;
440    }
441  }
442  *MCF5206E_MFDR(i2c_bus->base) = mbc;
443  return RTEMS_SUCCESSFUL;
444}
445
446/* mcfmbus_initialize --
447*     Initialize ColdFire MBUS I2C bus controller.
448*
449* PARAMETERS:
450*     i2c_bus - pointer to the bus descriptor structure
451*     base    - ColdFire internal peripherial base address
452*
453* RETURNS:
454*     RTEMS_SUCCESSFUL, or RTEMS error code when initialization failed.
455*/
456rtems_status_code mcfmbus_initialize(mcfmbus *i2c_bus, uint32_t   base)
457{
458  rtems_interrupt_level level;
459  rtems_status_code sc;
460
461  if (mbus != NULL) /* Check if already initialized */
462    return RTEMS_RESOURCE_IN_USE;
463
464  if (i2c_bus == NULL)
465    return RTEMS_INVALID_ADDRESS;
466
467
468  i2c_bus->base = base;
469  i2c_bus->state = STATE_IDLE;
470  i2c_bus->msg = NULL;
471  i2c_bus->cmsg = NULL;
472  i2c_bus->nmsg = 0;
473  i2c_bus->byte = 0;
474
475  sc = rtems_interrupt_catch(
476      mcfmbus_interrupt_handler,
477      24 + ((*MCF5206E_ICR(base, MCF5206E_INTR_MBUS) & MCF5206E_ICR_IL) >>
478                                 MCF5206E_ICR_IL_S),
479      &i2c_bus->oldisr
480  );
481  if (sc != RTEMS_SUCCESSFUL)
482    return sc;
483
484  mbus = i2c_bus;
485  rtems_interrupt_disable(level);
486  *MCF5206E_IMR(base) &= ~MCF5206E_INTR_BIT(MCF5206E_INTR_MBUS);
487  *MCF5206E_MBCR(base) = 0;
488  *MCF5206E_MBSR(base) = 0;
489  *MCF5206E_MBDR(base) = 0x1F; /* Maximum possible divider is 3840 */
490  *MCF5206E_MBCR(base) = MCF5206E_MBCR_MEN | MCF5206E_MBCR_MIEN;
491  rtems_interrupt_enable(level);
492
493  return RTEMS_SUCCESSFUL;
494}
495
496/* mcfmbus_i2c_transfer --
497*     Initiate multiple-messages transfer over I2C bus via ColdFire MBUS
498*     controller.
499*
500* PARAMETERS:
501*     bus - pointer to MBUS controller descriptor
502*     nmsg - number of messages
503*     msg - pointer to messages array
504*     done - function which is called when transfer is finished
505*     done_arg_ptr - arbitrary argument ptr passed to done funciton
506*
507* RETURNS:
508*     RTEMS_SUCCESSFUL if transfer initiated successfully, or error
509*     code when failed.
510*/
511rtems_status_code mcfmbus_i2c_transfer(
512  mcfmbus *bus,
513  int nmsg,
514  i2c_message *msg,
515  i2c_transfer_done done,
516  void *done_arg_ptr
517)
518{
519  if (bus != mbus)
520    return RTEMS_NOT_CONFIGURED;
521
522  bus->done = done;
523  bus->done_arg_ptr = (uintptr_t) done_arg_ptr;
524  bus->cmsg = bus->msg = msg;
525  bus->nmsg = nmsg;
526  bus->byte = 0;
527  bus->state = STATE_IDLE;
528  mcfmbus_machine(bus, EVENT_TRANSFER);
529  return RTEMS_SUCCESSFUL;
530}
531
532
533/* mcfmbus_i2c_done --
534*     Close ColdFire MBUS I2C bus controller and release all resources.
535*
536* PARAMETERS:
537*     bus - pointer to MBUS controller descriptor
538*
539* RETURNS:
540*     RTEMS_SUCCESSFUL, if transfer initiated successfully, or error
541*     code when failed.
542*/
543rtems_status_code mcfmbus_i2c_done(mcfmbus *i2c_bus)
544{
545  rtems_status_code sc;
546  uint32_t   base;
547  if (mbus == NULL)
548    return RTEMS_NOT_CONFIGURED;
549
550  if (mbus != i2c_bus)
551    return RTEMS_INVALID_ADDRESS;
552
553  base = i2c_bus->base;
554
555  *MCF5206E_IMR(base) |= MCF5206E_INTR_BIT(MCF5206E_INTR_MBUS);
556  *MCF5206E_MBCR(base) = 0;
557
558  sc = rtems_interrupt_catch(
559      i2c_bus->oldisr,
560      24 + ((*MCF5206E_ICR(base, MCF5206E_INTR_MBUS) & MCF5206E_ICR_IL) >>
561                                 MCF5206E_ICR_IL_S),
562      NULL
563  );
564  return sc;
565}
Note: See TracBrowser for help on using the repository browser.