source: rtems/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c @ 4a4c7900

4.104.114.84.95
Last change on this file since 4a4c7900 was 4a4c7900, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 08/13/06 at 15:58:46

added vectors.h to bsp.h
fixed bug in mscan

  • Property mode set to 100644
File size: 50.1 KB
RevLine 
[ca680bc5]1/*===============================================================*\
2| Project: RTEMS generic MPC5200 BSP                              |
3+-----------------------------------------------------------------+
4|                    Copyright (c) 2005                           |
5|                    Embedded Brains GmbH                         |
6|                    Obere Lagerstr. 30                           |
7|                    D-82178 Puchheim                             |
8|                    Germany                                      |
9|                    rtems@embedded-brains.de                     |
10+-----------------------------------------------------------------+
11| The license and distribution terms for this file may be         |
12| found in the file LICENSE in this distribution or at            |
13|                                                                 |
14| http://www.rtems.com/license/LICENSE.                           |
15|                                                                 |
16+-----------------------------------------------------------------+
17| this file contains the MSCAN driver                             |
18\*===============================================================*/
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <rtems.h>
23#include <rtems/error.h>
24#include <rtems/libio.h>
25#include <string.h>
[4a4c7900]26#include "../include/bsp.h"
[ca680bc5]27#include "../irq/irq.h"
28#include "../include/mpc5200.h"
[da261595]29#include "mscan.h"
[ca680bc5]30
31/* #define MSCAN_LOOPBACK */
32
[c9b005a9]33volatile uint32_t tx_int_wr_count = 0;
34
[ca680bc5]35struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO];
[4a4c7900]36static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
[c9b005a9]37
38/* time segmant table  */
39uint8_t can_time_segment_table[CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1][NO_OF_TABLE_ENTRIES] = {
40
41/* Total no. of time quantas */   /* Time Segment 1*/    /* Time Segment 2 */     /* Sync: Jump width */
42{         7,                                4,                     2,                       1          },
43{         8,                                5,                     2,                       1          },
44{         9,                                6,                     2,                       2          },
45{        10,                                6,                     3,                       2          },
46{        11,                                7,                     3,                       2          },
47{        12,                                8,                     3,                       2          },
48{        13,                                8,                     4,                       2          },
49{        14,                                9,                     4,                       2          },
50{        15,                               10,                     4,                       2          },
51{        16,                               10,                     5,                       2          },
52{        17,                               11,                     5,                       2          },
53{        18,                               12,                     5,                       2          },
54{        19,                               12,                     6,                       2          },
55{        20,                               13,                     6,                       2          },
56{        21,                               14,                     6,                       2          },
57{        22,                               14,                     7,                       2          },
58{        23,                               15,                     7,                       2          },
59{        24,                               15,                     8,                       2          },
60{        25,                               16,                     8,                       2          }};
61
62
63/*
64 * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer
65 */
[4a4c7900]66static struct can_message * get_tx_buffer(struct mscan_channel_info *chan)
[c9b005a9]67  {
68  /* define a temp. mess ptr. */
[4a4c7900]69  struct can_message * tmp_mess_ptr = NULL, *temp_head_ptr;
[c9b005a9]70
71  /* set temp. head pointer */
72  temp_head_ptr = chan->tx_ring_buf.head_ptr;
73
74  /* check buffer empty condition */
75  if(temp_head_ptr != chan->tx_ring_buf.tail_ptr)
76    {
77
78    /* current buffer head. ptr. */
79    tmp_mess_ptr = temp_head_ptr;
80
81    /* increment the head pointer */
82    temp_head_ptr++;
83
84    /* check for wrap around condition */
85    if(temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
86      {
87
88      /* set head ptr. to the begin of the ring buffer */
89      temp_head_ptr = chan->tx_ring_buf.buf_ptr;
90
91      }
92
93    /* end of crtical section restore head ptr. */
94    chan->tx_ring_buf.head_ptr = temp_head_ptr;
95    }
96
97  /* return the current head pointer */
98  return tmp_mess_ptr;
99  }
100
101/*
102 * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer
103 */
[4a4c7900]104static struct can_message * fill_tx_buffer(struct mscan_channel_info *chan, struct can_message * mess_ptr)
[c9b005a9]105  {
106  /* define a temp. mess ptr. to the entry which follows the current tail entry */
107  struct can_message * tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1;
108
109  /* check for the wrap around condition */
110  if(tmp_mess_ptr >  chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
111    {
112        /* set temp. mess. ptr to the begin of the ring buffer */
113        tmp_mess_ptr = chan->tx_ring_buf.buf_ptr;
114    }
115
116  /* check buffer full condition */
117  if(tmp_mess_ptr == chan->tx_ring_buf.head_ptr)
118    {
119        /* return NULL in case buffer is full */
120        return NULL;
121    }
122  else
123    {
124        /* copy the can mess. to the tail of the buffer */
125    memcpy((void *)chan->tx_ring_buf.tail_ptr, (void *)mess_ptr, sizeof(struct can_message));
126
127    /* set new tail equal to temp. mess. ptr. */
128    chan->tx_ring_buf.tail_ptr = tmp_mess_ptr;
129    }
130
131  /* return the actual tail ptr. (next free entry) */
132  return chan->tx_ring_buf.tail_ptr;
133  }
[ca680bc5]134
135/*
136 * MPC5x00 MSCAN interrupt handler
137 */
138static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
139  {
140  rtems_status_code status;
141  mscan_handle *mscan_hdl = (mscan_handle *)handle;
142  struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel];
[c9b005a9]143  struct can_message rx_mess, *rx_mess_ptr, *tx_mess_ptr;
[ca680bc5]144  volatile struct mpc5200_mscan *mscan = chan->regs;
[c9b005a9]145  register uint8_t idx;
[ca680bc5]146
147  /*
[c9b005a9]148   handle tx ring buffer
[ca680bc5]149   */
150
[c9b005a9]151  /* loop over all 3 tx buffers */
152  for(idx = TFLG_TXE0; idx <= TFLG_TXE2; idx=idx<<1)
153    {
154
155    /* check for tx buffer vacation */
156    if((mscan->tflg) & idx)
157      {
158
159      /* try to get a message */
160      tx_mess_ptr = get_tx_buffer(chan);
161
162      /* check for new tx message */
163      if(tx_mess_ptr != NULL)
164        {
165
166        /* select the tx buffer */
167        mscan->bsel  = idx;
168
169        /* check for toucan interface */
170        if((mscan_hdl->toucan_callback) == NULL)
171          {
172
173          /* set tx id */
174                  mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
175                  mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
176                  mscan->txidr2 = 0;
177          mscan->txidr3 = 0;
178
179          /* insert dlc into mscan register */
180                  mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
181              }
182
183        /* select one free tx buffer if TOUCAN not registered) */
184        if(((mscan_hdl->toucan_callback) == NULL) || (((mscan_hdl->toucan_callback) != NULL) && ((tx_mess_ptr->toucan_tx_id) == idx)))
185          {
186
187          /* set tx id */
188                  mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
189                  mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
190                  mscan->txidr2 = 0;
191          mscan->txidr3 = 0;
192
193          /* insert dlc into mscan register */
194                  mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
195
196          /* copy tx data to MSCAN registers */
197          switch(mscan->txdlr)
198            {
199            case 8:
200              mscan->txdsr7 = tx_mess_ptr->mess_data[7];
201            case 7:
202              mscan->txdsr6 = tx_mess_ptr->mess_data[6];
203            case 6:
204              mscan->txdsr5 = tx_mess_ptr->mess_data[5];
205            case 5:
206              mscan->txdsr4 = tx_mess_ptr->mess_data[4];
207            case 4:
208              mscan->txdsr3 = tx_mess_ptr->mess_data[3];
209            case 3:
210              mscan->txdsr2 = tx_mess_ptr->mess_data[2];
211            case 2:
212              mscan->txdsr1 = tx_mess_ptr->mess_data[1];
213            case 1:
214              mscan->txdsr0 = tx_mess_ptr->mess_data[0];
215              break;
216            default:
217              break;
218            }
219
220          /* enable message buffer specific interrupt */
221              mscan->tier |= mscan->bsel;
222
223              /* start transfer */
224          mscan->tflg = mscan->bsel;
225
226          /* release counting semaphore of tx ring buffer */
227                  rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
228
229                  tx_int_wr_count++;
[ca680bc5]230
[c9b005a9]231          }
232        else
233          {
[ca680bc5]234
[c9b005a9]235          /* refill the tx ring buffer with the message */
236          fill_tx_buffer(chan, tx_mess_ptr);
237
238              }
239            }
240          else
241            {
242                /* reset interrupt enable bit */
243            mscan->tier &= ~(idx);
244            }
245      }
246    }
[ca680bc5]247
248  /*
249   handle rx interrupts
250   */
251
252  /* check for rx interrupt source */
253  if(mscan->rier & RIER_RXFIE)
254    {
255
256    /* can messages received ? */
257    while(mscan->rflg & RFLG_RXF)
258      {
259
260      if(mscan_hdl->toucan_callback == NULL)
261        {
262
263        /* select temporary rx buffer */
264        rx_mess_ptr = &rx_mess;
265
266        }
267      else
268        {
269
270        /* check the rx fliter-match indicators (16-bit filter mode) */
271        /* in case of more than one hit, lower hit has priority */
[c9b005a9]272          idx = (mscan->idac) & 0x7;
273          switch(idx)
[ca680bc5]274          {
275
276          case 0:
[c9b005a9]277          case 1:
[ca680bc5]278          case 2:
[c9b005a9]279          case 3:
280            rx_mess_ptr =
281              (struct can_message *)&(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel].can_rx_message[idx]);
282            break;
[ca680bc5]283
284          /* this case should never happen */
285                  default:
286            /* reset the rx indication flag */
287            mscan->rflg |= RFLG_RXF;
288
289            return;
290            break;
291              }
292
293        }
294
295      /* get rx ID */
296      rx_mess_ptr->mess_id = GET_IDR0(mscan->rxidr0) | GET_IDR1(mscan->rxidr1);
297
298      /* get rx len */
299      rx_mess_ptr->mess_len = ((mscan->rxdlr) & 0x0F);
300
301      /* get time stamp */
302      rx_mess_ptr->mess_time_stamp = ((mscan->rxtimh << 8) | (mscan->rxtiml));
303
304      /* get the data */
305          switch(rx_mess_ptr->mess_len)
306            {
307
308            case 8:
309              rx_mess_ptr->mess_data[7] = mscan->rxdsr7;
310            case 7:
311              rx_mess_ptr->mess_data[6] = mscan->rxdsr6;
312            case 6:
313              rx_mess_ptr->mess_data[5] = mscan->rxdsr5;
314            case 5:
315              rx_mess_ptr->mess_data[4] = mscan->rxdsr4;
316            case 4:
317              rx_mess_ptr->mess_data[3] = mscan->rxdsr3;
318            case 3:
319              rx_mess_ptr->mess_data[2] = mscan->rxdsr2;
320            case 2:
321              rx_mess_ptr->mess_data[1] = mscan->rxdsr1;
322            case 1:
323              rx_mess_ptr->mess_data[0] = mscan->rxdsr0;
324            case 0:
325            default:
326              break;
327
328            }
329
330      if(mscan_hdl->toucan_callback == NULL)
331        {
332
333        if((status = rtems_message_queue_send(chan->rx_qid, (void *)rx_mess_ptr, sizeof(struct can_message))) != RTEMS_SUCCESSFUL)
334                  {
335
336                  chan->int_rx_err++;
337
338          }
339
340            }
341      else
342        {
343
344        mscan_hdl->toucan_callback((int16_t)(((mscan->idac) & 0x7) + 3));
345
346            }
347
348      /* reset the rx indication flag */
349      mscan->rflg |= RFLG_RXF;
350
351      } /* end of while(mscan->rflg & RFLG_RXF) */
352
353    }
354
355    /* status change detected */
356    if(mscan->rflg & RFLG_CSCIF)
357      {
358
359      mscan->rflg |= RFLG_CSCIF;
360
361      if(mscan_hdl->toucan_callback != NULL)
362        {
363
364        mscan_hdl->toucan_callback((int16_t)(-1));
365
366        }
367
368      }
369
370  }
371
372
373/*
374 * Disable MSCAN ints.
375 */
376void mpc5200_mscan_int_disable(volatile struct mpc5200_mscan *mscan)
377  {
378
379  /* RX Interrupt Enable on MSCAN_A/_B -----------------------------*/
380  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
381  /*    [06]:CSCIE         0 : Status Change interrupt disabled     */
382  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
383  /*    [04]:RSTATE0       0 : Recv. Status Change int. ,Bit 0      */
384  /*                           -> 00 rx status change int. disabled */
385  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
386  /*    [02]:TSTAT0        0 : Transmit. Status Change int. , Bit 0 */
387  /*                           -> 00 tx status change int. disabled */
388  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
389  /*    [00]:RXFIE         0 : Recv. Full interrupt is disabled     */
390  mscan->rier &= ~(RIER_CSCIE | RIER_RXFIE);
391
392  /* TX Interrupt Enable on MSCAN_A/_B -----------------------------*/
393  /*    [07]:res.          0 : reserved                             */
394  /*    [06]:res.          0 : reserved                             */
395  /*    [05]:res.          0 : reserved                             */
396  /*    [04]:res.          0 : reserved                             */
397  /*    [03]:res.          0 : reserved                             */
398  /*    [02]:TSEG12        0 : TX2message buffer int. is disabled   */
399  /*    [01]:TSEG11        0 : TX1 message buffer int. is disabled  */
400  /*    [00]:TSEG10        0 : TX0 message buffer int. is disabled  */
401  mscan->tier &= ~(TIER_TXEI2 | TIER_TXEI1 | TIER_TXEI0);
402
403  return;
404
405  }
406
407
408/*
409 * Enable MSCAN ints.
410 */
411void mpc5200_mscan_int_enable(volatile struct mpc5200_mscan *mscan)
412  {
413
414  /* RX Interrupt Enable on MSCAN_A/_B -----------------------------*/
415  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
416  /*    [06]:CSCIE         1 : Status Change interrupt enabled      */
417  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
418  /*    [04]:RSTATE0       1 : Recv. Status Change int. ,Bit 0      */
419  /*                           -> 01 BusOff status changes enabled  */
420  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
421  /*    [02]:TSTAT0        1 : Transmit. Status Change int. , Bit 0 */
422  /*                           -> 01 BusOff status changes enabled  */
423  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
424  /*    [00]:RXFIE         1 : Recv. Full interrupt is enabled      */
425  mscan->rier |= (RIER_CSCIE  | RIER_RXFIE | RIER_RSTAT(1) | RIER_TSTAT(1));
426
427  return;
428
429  }
430
431/*
432 * Unmask MPC5x00 MSCAN_A interrupts
433 */
434void mpc5200_mscan_a_on(const rtems_irq_connect_data* ptr)
435  {
436  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
437
438  mpc5200_mscan_int_enable(mscan);
439
440  return;
441
442  }
443
444
445/*
446 * Mask MPC5x00 MSCAN_A interrupts
447 */
448void mpc5200_mscan_a_off(const rtems_irq_connect_data* ptr)
449  {
450  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
451
452  mpc5200_mscan_int_disable(mscan);
453
454  return;
455
456  }
457
458
459/*
460 *  Get MSCAN_A interrupt mask setting
461 */
462int mpc5200_mscan_a_isOn(const rtems_irq_connect_data* ptr)
463  {
464  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
465
466  if((mscan->rier & RIER_CSCIE) && (mscan->rier & RIER_RXFIE))
467    return RTEMS_SUCCESSFUL;
468  else
469    return RTEMS_UNSATISFIED;
470
471  return RTEMS_SUCCESSFUL;
472
473  }
474
475
476/*
477 * Unmask MPC5x00 MSCAN_B interrupts
478 */
479void mpc5200_mscan_b_on(const rtems_irq_connect_data* ptr)
480  {
481  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
482
483  mpc5200_mscan_int_enable(mscan);
484
485  return;
486
487  }
488
489
490/*
491 * Mask MPC5x00 MSCAN_B interrupts
492 */
493void mpc5200_mscan_b_off(const rtems_irq_connect_data* ptr)
494  {
495  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
496
497  mpc5200_mscan_int_disable(mscan);
498
499  return;
500
501  }
502
503
504/*
505 *  Get MSCAN_B interrupt mask setting
506 */
507int mpc5200_mscan_b_isOn(const rtems_irq_connect_data* ptr)
508  {
509  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
510
511  if((mscan->rier & RIER_CSCIE) && (mscan->rier & RIER_RXFIE))
512    return RTEMS_SUCCESSFUL;
513  else
514    return RTEMS_UNSATISFIED;
515
516  return RTEMS_SUCCESSFUL;
517
518  }
519
520static mscan_handle mscan_a_handle =
521  {
522  MSCAN_A,
523  NULL
524  };
525
526
527static mscan_handle mscan_b_handle =
528  {
529  MSCAN_B,
530  NULL
531  };
532
533/*
534 * MPC5x00 MSCAN_A/_B irq data
535 */
536static rtems_irq_connect_data mpc5200_mscan_irq_data[MPC5200_CAN_NO] =
537  {{
538  BSP_SIU_IRQ_MSCAN1,
539  (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
540  (rtems_irq_hdl_param) &mscan_a_handle,
541  (rtems_irq_enable) mpc5200_mscan_a_on,
542  (rtems_irq_disable) mpc5200_mscan_a_off,
543  (rtems_irq_is_enabled) mpc5200_mscan_a_isOn
544  },
545  {
546  BSP_SIU_IRQ_MSCAN2,
547  (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
548  (rtems_irq_hdl_param) &mscan_b_handle,
549  (rtems_irq_enable) mpc5200_mscan_b_on,
550  (rtems_irq_disable) mpc5200_mscan_b_off,
551  (rtems_irq_is_enabled) mpc5200_mscan_b_isOn
552  }};
553
554
555/*
556 * Enter MSCAN sleep mode
557 */
558void mpc5200_mscan_enter_sleep_mode(volatile struct mpc5200_mscan *mscan)
559  {
560
561  /* Control Register 0 --------------------------------------------*/
562  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
563  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
564  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
565  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
566  /*    [03]:TIME        1 : Generate Timestamps                    */
567  /*    [02]:WUPE        1 : WakeUp Enabled                         */
568  /*    [01]:SLPRQ    0->1 : Sleep Mode Request                     */
569  /*    [00]:INITRQ      0 : No init. Mode Request                  */
570  /* select sleep mode */
571  mscan->ctl0 |= (CTL0_SLPRQ);
572
573  /* Control Register 1 --------------------------------------------*/
574  /*    [07]:CANE        0 : MSCAN Module is disabled               */
575  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
576  /*    [05]:LOOPB       0 : No Loopback                            */
577  /*    [04]:LISTEN      0 : Normal Operation                       */
578  /*    [03]:res         0 : reserved                               */
579  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
580  /*    [01]:SLPAK    0->1 : Sleep Mode Acknowledge (rd. only)      */
581  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
582  /* wait for sleep mode acknowledge */
583  while(!(mscan->ctl1 & CTL1_SLPAK));
584
585  return;
586
587  }
588
589
590/*
591 * Exit MSCAN sleep mode
592 */
593void mpc5200_mscan_exit_sleep_mode(volatile struct mpc5200_mscan *mscan)
594  {
595
596  /* Control Register 0 --------------------------------------------*/
597  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
598  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
599  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
600  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
601  /*    [03]:TIME        1 : Generate Timestamps                    */
602  /*    [02]:WUPE        1 : WakeUp Enabled                         */
603  /*    [01]:SLPRQ    0->1 : Sleep Mode Request                     */
604  /*    [00]:INITRQ      0 : No init. Mode Request                  */
605  /* select sleep mode */
606  mscan->ctl0 &= ~(CTL0_SLPRQ);
607
608  /* Control Register 1 --------------------------------------------*/
609  /*    [07]:CANE        0 : MSCAN Module is disabled               */
610  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
611  /*    [05]:LOOPB       0 : No Loopback                            */
612  /*    [04]:LISTEN      0 : Normal Operation                       */
613  /*    [03]:res         0 : reserved                               */
614  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
615  /*    [01]:SLPAK    0->1 : Sleep Mode Acknowledge (rd. only)      */
616  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
617  /* wait for sleep mode acknowledge */
618  while((mscan->ctl1 & CTL1_SLPAK));
619
620  return;
621
622  }
623
624
625/*
626 * Enter MSCAN init mode and disconnect from bus
627 */
628void mpc5200_mscan_enter_init_mode(volatile struct mpc5200_mscan *mscan)
629  {
630
631  /* Control Register 0 --------------------------------------------*/
632  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
633  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
634  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
635  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
636  /*    [03]:TIME        1 : Generate Timestamps                    */
637  /*    [02]:WUPE        0 : WakeUp disabled                        */
638  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
639  /*    [00]:INITRQ   0->1 : Init. Mode Request                     */
640  /* select init mode */
641  mscan->ctl0 |= (CTL0_INITRQ);
642
643  /* Control Register 1 --------------------------------------------*/
644  /*    [07]:CANE        0 : MSCAN Module is disabled               */
645  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
646  /*    [05]:LOOPB       0 : No Loopback                            */
647  /*    [04]:LISTEN      0 : Normal Operation                       */
648  /*    [03]:res         0 : reserved                               */
649  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
650  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
651  /*    [00]:INITAK   0->1 : Init. Mode Acknowledge (rd. only)      */
652  /* wait for init mode acknowledge */
653  while(!(mscan->ctl1 & CTL1_INITAK));
654
655  return;
656
657  }
658
659
660/*
661 * Exit MSCAN init mode
662 */
663void mpc5200_mscan_exit_init_mode(volatile struct mpc5200_mscan *mscan)
664  {
665
666  /* Control Register 0 --------------------------------------------*/
667  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
668  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
669  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
670  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
671  /*    [03]:TIME        1 : Generate Timestamps                    */
672  /*    [02]:WUPE        0 : WakeUp Disabled                        */
673  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
674  /*    [00]:INITRQ   1->0 : Init. Mode Request                     */
675  /* select normal mode */
676  mscan->ctl0 &= ~(CTL0_INITRQ);
677
678  /* Control Register 1 --------------------------------------------*/
679  /*    [07]:CANE        0 : MSCAN Module is disabled               */
680  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
681  /*    [05]:LOOPB       0 : No Loopback                            */
682  /*    [04]:LISTEN      0 : Normal Operation                       */
683  /*    [03]:res         0 : reserved                               */
684  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
685  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
686  /*    [00]:INITAK   1->0 : Init. Mode Acknowledge (rd. only)      */
687  /* wait for normal mode acknowledge */
688  while(mscan->ctl1 & CTL1_INITAK);
689
690  return;
691
692  }
693
694
695/*
696 * MPC5x00 MSCAN wait for sync. with CAN bus
697 */
698void mpc5200_mscan_wait_sync(volatile struct mpc5200_mscan *mscan)
699  {
700
701  /* Control Register 0 --------------------------------------------*/
702  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
703  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
704  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
705  /*    [04]:SYNCH    0->1 : Synchronized, Status Bit (rd. only)    */
706  /*    [03]:TIME        1 : Generate Timestamps                    */
707  /*    [02]:WUPE        0 : WakeUp Disabled                        */
708  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
709  /*    [00]:INITRQ      0 : No init. Mode Request                  */
710  /* wait for MSCAN A_/_B bus synch. */
711
[c9b005a9]712#if 0 /* we don't have a need to wait for sync. */
713  while(!((mscan->ctl0) & CTL0_SYNCH));
714#endif
[ca680bc5]715  return;
716
717  }
718
[c9b005a9]719/* calculate the can clock prescaler value */
720uint8_t prescaler_calculation(uint32_t can_bit_rate, uint32_t can_clock_frq, uint8_t *tq_no) {
721
722/* local variables */
[4a4c7900]723uint8_t presc_val, tq_no_dev_min = 0;
724uint32_t bit_rate, bit_rate_dev, frq_tq, bit_rate_dev_min = 0xFFFFFFFF;
[c9b005a9]725
726/* loop through all values of time quantas */
727for(*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) {
728
729  /* calculate time quanta freq. */
730  frq_tq = *tq_no * can_bit_rate;
731
[4a4c7900]732  /* calculate the optimized prescal. val. */
733  presc_val = (can_clock_frq+frq_tq/2)/frq_tq;
734
735  /* calculate the bitrate */
736  bit_rate = can_clock_frq/(*tq_no * presc_val);
737
738  /* calculate the bitrate deviation */
739  if(can_bit_rate >= bit_rate)
740    {
741    /* calculate the bitrate deviation */
742    bit_rate_dev = can_bit_rate - bit_rate;
743    }
744  else
745    {
746    /* calculate the bitrate deviation */
747    bit_rate_dev = bit_rate - can_bit_rate;
748    }
[c9b005a9]749
750  /* check the deviation freq. */
[4a4c7900]751  if(bit_rate_dev == 0) {
[c9b005a9]752
753    /* return if best match (zero deviation) */
[4a4c7900]754   return (uint8_t)(presc_val);
[c9b005a9]755    }
756  else
757    {
758
[4a4c7900]759    /* check for minimum of bit rate deviation */
760    if(bit_rate_dev < bit_rate_dev_min) {
[c9b005a9]761
762      /* recognize the minimum freq. deviation */
[4a4c7900]763      bit_rate_dev_min = bit_rate_dev;
[c9b005a9]764
765      /* recognize the no. of time quantas */
[4a4c7900]766      tq_no_dev_min = *tq_no;
[c9b005a9]767          }
768        }
769  }
770
[4a4c7900]771  /* get the no of tq's */
772  *tq_no = tq_no_dev_min;
773
774  /* calculate time quanta freq. */
775  frq_tq = *tq_no * can_bit_rate;
776
777  /* return the optimized prescaler value */
778  return (uint8_t)((can_clock_frq+frq_tq/2)/frq_tq);
[c9b005a9]779}
[ca680bc5]780
781/*
782 * MPC5x00 MSCAN set up the bit timing
783 */
[c9b005a9]784void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan, uint32_t can_bit_rate, uint32_t can_clock_frq)
[ca680bc5]785{
786  uint32_t prescale_val = 0;
[c9b005a9]787  uint8_t tq_no, tseg_1, tseg_2, sseg;
788
789  /* get optimized prescaler value */
790  prescale_val = prescaler_calculation(can_bit_rate, can_clock_frq, &tq_no);
791
792  /* get time segment length from time segment table */
793  tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1];
794  tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2];
795  sseg    = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW];
[ca680bc5]796
797  /* Bus Timing Register 0 MSCAN_A/_B ------------------------------*/
798  /*    [07]:SJW1        1 : Synchronization jump width, Bit1       */
799  /*    [06]:SJW0        0 : Synchronization jump width, Bit0       */
800  /*                         SJW = 2 -> 3 Tq clock cycles           */
801  /*    [05]:BRP5        0 : Baud Rate Prescaler, Bit 5             */
802  /*    [04]:BRP4        0 : Baud Rate Prescaler, Bit 4             */
803  /*    [03]:BRP3        0 : Baud Rate Prescaler, Bit 3             */
804  /*    [02]:BRP2        1 : Baud Rate Prescaler, Bit 2             */
805  /*    [01]:BRP1        0 : Baud Rate Prescaler, Bit 1             */
806  /*    [00]:BRP0        1 : Baud Rate Prescaler, Bit 0             */
[c9b005a9]807  mscan->btr0 = (BTR0_SJW(sseg-1) | BTR0_BRP(prescale_val-1));
[ca680bc5]808
809  /* Bus Timing Register 1 MSCAN_A/_B ------------------------------*/
810  /*    [07]:SAMP        0 : One Sample per bit                     */
811  /*    [06]:TSEG22      0 : Time Segment 2, Bit 2                  */
812  /*    [05]:TSEG21      1 : Time Segment 2, Bit 1                  */
813  /*    [04]:TSEG20      0 : Time Segment 2, Bit 0                  */
814  /*                         -> PHASE_SEG2 = 3 Tq                   */
815  /*    [03]:TSEG13      0 : Time Segment 1, Bit 3                  */
816  /*    [02]:TSEG12      1 : Time Segment 1, Bit 2                  */
817  /*    [01]:TSEG11      1 : Time Segment 1, Bit 1                  */
818  /*    [00]:TSEG10      0 : Time Segment 1, Bit 0                  */
[c9b005a9]819  mscan->btr1 =  (BTR1_TSEG_22_20(tseg_2-1) | BTR1_TSEG_13_10(tseg_1-1));
[ca680bc5]820
821  return;
822
823  }
824
825
826/*
827 * MPC5x00 MSCAN perform settings in init mode
828 */
829void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *mscan)
830  {
[c9b005a9]831
832  /* perform all can bit time settings */
833  mpc5200_mscan_perform_bit_time_settings(mscan,CAN_BIT_RATE,IPB_CLOCK);
834
[ca680bc5]835  /* Control Register 1 --------------------------------------------*/
836  /*    [07]:CANE        0 : MSCAN Module is disabled               */
837  /*    [06]:CLKSRC      0 : Clock Source -> IPB_CLOCK (bsp.h)      */
838  /*    [05]:LOOPB       0 : No Loopback                            */
839  /*    [04]:LISTEN      0 : Normal Operation                       */
840  /*    [03]:res         0 : reserved                               */
841  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
842  /*    [01]:SLPAK    1->0 : Sleep Mode Acknowledge (rd. only)      */
843  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
844  /* Set CLK source, disable loopback & listen-only mode */
845#ifndef MSCAN_LOOPBACK
846  mscan->ctl1 &= ~(CTL1_LISTEN | CTL1_LOOPB | CTL1_CLKSRC);
847#else
848  mscan->ctl1 &= ~(CTL1_LISTEN | CTL1_CLKSRC);
849  mscan->ctl1 |=  (CTL1_LOOPB);
850#endif
851
852  /* IPB clock                  -> IPB_CLOCK (bsp.h)                                                    */
853  /* bitrate                    -> CAN_BIT_RATE (mscan.h)                                               */
854  /* Max. no of Tq              -> CAN_MAX_NO_OF_TQ (mscan.h)                                           */
855  /* Prescaler value            -> prescale_val = ROUND_UP(IPB_CLOCK/(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) */
856  /* SYNC_SEG                   ->  1 tq                                                                */
857  /* time segment 1             -> 16 tq (PROP_SEG+PHASE_SEG), CAN_MAX_NO_OF_TQ_TSEG1 = 15 (mscan.h)    */
858  /* time segment 2             ->  8 tq (PHASE_SEG2)        , CAN_MAX_NO_OF_TQ_TSEG2 =  7 (mscan.h)    */
859  /* SJW                        ->  3 (fixed 0...3)          , CAN_MAX_NO_OF_TQ_SJW   =  2 (mscan.h)    */
860
861  /* ID Acceptance Control MSCAN_A/_B ------------------------------*/
862  /*    [07]:res.        0 : reserved                               */
863  /*    [06]:res.        0 : reserved                               */
864  /*    [05]:IDAM1       0 : ID acceptance control, Bit1            */
865  /*    [04]:IDAM0       1 : ID acceptance control, Bit0            */
866  /*                         -> filter 16 bit mode                  */
867  /*    [03]:res.        0 : reserved                               */
868  /*    [02]:IDHIT2      0 : ID acceptance hit indication, Bit 2    */
869  /*    [01]:IDHIT1      0 : ID acceptance hit indication, Bit 1    */
870  /*    [00]:IDHIT0      0 : ID acceptance hit indication, Bit 0    */
871  mscan->idac &= ~(IDAC_IDAM1);
872  mscan->idac |=  (IDAC_IDAM0);
873
[c9b005a9]874  /* initialize rx filter masks (16 bit) */
875  mscan->idmr0  = SET_IDMR0(0x07FF);
876  mscan->idmr1  = SET_IDMR1(0x07FF);
877  mscan->idmr2  = SET_IDMR2(0x07FF);
878  mscan->idmr3  = SET_IDMR3(0x07FF);
879  mscan->idmr4  = SET_IDMR4(0x07FF);
880  mscan->idmr5  = SET_IDMR5(0x07FF);
881  mscan->idmr6  = SET_IDMR6(0x07FF);
882  mscan->idmr7  = SET_IDMR7(0x07FF);
[ca680bc5]883
884  /* Control Register 1 --------------------------------------------*/
885  /*    [07]:CANE     0->1 : MSCAN Module is enabled                */
886  /*    [06]:CLKSRC      1 : Clock Source -> IPB_CLOCK (bsp.h)      */
887  /*    [05]:LOOPB       0 : No Loopback                            */
888  /*    [04]:LISTEN      0 : Normal Operation                       */
889  /*    [03]:res         0 : reserved                               */
890  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
891  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
892  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
893  /* enable MSCAN A_/_B */
894  mscan->ctl1 |= (CTL1_CANE);
895
896  return;
897
898  }
899
900
901/*
902 * MPC5x00 MSCAN perform settings in normal mode
903 */
904void mpc5200_mscan_perform_normal_mode_settings(volatile struct mpc5200_mscan *mscan)
905  {
906
907  /* Control Register 0 --------------------------------------------*/
908  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
909  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
910  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
911  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
912  /*    [03]:TIME        1 : Generate Timestamps                    */
913  /*    [02]:WUPE        0 : WakeUp Disabled                        */
914  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
915  /*    [00]:INITRQ      0 : No init. Mode Request                  */
916  /* Disable wait mode, enable timestamps */
917  mscan->ctl0 &= ~(CTL0_CSWAI);
918  mscan->ctl0 |=  (CTL0_TIME);
919
920  return;
921
922  }
923
924rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor, uint8_t mode)
925  {
926  struct mscan_channel_info *chan = NULL;
927  volatile struct mpc5200_mscan *mscan     = NULL;
928
929  switch(minor)
930    {
931
932    case MSCAN_A:
933    case MSCAN_B:
934      chan  = &chan_info[minor];
935      mscan = chan->regs;
936      break;
937
938    default:
939      return RTEMS_UNSATISFIED;
940      break;
941    }
942
943  if(chan->mode == mode)
944    return RTEMS_SUCCESSFUL;
945
946  switch(mode)
947    {
948
[c9b005a9]949    case MSCAN_INIT_NORMAL_MODE:
950      /* if not already set enter init mode */
951          mpc5200_mscan_enter_init_mode(mscan);
952          /* perform initialization which has to be done in init mode */
953      mpc5200_mscan_perform_init_mode_settings(mscan);
954      break;
955
[ca680bc5]956    case MSCAN_NORMAL_MODE:
957      /* if not already set enter init mode */
958      mpc5200_mscan_enter_init_mode(mscan);
959
960      if((chan->mode) == MSCAN_INITIALIZED_MODE)
[c9b005a9]961        {
962
[ca680bc5]963        /* perform initialization which has to be done in init mode */
964        mpc5200_mscan_perform_init_mode_settings(mscan);
[c9b005a9]965            }
966
967      if((chan->mode) == MSCAN_SLEEP_MODE)
968        {
969
[ca680bc5]970        /* exit sleep mode */
971            mpc5200_mscan_exit_sleep_mode(mscan);
[c9b005a9]972            }
[ca680bc5]973
[c9b005a9]974      /* exit init mode */
[ca680bc5]975      mpc5200_mscan_exit_init_mode(mscan);
976      /* enable ints. */
977      mpc5200_mscan_int_enable(mscan);
978      /* wait for bus sync. */
979      mpc5200_mscan_wait_sync(mscan);
980      break;
981
982    case MSCAN_SLEEP_MODE:
[c9b005a9]983      /* disable ints. */
[ca680bc5]984      mpc5200_mscan_int_disable(mscan);
985      /* exit sleep mode */
986          mpc5200_mscan_enter_sleep_mode(mscan);
987      break;
988
989    default:
990      return RTEMS_UNSATISFIED;
991      break;
992
993    }
994
995  /* set new channel mode */
996  chan->mode = mode;
997
998  return RTEMS_SUCCESSFUL;
999
1000  }
1001
1002
1003/*
1004 * initialization of channel info.
1005 */
1006rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtems_device_minor_number minor)
1007  {
1008  rtems_status_code status;
1009  struct mscan_channel_info *chan = &chan_info[minor];
1010
[c9b005a9]1011
[ca680bc5]1012  /* set registers according to MSCAN channel information */
1013  switch(minor)
1014    {
1015
1016    case MSCAN_A:
1017      chan->rx_qname = rtems_build_name ('C', 'N', 'A', 'Q');
[c9b005a9]1018      chan->tx_rb_sname = rtems_build_name ('C', 'N', 'A', 'S');
[ca680bc5]1019
1020      /* register RTEMS device names for MSCAN A */
[c9b005a9]1021      if((status = rtems_io_register_name (MSCAN_A_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
1022            return status;
1023
1024      /* register RTEMS device names for MSCAN 0 */
1025      if((status = rtems_io_register_name (MSCAN_0_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
[ca680bc5]1026            return status;
1027
[c9b005a9]1028          /* allocate the space for MSCAN A tx ring buffer */
1029          if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
1030            {
1031        chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1032            }
1033          else
1034            {
1035                return RTEMS_UNSATISFIED;
1036            }
[ca680bc5]1037      break;
1038
1039    case MSCAN_B:
1040          chan->rx_qname = rtems_build_name ('C', 'N', 'B', 'Q');
[c9b005a9]1041      chan->tx_rb_sname = rtems_build_name ('C', 'N', 'B', 'S');
[ca680bc5]1042
1043          /* register RTEMS device names for MSCAN B */
1044          if((status = rtems_io_register_name (MSCAN_B_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
1045            return status;
1046
[c9b005a9]1047      /* register RTEMS device names for MSCAN 1 */
1048          if((status = rtems_io_register_name (MSCAN_1_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
1049            return status;
1050
1051      /* allocate the space for MSCAN B tx ring buffer */
1052          if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
1053            {
1054                chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1055            }
1056          else
1057            {
1058                return RTEMS_UNSATISFIED;
1059            }
[ca680bc5]1060      break;
1061
1062    default:
1063      return RTEMS_UNSATISFIED;
1064      break;
1065    }
1066
[c9b005a9]1067  /* create RTEMS rx message queue */
1068  status = rtems_message_queue_create(chan->rx_qname,
1069                                             (uint32_t) NO_OF_MSCAN_RX_BUFF,
1070                                             (uint32_t) MSCAN_MESSAGE_SIZE(sizeof(struct can_message)),
1071                                             (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
1072                                             (rtems_id *)&(chan->rx_qid));
1073
1074  /* create counting RTEMS tx ring buffer semaphore */
1075  status = rtems_semaphore_create(chan->tx_rb_sname,
1076                                 (uint32_t)(NO_OF_MSCAN_TX_BUFF),
1077                                  RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
1078                                 (rtems_task_priority)0,
1079                                 (rtems_id *)&(chan->tx_rb_sid));
1080
1081  /* Set up interrupts */
[ca680bc5]1082  if(!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor])))
1083    rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %d\n", minor);
1084
1085  /* basic setup for channel info. struct. */
[c9b005a9]1086  chan->regs           = (struct mpc5200_mscan *)&(mpc5200.mscan[minor]);
1087  chan->int_rx_err     = 0;
1088  chan->id_extended    = FALSE;
1089  chan->mode           = MSCAN_INITIALIZED_MODE;
1090  chan->tx_buf_no      = NO_OF_MSCAN_TX_BUFF;
[ca680bc5]1091
1092  return status;
1093
1094  }
1095
1096
1097/*
1098 * MPC5x00 MSCAN device initialization
1099 */
1100rtems_device_driver mscan_initialize(rtems_device_major_number major,
1101                                     rtems_device_minor_number minor,
1102                                     void *arg
1103                                    )
1104  {
1105  rtems_status_code status;
1106
1107  /* Initialization requested via RTEMS */
1108  if((status = mscan_channel_initialize(major,MSCAN_A)) != RTEMS_SUCCESSFUL)
1109    rtems_fatal_error_occurred(status);
1110
1111  if((status = mscan_channel_initialize(major,MSCAN_B)) != RTEMS_SUCCESSFUL)
1112    rtems_fatal_error_occurred(status);
1113
[c9b005a9]1114  if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
[ca680bc5]1115    rtems_fatal_error_occurred(status);
1116
[c9b005a9]1117  if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
[ca680bc5]1118    rtems_fatal_error_occurred(status);
1119
1120  return status;
1121
1122  }
1123
1124
1125/*
1126 * MPC5x00 MSCAN device open
1127 */
1128rtems_device_driver mscan_open( rtems_device_major_number major,
1129                                 rtems_device_minor_number minor,
1130                                 void * arg
1131                               )
1132  {
[c9b005a9]1133  rtems_status_code status = RTEMS_SUCCESSFUL;
[ca680bc5]1134  struct mscan_channel_info *chan = NULL;
1135
1136  switch(minor)
1137    {
1138
1139    case MSCAN_A:
1140    case MSCAN_B:
1141      chan = &chan_info[minor];
1142      break;
1143
1144    default:
1145      return RTEMS_UNSATISFIED;
1146      break;
1147    }
1148
[c9b005a9]1149
1150  /* check mode */
1151  if((chan->mode) == MSCAN_SLEEP_MODE)
1152    {
1153
1154    /* if not already set enter init mode */
1155    status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1156    }
[ca680bc5]1157
1158  return status;
1159
1160  }
1161
1162
1163/*
1164 * MPC5x00 MSCAN device close
1165 */
1166rtems_device_driver mscan_close( rtems_device_major_number major,
1167                                  rtems_device_minor_number minor,
1168                                  void * arg
1169                                )
1170  {
1171  rtems_status_code status;
1172  struct mscan_channel_info *chan = NULL;
1173
1174  switch(minor)
1175    {
1176
1177    case MSCAN_A:
1178    case MSCAN_B:
1179          chan = &chan_info[minor];
1180      break;
1181
1182    default:
1183      return RTEMS_UNSATISFIED;
1184      break;
1185    }
1186
1187  /* enter deep sleep mode */
1188  status = mpc5200_mscan_set_mode(minor, MSCAN_SLEEP_MODE);
1189
1190  return status;
1191
1192  }
1193
1194
1195/*
1196 * MPC5x00 MSCAN device read
1197 */
1198rtems_device_driver mscan_read( rtems_device_major_number major,
1199                                 rtems_device_minor_number minor,
1200                                 void * arg
1201                               )
1202  {
1203  rtems_status_code status;
1204  uint32_t          message_size = 0;
1205  rtems_libio_rw_args_t     *parms       = (rtems_libio_rw_args_t *)arg;
1206  struct mscan_rx_parms     *rx_parms    = (struct mscan_rx_parms *)(parms->buffer);
1207  struct can_message        *rx_mess     = (struct can_message *)(rx_parms->rx_mess);
1208  struct mscan_channel_info *chan        = NULL;
1209
1210  switch(minor)
1211    {
1212
1213    case MSCAN_A:
1214    case MSCAN_B:
1215          chan = &chan_info[minor];
1216      break;
1217
1218    default:
1219      return RTEMS_UNSATISFIED;
1220      break;
1221    }
1222
[c9b005a9]1223
1224  /* end init mode if it is first read */
1225  if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
1226    {
1227
1228    /* if not already set enter init mode */
1229    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1230    }
1231
[ca680bc5]1232  if((status = rtems_message_queue_receive(chan->rx_qid,
1233                                          (void *)(rx_mess),
1234                                          (uint32_t *)&message_size,
1235                                          (uint32_t)(rx_parms->rx_flags),
1236                                          (rtems_interval)(rx_parms->rx_timeout)))
1237                                          != RTEMS_SUCCESSFUL)
1238    {
1239
1240    parms->bytes_moved = 0;
1241
1242    }
1243  else
1244    {
1245
1246    parms->bytes_moved = sizeof(struct can_message);
1247
1248    }
1249
1250  return status;
1251
1252  }
1253
1254
1255/*
1256 * MPC5x00 MSCAN device write
1257 */
1258rtems_device_driver mscan_write( rtems_device_major_number major,
1259                                 rtems_device_minor_number minor,
1260                                 void * arg
1261                                )
1262  {
[c9b005a9]1263  rtems_status_code status;
1264  rtems_libio_rw_args_t         *parms       = (rtems_libio_rw_args_t *)arg;
1265  struct mscan_tx_parms         *tx_parms    = (struct mscan_tx_parms *)(parms->buffer);
1266  struct can_message            *tx_mess     = (struct can_message *)(tx_parms->tx_mess);
1267  struct mscan_channel_info     *chan        = NULL;
1268  mscan_handle                  *mscan_hdl   = NULL;
1269  volatile struct mpc5200_mscan *mscan       = NULL;
[ca680bc5]1270
1271  switch(minor)
1272    {
1273    case MSCAN_A:
1274    case MSCAN_B:
1275          chan      = &chan_info[minor];
1276      mscan_hdl = mpc5200_mscan_irq_data[minor].handle;
1277      mscan     = chan->regs;
1278      break;
1279
1280    default:
1281      return RTEMS_UNSATISFIED;
1282      break;
1283    }
1284
[c9b005a9]1285  /* end init mode if it is first write */
1286  if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
[ca680bc5]1287    {
1288
[c9b005a9]1289    /* if not already set enter init mode */
1290    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
[ca680bc5]1291    }
1292
[c9b005a9]1293  /* preset moved bytes */
1294  parms->bytes_moved = 0;
[ca680bc5]1295
[c9b005a9]1296  /* obtain counting semaphore of tx ring buffer */
1297  if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
1298                                       RTEMS_NO_WAIT,
1299                                          (rtems_interval)0))
1300                                        == RTEMS_SUCCESSFUL)
[ca680bc5]1301    {
1302
[c9b005a9]1303    /* append the TOUCAN tx_id to the mess. due to interrupt handling */
1304        tx_mess->toucan_tx_id = tx_parms->tx_id;
[ca680bc5]1305
[c9b005a9]1306    /* fill the tx ring buffer with the message */
1307    fill_tx_buffer(chan, tx_mess);
[ca680bc5]1308
[c9b005a9]1309    /* enable message buffer specific interrupt */
1310    mscan->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2);
[ca680bc5]1311
[c9b005a9]1312    /* calculate moved bytes */
1313    parms->bytes_moved = (tx_mess->mess_len) & 0x000F;
[ca680bc5]1314
1315    }
1316
[c9b005a9]1317  return status;
[ca680bc5]1318
1319  }
1320
1321
1322/*
1323 * MPC5x00 MSCAN device control
1324 */
1325rtems_device_driver mscan_control( rtems_device_major_number major,
1326                                    rtems_device_minor_number minor,
1327                                    void * arg
1328                                  )
1329  {
[c9b005a9]1330  rtems_status_code status;
[ca680bc5]1331  uint16_t tx_id;
[c9b005a9]1332  rtems_libio_ioctl_args_t      *parms       = (rtems_libio_ioctl_args_t *)arg;
1333  struct mscan_ctrl_parms       *ctrl_parms  = (struct mscan_ctrl_parms *)(parms->buffer);
1334  struct mscan_channel_info     *chan        = NULL;
1335  mscan_handle                  *mscan_hdl   = NULL;
1336  volatile struct mpc5200_mscan *mscan       = NULL;
1337  uint8_t                       tx_buf_count = 0;
[ca680bc5]1338
1339  switch(minor)
1340    {
1341
1342    case MSCAN_A:
1343    case MSCAN_B:
1344          chan = &chan_info[minor];
1345      mscan_hdl  = mpc5200_mscan_irq_data[minor].handle;
1346      mscan = chan->regs;
1347      break;
1348
1349    default:
1350      return RTEMS_UNSATISFIED;
1351      break;
1352    }
1353
1354  switch(parms->command)
1355    {
1356
1357      /* TOUCAN callback initialization for MSCAN */
1358    case TOUCAN_MSCAN_INIT:
1359      mscan_hdl->toucan_callback = ctrl_parms->toucan_cb_fnc;
1360      break;
1361
1362    /* set rx buffer ID */
1363    case MSCAN_SET_RX_ID:
1364
1365      /* enter init mode */
1366      mpc5200_mscan_enter_init_mode(mscan);
1367
1368      switch(ctrl_parms->ctrl_reg_no)
1369        {
1370
1371        case RX_BUFFER_0:
1372          mscan->idar0  = SET_IDR0(ctrl_parms->ctrl_id);
1373          mscan->idar1  = SET_IDR1(ctrl_parms->ctrl_id);
1374          break;
1375
1376        case RX_BUFFER_1:
1377          mscan->idar2  = SET_IDR2(ctrl_parms->ctrl_id);
1378          mscan->idar3  = SET_IDR3(ctrl_parms->ctrl_id);
1379          break;
1380
1381        case RX_BUFFER_2:
1382          mscan->idar4  = SET_IDR4(ctrl_parms->ctrl_id);
1383          mscan->idar5  = SET_IDR5(ctrl_parms->ctrl_id);
1384          break;
1385
1386        case RX_BUFFER_3:
1387          mscan->idar6  = SET_IDR6(ctrl_parms->ctrl_id);
1388          mscan->idar7  = SET_IDR7(ctrl_parms->ctrl_id);
1389          break;
1390
1391        default:
1392        break;
1393
1394        }
1395
1396      /* exit init mode and perform further initialization which is required in the normal mode */
1397      mpc5200_mscan_exit_init_mode(mscan);
1398
1399      /* enable ints. */
1400      mpc5200_mscan_int_enable(mscan);
1401
1402      /* wait for bus sync. */
1403      mpc5200_mscan_wait_sync(mscan);
1404
1405      return RTEMS_SUCCESSFUL;
1406      break;
1407
1408    /* get rx buffer ID */
1409    case MSCAN_GET_RX_ID:
1410
1411      switch(ctrl_parms->ctrl_reg_no)
1412            {
1413
1414        case RX_BUFFER_0:
1415          ctrl_parms->ctrl_id = GET_IDR0(mscan->idar0) | GET_IDR1(mscan->idar1);
1416          break;
1417
1418        case RX_BUFFER_1:
1419          ctrl_parms->ctrl_id = GET_IDR2(mscan->idar2) | GET_IDR3(mscan->idar3);
1420          break;
1421
1422        case RX_BUFFER_2:
1423          ctrl_parms->ctrl_id = GET_IDR4(mscan->idar4) | GET_IDR5(mscan->idar5);
1424          break;
1425
1426        case RX_BUFFER_3:
1427          ctrl_parms->ctrl_id = GET_IDR6(mscan->idar6) | GET_IDR7(mscan->idar7);
1428          break;
1429
1430        default:
1431        break;
1432
1433        }
1434
1435      break;
1436
1437    /* set rx buffer ID mask */
1438    case MSCAN_SET_RX_ID_MASK:
1439
1440      /* enter init mode */
1441      mpc5200_mscan_enter_init_mode(mscan);
1442
1443      switch(ctrl_parms->ctrl_reg_no)
1444        {
1445
1446        case RX_BUFFER_0:
[c9b005a9]1447          mscan->idmr0  = SET_IDMR0(ctrl_parms->ctrl_id_mask);
1448          mscan->idmr1  = SET_IDMR1(ctrl_parms->ctrl_id_mask);
[ca680bc5]1449          break;
1450
1451        case RX_BUFFER_1:
[c9b005a9]1452          mscan->idmr2  = SET_IDMR2(ctrl_parms->ctrl_id_mask);
1453          mscan->idmr3  = SET_IDMR3(ctrl_parms->ctrl_id_mask);
[ca680bc5]1454          break;
1455
1456        case RX_BUFFER_2:
[c9b005a9]1457          mscan->idmr4  = SET_IDMR4(ctrl_parms->ctrl_id_mask);
1458          mscan->idmr5  = SET_IDMR5(ctrl_parms->ctrl_id_mask);
[ca680bc5]1459          break;
1460
1461        case RX_BUFFER_3:
[c9b005a9]1462          mscan->idmr6  = SET_IDMR6(ctrl_parms->ctrl_id_mask);
1463          mscan->idmr7  = SET_IDMR7(ctrl_parms->ctrl_id_mask);
[ca680bc5]1464          break;
1465
1466        default:
1467        break;
1468
1469        }
1470
1471      /* exit init mode and perform further initialization which is required in the normal mode */
1472      mpc5200_mscan_exit_init_mode(mscan);
1473
1474      /* enable ints. */
1475      mpc5200_mscan_int_enable(mscan);
1476
1477      /* wait for bus sync. */
1478      mpc5200_mscan_wait_sync(mscan);
1479
1480      break;
1481
1482    /* get rx buffer ID mask */
1483    case MSCAN_GET_RX_ID_MASK:
1484
1485      switch(ctrl_parms->ctrl_reg_no)
1486        {
1487
1488        case RX_BUFFER_0:
[c9b005a9]1489          ctrl_parms->ctrl_id_mask = GET_IDMR0(mscan->idmr0) | GET_IDMR1(mscan->idmr1);
[ca680bc5]1490          break;
1491
1492        case RX_BUFFER_1:
[c9b005a9]1493          ctrl_parms->ctrl_id_mask = GET_IDMR2(mscan->idmr2) | GET_IDMR3(mscan->idmr3);
[ca680bc5]1494          break;
1495
1496        case RX_BUFFER_2:
[c9b005a9]1497          ctrl_parms->ctrl_id_mask = GET_IDMR4(mscan->idmr4) | GET_IDMR5(mscan->idmr5);
[ca680bc5]1498          break;
1499
1500        case RX_BUFFER_3:
[c9b005a9]1501          ctrl_parms->ctrl_id_mask = GET_IDMR6(mscan->idmr6) | GET_IDMR7(mscan->idmr7);
[ca680bc5]1502          break;
1503
1504        default:
1505        break;
1506
1507        }
1508
1509    /* set tx buffer ID */
1510    case MSCAN_SET_TX_ID:
1511
1512      /* check for availability of tx buffer */
1513      if(!((mscan->tflg) & (uint8_t)(ctrl_parms->ctrl_reg_no)))
1514        {
1515
1516        /* do abort tx buf. request */
1517        mscan->tarq = (uint8_t)(ctrl_parms->ctrl_reg_no);
1518
1519        /* wait for abort tx buf. ack. */
1520        while((mscan->taak) & (uint8_t)(ctrl_parms->ctrl_reg_no));
1521
1522        }
1523
1524      /* select tx buf. */
1525      mscan->bsel   = (uint8_t)(ctrl_parms->ctrl_reg_no);
1526
1527      /* set the tx id of selected buf. */
1528      tx_id = ctrl_parms->ctrl_id;
1529      mscan->txidr0 = SET_IDR0(tx_id);
1530      mscan->txidr1 = SET_IDR1(tx_id);
1531      mscan->txidr2 = 0;
1532      mscan->txidr3 = 0;
1533
1534      break;
1535
1536    /* get tx buffer ID */
1537    case MSCAN_GET_TX_ID:
1538
1539      /* select tx buf. */
1540      mscan->bsel   = (uint8_t)(ctrl_parms->ctrl_reg_no);
1541
1542      /* get tx id. of selected buf. */
1543      ctrl_parms->ctrl_id = GET_IDR0(mscan->txidr0) | GET_IDR1(mscan->txidr1);
1544
1545      break;
1546
[c9b005a9]1547    /* set can bitrate */
1548    case MSCAN_SET_BAUDRATE:
1549
1550      /* check bitrate settings */
1551      if(((ctrl_parms->ctrl_can_bitrate) >= CAN_BIT_RATE_MIN) && ((ctrl_parms->ctrl_can_bitrate) <= CAN_BIT_RATE_MAX)) {
1552
1553        /* enter init mode */
1554        mpc5200_mscan_enter_init_mode(mscan);
1555
1556        /* perform all can bit time settings */
1557        mpc5200_mscan_perform_bit_time_settings(mscan,(uint32_t)(ctrl_parms->ctrl_can_bitrate),IPB_CLOCK);
1558
1559        /* exit init mode and perform further initialization which is required in the normal mode */
1560        mpc5200_mscan_exit_init_mode(mscan);
1561
1562        /* enable ints. */
1563        mpc5200_mscan_int_enable(mscan);
1564
1565        /* wait for bus sync. */
1566        mpc5200_mscan_wait_sync(mscan);
1567
1568            return RTEMS_SUCCESSFUL;
1569            }
1570          else {
1571
1572             return RTEMS_UNSATISFIED;
1573             }
1574
1575      break;
1576
1577    case SET_TX_BUF_NO:
1578
1579      /* check for different settings of tx ring buffer */
1580      if((tx_buf_count = chan->tx_buf_no) != (uint8_t)(ctrl_parms->ctrl_tx_buf_no))
1581        {
1582
1583        /* preset the channel specific no of messages in the tx ring buffer */
1584        tx_buf_count = chan->tx_buf_no;
1585
1586        /* try to obtain all of the tx ring buffers */
1587        while(tx_buf_count > 0)
1588          {
1589
1590          /* obtain semaphore of all tx ring buffers */
1591                  if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
1592                                                           RTEMS_WAIT,
1593                                                          (rtems_interval)10))
1594                                                == RTEMS_SUCCESSFUL)
1595                {
1596
1597                    tx_buf_count--;
1598
1599                }
1600
1601          }
1602
1603        /* free the former tx ring buffer */
1604        free((void *)chan->tx_ring_buf.buf_ptr);
1605
1606        /* allocate the tx ring buffer with new size */
1607            if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*((uint8_t)(ctrl_parms->ctrl_tx_buf_no)+1))) != NULL)
1608              {
1609                  chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1610              }
1611            else
1612              {
1613                  return RTEMS_UNSATISFIED;
1614              }
1615
1616        /* set the new amount of tx buffers */
1617        chan->tx_buf_no =  (uint8_t)(ctrl_parms->ctrl_tx_buf_no);
1618
1619        /* release the semaphore of all tx ring buffers */
1620        while(tx_buf_count < chan->tx_buf_no)
1621                  {
1622
1623                  /* obtain semaphore of all tx ring buffers */
1624              rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
1625
1626                  tx_buf_count++;
1627
1628                  }
1629
1630            }
1631          else
1632            {
1633
1634        return RTEMS_SUCCESSFUL;
1635
1636            }
1637      break;
1638
[ca680bc5]1639    default:
1640      break;
1641
1642    }
1643
1644  return RTEMS_SUCCESSFUL;
1645
1646  }
1647
Note: See TracBrowser for help on using the repository browser.