Back to home page

LXR

 
 

    


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

0001 /*
0002  * This file contains the M360 SPI driver
0003  */
0004 
0005 /*
0006  * Copyright (c) 2008 Embedded Brains GmbH. All rights reserved.
0007  *
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 <stdlib.h>
0015 #include <bsp.h>
0016 #include <rtems/m68k/m68360.h>
0017 #include <rtems/m68k/m360_spi.h>
0018 #include <rtems/error.h>
0019 #include <rtems/bspIo.h>
0020 #include <errno.h>
0021 #include <rtems/libi2c.h>
0022 
0023 #undef DEBUG
0024 static m360_spi_softc_t *m360_spi_softc_ptr;
0025 /*
0026  * this is a dummy receive buffer for sequences,
0027  * where only send data are available
0028  */
0029 uint8_t m360_spi_dummy_rxbuf[2];
0030 /*=========================================================================*\
0031 | Function:                                                                 |
0032 \*-------------------------------------------------------------------------*/
0033 static rtems_status_code m360_spi_baud_to_mode
0034 (
0035 /*-------------------------------------------------------------------------*\
0036 | Purpose:                                                                  |
0037 |   determine proper divider value                                          |
0038 +---------------------------------------------------------------------------+
0039 | Input Parameters:                                                         |
0040 \*-------------------------------------------------------------------------*/
0041  uint32_t baudrate,                      /* desired baudrate               */
0042  uint32_t *spimode                       /* result value                   */
0043 )
0044 /*-------------------------------------------------------------------------*\
0045 | Return Value:                                                             |
0046 |    o = ok or error code                                                   |
0047 \*=========================================================================*/
0048 {
0049   uint32_t divider;
0050   uint16_t tmpmode = 0;
0051   /*
0052    * determine clock divider and DIV16 bit
0053    */
0054   divider = m360_clock_rate/baudrate;
0055   if (divider > 64) {
0056     tmpmode = M360_SPMODE_DIV16;
0057     divider /= 16;
0058   }
0059   if ((divider <  1) ||
0060       (divider > 64)) {
0061     return RTEMS_INVALID_NUMBER;
0062   }
0063   else {
0064     tmpmode |= M360_SPMODE_PM(divider/4-1);
0065   }
0066   *spimode = tmpmode;
0067   return RTEMS_SUCCESSFUL;
0068 }
0069 
0070 /*=========================================================================*\
0071 | Function:                                                                 |
0072 \*-------------------------------------------------------------------------*/
0073 static rtems_status_code m360_spi_char_mode
0074 (
0075 /*-------------------------------------------------------------------------*\
0076 | Purpose:                                                                  |
0077 |   determine proper value for character size                               |
0078 +---------------------------------------------------------------------------+
0079 | Input Parameters:                                                         |
0080 \*-------------------------------------------------------------------------*/
0081  m360_spi_softc_t *softc_ptr,            /* handle                         */
0082  uint32_t bits_per_char,                 /* bits per character             */
0083  bool     lsb_first,                     /* TRUE: send LSB first           */
0084  uint16_t *spimode                       /* result value                   */
0085 )
0086 /*-------------------------------------------------------------------------*\
0087 | Return Value:                                                             |
0088 |    o = ok or error code                                                   |
0089 \*=========================================================================*/
0090 {
0091   uint16_t tmpmode;
0092 
0093   /*
0094    * calculate data format
0095    */
0096   if ((bits_per_char >= 4) &&
0097       (bits_per_char <= 16)) {
0098     tmpmode = M360_SPMODE_CLEN( bits_per_char-1);
0099   }
0100   else {
0101     return RTEMS_INVALID_NUMBER;
0102   }
0103 
0104   *spimode = tmpmode;
0105   return 0;
0106 }
0107 
0108 /*=========================================================================*\
0109 | Function:                                                                 |
0110 \*-------------------------------------------------------------------------*/
0111 static int m360_spi_wait
0112 (
0113 /*-------------------------------------------------------------------------*\
0114 | Purpose:                                                                  |
0115 |   wait for spi to become idle                                             |
0116 +---------------------------------------------------------------------------+
0117 | Input Parameters:                                                         |
0118 \*-------------------------------------------------------------------------*/
0119  m360_spi_softc_t    *softc_ptr           /* handle              */
0120 )
0121 /*-------------------------------------------------------------------------*\
0122 | Return Value:                                                             |
0123 |    o = ok or error code                                                   |
0124 \*=========================================================================*/
0125 {
0126   uint16_t act_status;
0127   rtems_status_code rc;
0128   uint32_t tout;
0129 
0130 #if defined(DEBUG)
0131   printk("m360_spi_wait called... ");
0132 #endif
0133   if (softc_ptr->initialized) {
0134     /*
0135      * allow interrupts, when receiver is not empty
0136      */
0137     m360.spim = (M360_SPIE_TXE | M360_SPIE_TXB |
0138          M360_SPIE_BSY | M360_SPIE_MME);
0139 
0140     rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,
0141                 RTEMS_WAIT,
0142                 RTEMS_NO_TIMEOUT);
0143     if (rc != RTEMS_SUCCESSFUL) {
0144       return rc;
0145     }
0146   }
0147   else {
0148     tout = 0;
0149     do {
0150       if (tout++ > 1000000) {
0151 #if defined(DEBUG)
0152     printk("... exit with RTEMS_TIMEOUT\r\n");
0153 #endif
0154     return RTEMS_TIMEOUT;
0155       }
0156       /*
0157        * wait for SPI to terminate
0158        */
0159     } while (!(m360.spie & M360_SPIE_TXB));
0160   }
0161 
0162   act_status = m360.spie;
0163   if ((act_status  & (M360_SPIE_TXE | M360_SPIE_TXB |
0164               M360_SPIE_BSY | M360_SPIE_MME))!= M360_SPIE_TXB) {
0165 #if defined(DEBUG)
0166     printk("... exit with RTEMS_IO_ERROR,"
0167        "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n",
0168        act_status,status_mask,desired_status);
0169 #endif
0170     return RTEMS_IO_ERROR;
0171   }
0172 #if defined(DEBUG)
0173     printk("... exit OK\r\n");
0174 #endif
0175   return RTEMS_SUCCESSFUL;
0176 }
0177 
0178 /*=========================================================================*\
0179 | Function:                                                                 |
0180 \*-------------------------------------------------------------------------*/
0181 static rtems_isr m360_spi_irq_handler
0182 (
0183 /*-------------------------------------------------------------------------*\
0184 | Purpose:                                                                  |
0185 |   handle interrupts                                                       |
0186 +---------------------------------------------------------------------------+
0187 | Input Parameters:                                                         |
0188 \*-------------------------------------------------------------------------*/
0189  rtems_vector_number v                          /* vector number           */
0190 )
0191 /*-------------------------------------------------------------------------*\
0192 | Return Value:                                                             |
0193 |    <none>                                                                 |
0194 \*=========================================================================*/
0195 {
0196   m360_spi_softc_t *softc_ptr = m360_spi_softc_ptr;
0197 
0198   /*
0199    * disable interrupt mask
0200    */
0201   m360.spim = 0;
0202   if (softc_ptr->initialized) {
0203     rtems_semaphore_release(softc_ptr->irq_sema_id);
0204   }
0205 }
0206 
0207 /*=========================================================================*\
0208 | Function:                                                                 |
0209 \*-------------------------------------------------------------------------*/
0210 static void m360_spi_install_irq_handler
0211 (
0212 /*-------------------------------------------------------------------------*\
0213 | Purpose:                                                                  |
0214 |   (un-)install the interrupt handler                                      |
0215 +---------------------------------------------------------------------------+
0216 | Input Parameters:                                                         |
0217 \*-------------------------------------------------------------------------*/
0218  m360_spi_softc_t *softc_ptr,           /* ptr to control structure        */
0219  int install                            /* TRUE: install, FALSE: remove    */
0220 )
0221 /*-------------------------------------------------------------------------*\
0222 | Return Value:                                                             |
0223 |    <none>                                                                 |
0224 \*=========================================================================*/
0225 {
0226   rtems_status_code rc = RTEMS_SUCCESSFUL;
0227 
0228   /*
0229    * (un-)install handler for SPI device
0230    */
0231   if (install) {
0232     /*
0233      * create semaphore for IRQ synchronization
0234      */
0235     rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
0236                 0,
0237                 RTEMS_FIFO
0238                 | RTEMS_SIMPLE_BINARY_SEMAPHORE,
0239                 0,
0240                 &softc_ptr->irq_sema_id);
0241     if (rc != RTEMS_SUCCESSFUL) {
0242       rtems_panic("SPI: cannot create semaphore");
0243     }
0244     if (rc == RTEMS_SUCCESSFUL) {
0245       rc = rtems_interrupt_catch (m360_spi_irq_handler,
0246                   (m360.cicr & 0xE0) | 0x05,
0247                   &softc_ptr->old_handler);
0248       if (rc != RTEMS_SUCCESSFUL) {
0249     rtems_panic("SPI: cannot install IRQ handler");
0250       }
0251     }
0252     /*
0253      * enable IRQ in CPIC
0254      */
0255     if (rc == RTEMS_SUCCESSFUL) {
0256       m360.cimr |= (1 << 5);
0257     }
0258   }
0259   else {
0260     rtems_isr_entry old_handler;
0261     /*
0262      * disable IRQ in CPIC
0263      */
0264     if (rc == RTEMS_SUCCESSFUL) {
0265       m360.cimr &= ~(1 << 5);
0266     }
0267     rc = rtems_interrupt_catch (softc_ptr->old_handler,
0268                 (m360.cicr & 0xE0) | 0x05,
0269                 &old_handler);
0270     if (rc != RTEMS_SUCCESSFUL) {
0271       rtems_panic("SPI: cannot uninstall IRQ handler");
0272     }
0273     /*
0274      * delete sync semaphore
0275      */
0276     if (softc_ptr->irq_sema_id != 0) {
0277       rc = rtems_semaphore_delete(softc_ptr->irq_sema_id);
0278       if (rc != RTEMS_SUCCESSFUL) {
0279     rtems_panic("SPI: cannot delete semaphore");
0280       }
0281     }
0282   }
0283 }
0284 
0285 /*=========================================================================*\
0286 | Function:                                                                 |
0287 \*-------------------------------------------------------------------------*/
0288 rtems_status_code m360_spi_init
0289 (
0290 /*-------------------------------------------------------------------------*\
0291 | Purpose:                                                                  |
0292 |   initialize the driver                                                   |
0293 +---------------------------------------------------------------------------+
0294 | Input Parameters:                                                         |
0295 \*-------------------------------------------------------------------------*/
0296  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0297 )
0298 /*-------------------------------------------------------------------------*\
0299 | Return Value:                                                             |
0300 |    o = ok or error code                                                   |
0301 \*=========================================================================*/
0302 {
0303   m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc);
0304   rtems_status_code rc = RTEMS_SUCCESSFUL;
0305 
0306 #if defined(DEBUG)
0307   printk("m360_spi_init called... ");
0308 #endif
0309   /*
0310    * init HW registers:
0311    */
0312   /*
0313    * FIXME: set default mode in SPMODE
0314    */
0315 
0316   /*
0317    * allocate BDs (1x RX, 1x TX)
0318    */
0319   if (rc == RTEMS_SUCCESSFUL) {
0320     softc_ptr->rx_bd = M360AllocateBufferDescriptors (1);
0321     softc_ptr->tx_bd = M360AllocateBufferDescriptors (1);
0322     if ((softc_ptr->rx_bd == NULL) ||
0323     (softc_ptr->tx_bd == NULL)) {
0324       rc = RTEMS_NO_MEMORY;
0325     }
0326   }
0327   /*
0328    * set parameter RAM
0329    */
0330   m360.spip.rbase = (char *)softc_ptr->rx_bd - (char *)&m360;
0331   m360.spip.tbase = (char *)softc_ptr->tx_bd - (char *)&m360;
0332   m360.spip.rfcr  = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
0333   m360.spip.tfcr  = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
0334   m360.spip.mrblr = 2;
0335 
0336   /*
0337    * issue "InitRxTx" Command to CP
0338    */
0339   M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SPI);
0340 
0341   /*
0342    * init interrupt stuff
0343    */
0344   if (rc == RTEMS_SUCCESSFUL) {
0345     m360_spi_install_irq_handler(softc_ptr,TRUE);
0346   }
0347   if (rc == RTEMS_SUCCESSFUL) {
0348     /*
0349      * set up ports
0350      * LINE      PAR  DIR  DAT
0351      * -----------------------
0352      * MOSI       1    1    x
0353      * MISO       1    1    x
0354      * CLK        1    1    x
0355      */
0356 
0357     /* set Port B Pin Assignment Register... */
0358     m360.pbpar =
0359       m360.pbpar
0360       | M360_PB_SPI_MISO_MSK
0361       | M360_PB_SPI_MOSI_MSK
0362       | M360_PB_SPI_CLK_MSK;
0363 
0364     /* set Port B Data Direction Register... */
0365     m360.pbdir =
0366       m360.pbdir
0367       | M360_PB_SPI_MISO_MSK
0368       | M360_PB_SPI_MOSI_MSK
0369       | M360_PB_SPI_CLK_MSK;
0370   }
0371   /*
0372    * mark, that we have initialized
0373    */
0374   if (rc == RTEMS_SUCCESSFUL) {
0375     softc_ptr->initialized = TRUE;
0376   }
0377 #if defined(DEBUG)
0378   printk("... exit OK\r\n");
0379 #endif
0380   return rc;
0381 }
0382 
0383 
0384 /*=========================================================================*\
0385 | Function:                                                                 |
0386 \*-------------------------------------------------------------------------*/
0387 static int m360_spi_read_write_bytes
0388 (
0389 /*-------------------------------------------------------------------------*\
0390 | Purpose:                                                                  |
0391 |   transmit/receive some bytes from SPI device                             |
0392 +---------------------------------------------------------------------------+
0393 | Input Parameters:                                                         |
0394 \*-------------------------------------------------------------------------*/
0395  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0396  unsigned char *rbuf,                    /* buffer to store bytes          */
0397  const unsigned char *tbuf,              /* buffer to send  bytes          */
0398  int len                                 /* number of bytes to transceive  */
0399 )
0400 /*-------------------------------------------------------------------------*\
0401 | Return Value:                                                             |
0402 |    number of bytes received or (negative) error code                      |
0403 \*=========================================================================*/
0404 {
0405   m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc);
0406   rtems_status_code rc = RTEMS_SUCCESSFUL;
0407   int bc = 0;
0408 
0409 #if defined(DEBUG)
0410   printk("m360_spi_read_write_bytes called... ");
0411 #endif
0412 
0413   /*
0414    * prepare RxBD
0415    */
0416   if (rc == RTEMS_SUCCESSFUL) {
0417     if (rbuf == NULL) {
0418       /*
0419        * no Tx buffer: receive to dummy buffer
0420        */
0421       m360.spip.mrblr          = sizeof(m360_spi_dummy_rxbuf);
0422       softc_ptr->rx_bd->buffer = m360_spi_dummy_rxbuf;
0423       softc_ptr->rx_bd->length = 0;
0424       softc_ptr->rx_bd->status = (M360_BD_EMPTY | M360_BD_WRAP |
0425                   M360_BD_CONTINUOUS);
0426     }
0427     else {
0428       m360.spip.mrblr          = len;
0429       softc_ptr->rx_bd->buffer = rbuf;
0430       softc_ptr->rx_bd->length = 0;
0431       softc_ptr->rx_bd->status = (M360_BD_EMPTY | M360_BD_WRAP);
0432     }
0433   }
0434   /*
0435    * prepare TxBD
0436    */
0437   if (rc == RTEMS_SUCCESSFUL) {
0438     if (tbuf == NULL) {
0439       /*
0440        * FIXME: no Tx buffer: transmit from dummy buffer
0441        */
0442       softc_ptr->tx_bd->buffer = m360_spi_dummy_rxbuf;
0443       softc_ptr->tx_bd->length = len;
0444       softc_ptr->tx_bd->status = (M360_BD_READY | M360_BD_WRAP |
0445                   M360_BD_CONTINUOUS);
0446     }
0447     else {
0448       softc_ptr->tx_bd->buffer = tbuf;
0449       softc_ptr->tx_bd->length = len;
0450       softc_ptr->tx_bd->status = (M360_BD_READY | M360_BD_WRAP);
0451     }
0452   }
0453 
0454   if (rc == RTEMS_SUCCESSFUL) {
0455     /*
0456      * set START command
0457      */
0458     m360.spcom = M360_SPCOM_STR;
0459     /*
0460      * wait for SPI to finish
0461      */
0462     rc = m360_spi_wait(softc_ptr);
0463   }
0464 #if defined(DEBUG)
0465   printk("... exit OK, rc=%d\r\n",bc);
0466 #endif
0467   return (rc == RTEMS_SUCCESSFUL) ? bc : -rc;
0468 }
0469 
0470 /*=========================================================================*\
0471 | Function:                                                                 |
0472 \*-------------------------------------------------------------------------*/
0473 int m360_spi_read_bytes
0474 (
0475 /*-------------------------------------------------------------------------*\
0476 | Purpose:                                                                  |
0477 |   receive some bytes from SPI device                                      |
0478 +---------------------------------------------------------------------------+
0479 | Input Parameters:                                                         |
0480 \*-------------------------------------------------------------------------*/
0481  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0482  unsigned char *buf,                     /* buffer to store bytes          */
0483  int len                                 /* number of bytes to receive     */
0484 )
0485 /*-------------------------------------------------------------------------*\
0486 | Return Value:                                                             |
0487 |    number of bytes received or (negative) error code                      |
0488 \*=========================================================================*/
0489 {
0490   return m360_spi_read_write_bytes(bh,buf,NULL,len);
0491 }
0492 
0493 /*=========================================================================*\
0494 | Function:                                                                 |
0495 \*-------------------------------------------------------------------------*/
0496 int m360_spi_write_bytes
0497 (
0498 /*-------------------------------------------------------------------------*\
0499 | Purpose:                                                                  |
0500 |   send some bytes to SPI device                                           |
0501 +---------------------------------------------------------------------------+
0502 | Input Parameters:                                                         |
0503 \*-------------------------------------------------------------------------*/
0504  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0505  unsigned char *buf,                     /* buffer to send                 */
0506  int len                                 /* number of bytes to send        */
0507 
0508 )
0509 /*-------------------------------------------------------------------------*\
0510 | Return Value:                                                             |
0511 |    number of bytes sent or (negative) error code                          |
0512 \*=========================================================================*/
0513 {
0514   return m360_spi_read_write_bytes(bh,NULL,buf,len);
0515 }
0516 
0517 /*=========================================================================*\
0518 | Function:                                                                 |
0519 \*-------------------------------------------------------------------------*/
0520 rtems_status_code m360_spi_set_tfr_mode
0521 (
0522 /*-------------------------------------------------------------------------*\
0523 | Purpose:                                                                  |
0524 |   set SPI to desired baudrate/clock mode/character mode                   |
0525 +---------------------------------------------------------------------------+
0526 | Input Parameters:                                                         |
0527 \*-------------------------------------------------------------------------*/
0528  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0529  const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info             */
0530 )
0531 /*-------------------------------------------------------------------------*\
0532 | Return Value:                                                             |
0533 |    rtems_status_code                                                      |
0534 \*=========================================================================*/
0535 {
0536   m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc);
0537   uint32_t spimode_baud,spimode;
0538   rtems_status_code rc = RTEMS_SUCCESSFUL;
0539   /*
0540    * FIXME: set proper mode
0541    */
0542   if (rc == RTEMS_SUCCESSFUL) {
0543     rc = m360_spi_baud_to_mode(tfr_mode->baudrate,&spimode_baud);
0544   }
0545   if (rc == RTEMS_SUCCESSFUL) {
0546     rc = m360_spi_char_mode(softc_ptr,
0547                    tfr_mode->bits_per_char,
0548                    tfr_mode->lsb_first,
0549                    &spimode);
0550   }
0551   if (rc == RTEMS_SUCCESSFUL) {
0552     spimode |= spimode_baud;
0553     spimode |= M360_SPMODE_MASTER; /* set master mode */
0554     if (!tfr_mode->lsb_first) {
0555       spimode |= M360_SPMODE_REV;
0556     }
0557     if (tfr_mode->clock_inv) {
0558       spimode |= M360_SPMODE_CI;
0559     }
0560     if (tfr_mode->clock_phs) {
0561       spimode |= M360_SPMODE_CP;
0562     }
0563   }
0564 
0565   if (rc == RTEMS_SUCCESSFUL) {
0566     /*
0567      * disable SPI
0568      */
0569     m360.spmode &= ~M360_SPMODE_EN;
0570     /*
0571      * set new mode and reenable SPI
0572      */
0573     m360.spmode = spimode | M360_SPMODE_EN;
0574   }
0575   return rc;
0576 }
0577 
0578 
0579 /*=========================================================================*\
0580 | Function:                                                                 |
0581 \*-------------------------------------------------------------------------*/
0582 int m360_spi_ioctl
0583 (
0584 /*-------------------------------------------------------------------------*\
0585 | Purpose:                                                                  |
0586 |   perform selected ioctl function for SPI                                 |
0587 +---------------------------------------------------------------------------+
0588 | Input Parameters:                                                         |
0589 \*-------------------------------------------------------------------------*/
0590  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0591  int                 cmd,                /* ioctl command code             */
0592  void               *arg                 /* additional argument array      */
0593 )
0594 /*-------------------------------------------------------------------------*\
0595 | Return Value:                                                             |
0596 |    rtems_status_code                                                      |
0597 \*=========================================================================*/
0598 {
0599   int ret_val = -1;
0600 
0601   switch(cmd) {
0602   case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0603     ret_val =
0604       -m360_spi_set_tfr_mode(bh,
0605                 (const rtems_libi2c_tfr_mode_t *)arg);
0606     break;
0607   case RTEMS_LIBI2C_IOCTL_READ_WRITE:
0608     ret_val =
0609       m360_spi_read_write_bytes(bh,
0610                 ((rtems_libi2c_read_write_t *)arg)->rd_buf,
0611                 ((rtems_libi2c_read_write_t *)arg)->wr_buf,
0612                 ((rtems_libi2c_read_write_t *)arg)->byte_cnt);
0613     break;
0614   default:
0615     ret_val = -RTEMS_NOT_DEFINED;
0616     break;
0617   }
0618   return ret_val;
0619 }
0620 
0621 /*=========================================================================*\
0622 | Board-specific adaptation functions                                       |
0623 \*=========================================================================*/
0624 
0625 /*=========================================================================*\
0626 | Function:                                                                 |
0627 \*-------------------------------------------------------------------------*/
0628 static rtems_status_code bsp_spi_sel_addr
0629 (
0630 /*-------------------------------------------------------------------------*\
0631 | Purpose:                                                                  |
0632 |   address a slave device on the bus                                       |
0633 +---------------------------------------------------------------------------+
0634 | Input Parameters:                                                         |
0635 \*-------------------------------------------------------------------------*/
0636  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0637  uint32_t addr,                          /* address to send on bus         */
0638  int rw                                  /* 0=write,1=read                 */
0639 )
0640 /*-------------------------------------------------------------------------*\
0641 | Return Value:                                                             |
0642 |    o = ok or error code                                                   |
0643 \*=========================================================================*/
0644 {
0645 #if defined(PGH360)
0646   /*
0647    * select given device
0648    */
0649   /*
0650    * GPIO1[24] is SPI_A0
0651    * GPIO1[25] is SPI_A1
0652    * GPIO1[26] is SPI_A2
0653    * set pins to address
0654    */
0655   switch(addr) {
0656   case PGH360_SPI_ADDR_EEPROM:
0657     m360.pbdat &= ~PGH360_PB_SPI_EEP_CE_MSK;
0658     break;
0659   case PGH360_SPI_ADDR_DISP4_DATA:
0660     m360.pbdat = (m360.pbdat
0661           & ~(PGH360_PB_SPI_DISP4_CE_MSK |
0662               PGH360_PB_SPI_DISP4_RS_MSK));
0663     break;
0664   case PGH360_SPI_ADDR_DISP4_CTRL:
0665     m360.pbdat = (m360.pbdat
0666           & ~(PGH360_PB_SPI_DISP4_CE_MSK)
0667           |   PGH360_PB_SPI_DISP4_RS_MSK);
0668     break;
0669   default:
0670     return RTEMS_INVALID_NUMBER;
0671   }
0672 #endif /* PGH360 */
0673   return  RTEMS_SUCCESSFUL;
0674 }
0675 
0676 /*=========================================================================*\
0677 | Function:                                                                 |
0678 \*-------------------------------------------------------------------------*/
0679 static rtems_status_code bsp_spi_send_start_dummy
0680 (
0681 /*-------------------------------------------------------------------------*\
0682 | Purpose:                                                                  |
0683 |   dummy function, SPI has no start condition                              |
0684 +---------------------------------------------------------------------------+
0685 | Input Parameters:                                                         |
0686 \*-------------------------------------------------------------------------*/
0687  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0688 )
0689 /*-------------------------------------------------------------------------*\
0690 | Return Value:                                                             |
0691 |    o = ok or error code                                                   |
0692 \*=========================================================================*/
0693 {
0694   return 0;
0695 }
0696 
0697 /*=========================================================================*\
0698 | Function:                                                                 |
0699 \*-------------------------------------------------------------------------*/
0700 static rtems_status_code bsp_spi_send_stop
0701 (
0702 /*-------------------------------------------------------------------------*\
0703 | Purpose:                                                                  |
0704 |   deselect SPI                                                            |
0705 +---------------------------------------------------------------------------+
0706 | Input Parameters:                                                         |
0707 \*-------------------------------------------------------------------------*/
0708  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0709 )
0710 /*-------------------------------------------------------------------------*\
0711 | Return Value:                                                             |
0712 |    o = ok or error code                                                   |
0713 \*=========================================================================*/
0714 {
0715 #if defined(DEBUG)
0716   printk("bsp_spi_send_stop called... ");
0717 #endif
0718 #if defined(PGH360)
0719     m360.pbdat = (m360.pbdat
0720           | PGH360_PB_SPI_DISP4_CE_MSK
0721           | PGH360_PB_SPI_EEP_CE_MSK);
0722 #endif
0723 #if defined(DEBUG)
0724   printk("... exit OK\r\n");
0725 #endif
0726   return 0;
0727 }
0728 
0729 /*=========================================================================*\
0730 | list of handlers                                                          |
0731 \*=========================================================================*/
0732 
0733 rtems_libi2c_bus_ops_t bsp_spi_ops = {
0734   init:             m360_spi_init,
0735   send_start:       bsp_spi_send_start_dummy,
0736   send_stop:        bsp_spi_send_stop,
0737   send_addr:        bsp_spi_sel_addr,
0738   read_bytes:       m360_spi_read_bytes,
0739   write_bytes:      m360_spi_write_bytes,
0740   ioctl:            m360_spi_ioctl
0741 };
0742 
0743 static m360_spi_desc_t bsp_spi_bus_desc = {
0744   {/* public fields */
0745     ops:    &bsp_spi_ops,
0746     size:   sizeof(bsp_spi_bus_desc)
0747   },
0748   { /* our private fields */
0749     initialized: FALSE
0750   }
0751 };
0752 
0753 /*=========================================================================*\
0754 | initialization                                                            |
0755 \*=========================================================================*/
0756 
0757 /*=========================================================================*\
0758 | Function:                                                                 |
0759 \*-------------------------------------------------------------------------*/
0760 rtems_status_code bsp_register_spi
0761 (
0762 /*-------------------------------------------------------------------------*\
0763 | Purpose:                                                                  |
0764 |   register SPI bus and devices                                            |
0765 +---------------------------------------------------------------------------+
0766 | Input Parameters:                                                         |
0767 \*-------------------------------------------------------------------------*/
0768  void                                    /* <none>                         */
0769 )
0770 /*-------------------------------------------------------------------------*\
0771 | Return Value:                                                             |
0772 |    0 or error code                                                        |
0773 \*=========================================================================*/
0774 {
0775   int ret_code;
0776   int spi_busno;
0777 
0778   /*
0779    * init I2C library (if not already done)
0780    */
0781   rtems_libi2c_initialize ();
0782 
0783   /*
0784    * init port pins used to address/select SPI devices
0785    */
0786 
0787 #if defined(PGH360)
0788 
0789   /*
0790    * set up ports
0791    * LINE      PAR  DIR  DAT
0792    * -----------------------
0793    * EEP_CE     0    1 act-high
0794    * DISP4_CS   0    1 act-high
0795    * DISP4_RS   0    1 active
0796    */
0797 
0798   /* set Port B Pin Assignment Register... */
0799   m360.pbpar =
0800     (m360.pbpar
0801      & ~(PGH360_PB_SPI_EEP_CE_MSK
0802      | PGH360_PB_SPI_DISP4_CE_MSK
0803      | PGH360_PB_SPI_DISP4_RS_MSK));
0804 
0805     /* set Port B Data Direction Register... */
0806   m360.pbdir =
0807     m360.pbdir
0808     | PGH360_PB_SPI_EEP_CE_MSK
0809     | PGH360_PB_SPI_DISP4_CE_MSK
0810     | PGH360_PB_SPI_DISP4_RS_MSK;
0811 
0812   /* set Port B Data Register to inactive CE state */
0813   m360.pbdat =
0814     m360.pbdat
0815     | PGH360_PB_SPI_DISP4_CE_MSK
0816     | PGH360_PB_SPI_DISP4_RS_MSK;
0817 #endif
0818 
0819   /*
0820    * register SPI bus
0821    */
0822   ret_code = rtems_libi2c_register_bus("/dev/spi",
0823                        &(bsp_spi_bus_desc.bus_desc));
0824   if (ret_code < 0) {
0825     return -ret_code;
0826   }
0827   spi_busno = ret_code;
0828 #if defined(PGH360)
0829   /*
0830    * register devices
0831    */
0832 #if 0
0833   ret_code = rtems_libi2c_register_drv(RTEMS_BSP_SPI_FLASH_DEVICE_NAME,
0834                        spi_flash_m25p40_rw_driver_descriptor,
0835                        spi_busno,0x00);
0836   if (ret_code < 0) {
0837     return -ret_code;
0838   }
0839 #endif
0840 #endif /* defined(PGH360) */
0841   /*
0842    * FIXME: further drivers, when available
0843    */
0844   return 0;
0845 }
0846 
0847