Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * RTEMS support for tqm8xx
0005  *
0006  * This file contains the MPC8xx SPI driver.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2009 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 #include <stdlib.h>
0035 #include <bsp.h>
0036 #include <mpc8xx.h>
0037 #include <bsp/spi.h>
0038 #include <libchip/disp_hcms29xx.h>
0039 #include <rtems/error.h>
0040 #include <rtems/bspIo.h>
0041 #include <errno.h>
0042 #include <rtems/libi2c.h>
0043 #include <bsp/irq.h>
0044 
0045 #define M8xx_PB_SPI_MISO_MSK       (1<<(31-28))
0046 #define M8xx_PB_SPI_MOSI_MSK       (1<<(31-29))
0047 #define M8xx_PB_SPI_CLK_MSK        (1<<(31-30))
0048 
0049 #undef DEBUG
0050 
0051 /*
0052  * this is a dummy receive buffer for sequences,
0053  * where only send data are available
0054  */
0055 uint8_t m8xx_spi_dummy_rxbuf[2];
0056 /*=========================================================================*\
0057 | Function:                                                                 |
0058 \*-------------------------------------------------------------------------*/
0059 static rtems_status_code m8xx_spi_baud_to_mode
0060 (
0061 /*-------------------------------------------------------------------------*\
0062 | Purpose:                                                                  |
0063 |   determine proper divider value                                          |
0064 +---------------------------------------------------------------------------+
0065 | Input Parameters:                                                         |
0066 \*-------------------------------------------------------------------------*/
0067  uint32_t baudrate,                      /* desired baudrate               */
0068  uint32_t *spimode                       /* result value                   */
0069 )
0070 /*-------------------------------------------------------------------------*\
0071 | Return Value:                                                             |
0072 |    o = ok or error code                                                   |
0073 \*=========================================================================*/
0074 {
0075   uint32_t divider;
0076   uint16_t tmpmode = 0;
0077   /*
0078    * determine clock divider and DIV16 bit
0079    */
0080   divider = BSP_bus_frequency/baudrate;
0081   if (divider > 64) {
0082     tmpmode = M8xx_SPMODE_DIV16;
0083     divider /= 16;
0084   }
0085   if ((divider <  1) ||
0086       (divider > 64)) {
0087     return RTEMS_INVALID_NUMBER;
0088   }
0089   else {
0090     tmpmode |= M8xx_SPMODE_PM(divider/4-1);
0091   }
0092   *spimode = tmpmode;
0093   return RTEMS_SUCCESSFUL;
0094 }
0095 
0096 /*=========================================================================*\
0097 | Function:                                                                 |
0098 \*-------------------------------------------------------------------------*/
0099 static rtems_status_code m8xx_spi_char_mode
0100 (
0101 /*-------------------------------------------------------------------------*\
0102 | Purpose:                                                                  |
0103 |   determine proper value for character size                               |
0104 +---------------------------------------------------------------------------+
0105 | Input Parameters:                                                         |
0106 \*-------------------------------------------------------------------------*/
0107  m8xx_spi_softc_t *softc_ptr,            /* handle                         */
0108  uint32_t bits_per_char,                 /* bits per character             */
0109  bool     lsb_first,                     /* TRUE: send LSB first           */
0110  uint16_t *spimode                       /* result value                   */
0111 )
0112 /*-------------------------------------------------------------------------*\
0113 | Return Value:                                                             |
0114 |    o = ok or error code                                                   |
0115 \*=========================================================================*/
0116 {
0117   uint16_t tmpmode;
0118 
0119   /*
0120    * calculate data format
0121    */
0122   if ((bits_per_char >= 4) &&
0123       (bits_per_char <= 16)) {
0124     tmpmode = M8xx_SPMODE_CLEN( bits_per_char-1);
0125   }
0126   else {
0127     return RTEMS_INVALID_NUMBER;
0128   }
0129 
0130   *spimode = tmpmode;
0131   return 0;
0132 }
0133 
0134 /*=========================================================================*\
0135 | Function:                                                                 |
0136 \*-------------------------------------------------------------------------*/
0137 static int m8xx_spi_wait
0138 (
0139 /*-------------------------------------------------------------------------*\
0140 | Purpose:                                                                  |
0141 |   wait for spi to become idle                                             |
0142 +---------------------------------------------------------------------------+
0143 | Input Parameters:                                                         |
0144 \*-------------------------------------------------------------------------*/
0145  m8xx_spi_softc_t    *softc_ptr           /* handle              */
0146 )
0147 /*-------------------------------------------------------------------------*\
0148 | Return Value:                                                             |
0149 |    o = ok or error code                                                   |
0150 \*=========================================================================*/
0151 {
0152   uint16_t act_status;
0153   rtems_status_code rc;
0154   uint32_t tout;
0155 
0156 #if defined(DEBUG)
0157   printk("m8xx_spi_wait called... ");
0158 #endif
0159   if (softc_ptr->initialized) {
0160     /*
0161      * allow interrupts, when receiver is not empty
0162      */
0163     m8xx.spim = (M8xx_SPIE_TXE | M8xx_SPIE_TXB |
0164          M8xx_SPIE_BSY | M8xx_SPIE_MME);
0165 
0166     rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,
0167                 RTEMS_WAIT,
0168                 RTEMS_NO_TIMEOUT);
0169     if (rc != RTEMS_SUCCESSFUL) {
0170       return rc;
0171     }
0172   }
0173   else {
0174     tout = 0;
0175     do {
0176       if (tout++ > 1000000) {
0177 #if defined(DEBUG)
0178     printk("... exit with RTEMS_TIMEOUT\r\n");
0179 #endif
0180     return RTEMS_TIMEOUT;
0181       }
0182       /*
0183        * wait for SPI to terminate
0184        */
0185     } while (!(m8xx.spie & M8xx_SPIE_TXB));
0186   }
0187 
0188   act_status = m8xx.spie;
0189   if ((act_status  & (M8xx_SPIE_TXE | M8xx_SPIE_TXB |
0190               M8xx_SPIE_BSY | M8xx_SPIE_MME))!= M8xx_SPIE_TXB) {
0191 #if defined(DEBUG)
0192     printk("... exit with RTEMS_IO_ERROR,"
0193        "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n",
0194        act_status,status_mask,desired_status);
0195 #endif
0196     return RTEMS_IO_ERROR;
0197   }
0198 #if defined(DEBUG)
0199     printk("... exit OK\r\n");
0200 #endif
0201   return RTEMS_SUCCESSFUL;
0202 }
0203 
0204 /*=========================================================================*\
0205 | Function:                                                                 |
0206 \*-------------------------------------------------------------------------*/
0207 static rtems_isr m8xx_spi_irq_handler
0208 (
0209 /*-------------------------------------------------------------------------*\
0210 | Purpose:                                                                  |
0211 |   handle interrupts                                                       |
0212 +---------------------------------------------------------------------------+
0213 | Input Parameters:                                                         |
0214 \*-------------------------------------------------------------------------*/
0215  void *arg
0216 )
0217 /*-------------------------------------------------------------------------*\
0218 | Return Value:                                                             |
0219 |    <none>                                                                 |
0220 \*=========================================================================*/
0221 {
0222   m8xx_spi_softc_t *softc_ptr = arg;
0223 
0224   /*
0225    * disable interrupt mask
0226    */
0227   m8xx.spim = 0;
0228   if (softc_ptr->initialized) {
0229     rtems_semaphore_release(softc_ptr->irq_sema_id);
0230   }
0231 }
0232 
0233 static void
0234 mpc8xx_spi_irq_on(const rtems_irq_connect_data *irq)
0235 {
0236 }
0237 
0238 static void
0239 mpc8xx_spi_irq_off(const rtems_irq_connect_data *irq)
0240 {
0241 }
0242 
0243 static int
0244 mpc8xx_spi_irq_isOn(const rtems_irq_connect_data *irq)
0245 {
0246   return 1;
0247 }
0248 
0249 /*=========================================================================*\
0250 | Function:                                                                 |
0251 \*-------------------------------------------------------------------------*/
0252 static void m8xx_spi_install_irq_handler
0253 (
0254 /*-------------------------------------------------------------------------*\
0255 | Purpose:                                                                  |
0256 |   install the interrupt handler                                           |
0257 +---------------------------------------------------------------------------+
0258 | Input Parameters:                                                         |
0259 \*-------------------------------------------------------------------------*/
0260  m8xx_spi_softc_t *softc_ptr,           /* ptr to control structure        */
0261  int install                            /* TRUE: install, FALSE: remove    */
0262 )
0263 /*-------------------------------------------------------------------------*\
0264 | Return Value:                                                             |
0265 |    <none>                                                                 |
0266 \*=========================================================================*/
0267 {
0268   rtems_status_code rc = RTEMS_SUCCESSFUL;
0269 
0270   /*
0271    * install handler for SPI device
0272    */
0273   /*
0274    * create semaphore for IRQ synchronization
0275    */
0276   rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
0277                   0,
0278                   RTEMS_FIFO
0279                   | RTEMS_SIMPLE_BINARY_SEMAPHORE,
0280                   0,
0281                   &softc_ptr->irq_sema_id);
0282   if (rc != RTEMS_SUCCESSFUL) {
0283     rtems_panic("SPI: cannot create semaphore");
0284   }
0285   if (rc == RTEMS_SUCCESSFUL) {
0286     rtems_irq_connect_data irq_conn_data = {
0287       BSP_CPM_IRQ_SPI,
0288       m8xx_spi_irq_handler,            /* rtems_irq_hdl           */
0289       (rtems_irq_hdl_param)softc_ptr,  /* (rtems_irq_hdl_param)   */
0290       mpc8xx_spi_irq_on,               /* (rtems_irq_enable)      */
0291       mpc8xx_spi_irq_off,              /* (rtems_irq_disable)     */
0292       mpc8xx_spi_irq_isOn              /* (rtems_irq_is_enabled)  */
0293     };
0294     if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
0295       rtems_panic("SPI: cannot install IRQ handler");
0296     }
0297   }
0298 }
0299 
0300 /*=========================================================================*\
0301 | Function:                                                                 |
0302 \*-------------------------------------------------------------------------*/
0303 rtems_status_code m8xx_spi_init
0304 (
0305 /*-------------------------------------------------------------------------*\
0306 | Purpose:                                                                  |
0307 |   initialize the driver                                                   |
0308 +---------------------------------------------------------------------------+
0309 | Input Parameters:                                                         |
0310 \*-------------------------------------------------------------------------*/
0311  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0312 )
0313 /*-------------------------------------------------------------------------*\
0314 | Return Value:                                                             |
0315 |    o = ok or error code                                                   |
0316 \*=========================================================================*/
0317 {
0318   m8xx_spi_softc_t *softc_ptr = &(((m8xx_spi_desc_t *)(bh))->softc);
0319   rtems_status_code rc = RTEMS_SUCCESSFUL;
0320 
0321 #if defined(DEBUG)
0322   printk("m8xx_spi_init called... ");
0323 #endif
0324   /*
0325    * init HW registers:
0326    */
0327   /*
0328    * FIXME: set default mode in SPMODE
0329    */
0330 
0331   /*
0332    * allocate BDs (1x RX, 1x TX)
0333    */
0334   if (rc == RTEMS_SUCCESSFUL) {
0335     softc_ptr->rx_bd = m8xx_bd_allocate (1);
0336     softc_ptr->tx_bd = m8xx_bd_allocate (1);
0337     if ((softc_ptr->rx_bd == NULL) ||
0338     (softc_ptr->tx_bd == NULL)) {
0339       rc = RTEMS_NO_MEMORY;
0340     }
0341   }
0342   /*
0343    * set parameter RAM
0344    */
0345   m8xx.spip.rbase = (char *)softc_ptr->rx_bd - (char *)&m8xx;
0346   m8xx.spip.tbase = (char *)softc_ptr->tx_bd - (char *)&m8xx;
0347   m8xx.spip.rfcr  = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
0348   m8xx.spip.tfcr  = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
0349   m8xx.spip.mrblr = 2;
0350 
0351   /*
0352    * issue "InitRxTx" Command to CP
0353    */
0354   m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SPI);
0355 
0356   /*
0357    * init interrupt stuff
0358    */
0359   if (rc == RTEMS_SUCCESSFUL) {
0360     m8xx_spi_install_irq_handler(softc_ptr,TRUE);
0361   }
0362   if (rc == RTEMS_SUCCESSFUL) {
0363     /*
0364      * set up ports
0365      * LINE      PAR  DIR  DAT
0366      * -----------------------
0367      * MOSI       1    1    x
0368      * MISO       1    1    x
0369      * CLK        1    1    x
0370      */
0371 
0372     /* set Port B Pin Assignment Register... */
0373     m8xx.pbpar =
0374       m8xx.pbpar
0375       | M8xx_PB_SPI_MISO_MSK
0376       | M8xx_PB_SPI_MOSI_MSK
0377       | M8xx_PB_SPI_CLK_MSK;
0378 
0379     /* set Port B Data Direction Register... */
0380     m8xx.pbdir =
0381       m8xx.pbdir
0382       | M8xx_PB_SPI_MISO_MSK
0383       | M8xx_PB_SPI_MOSI_MSK
0384       | M8xx_PB_SPI_CLK_MSK;
0385   }
0386   /*
0387    * mark, that we have initialized
0388    */
0389   if (rc == RTEMS_SUCCESSFUL) {
0390     softc_ptr->initialized = TRUE;
0391   }
0392 #if defined(DEBUG)
0393   printk("... exit OK\r\n");
0394 #endif
0395   return rc;
0396 }
0397 
0398 
0399 /*=========================================================================*\
0400 | Function:                                                                 |
0401 \*-------------------------------------------------------------------------*/
0402 static int m8xx_spi_read_write_bytes
0403 (
0404 /*-------------------------------------------------------------------------*\
0405 | Purpose:                                                                  |
0406 |   transmit/receive some bytes from SPI device                             |
0407 +---------------------------------------------------------------------------+
0408 | Input Parameters:                                                         |
0409 \*-------------------------------------------------------------------------*/
0410  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0411  unsigned char *rbuf,                    /* buffer to store bytes          */
0412  const unsigned char *tbuf,              /* buffer to send  bytes          */
0413  int len                                 /* number of bytes to transceive  */
0414 )
0415 /*-------------------------------------------------------------------------*\
0416 | Return Value:                                                             |
0417 |    number of bytes received or (negative) error code                      |
0418 \*=========================================================================*/
0419 {
0420   m8xx_spi_softc_t *softc_ptr = &(((m8xx_spi_desc_t *)(bh))->softc);
0421   rtems_status_code rc = RTEMS_SUCCESSFUL;
0422   int bc = 0;
0423 
0424 #if defined(DEBUG)
0425   printk("m8xx_spi_read_write_bytes called... ");
0426 #endif
0427 
0428   /*
0429    * prepare RxBD
0430    */
0431   if (rc == RTEMS_SUCCESSFUL) {
0432     if (rbuf == NULL) {
0433       /*
0434        * no Tx buffer: receive to dummy buffer
0435        */
0436       m8xx.spip.mrblr          = sizeof(m8xx_spi_dummy_rxbuf);
0437       softc_ptr->rx_bd->buffer = m8xx_spi_dummy_rxbuf;
0438       softc_ptr->rx_bd->length = 0;
0439       softc_ptr->rx_bd->status = (M8xx_BD_EMPTY | M8xx_BD_WRAP |
0440                   M8xx_BD_CONTINUOUS);
0441     }
0442     else {
0443       m8xx.spip.mrblr          = len;
0444       softc_ptr->rx_bd->buffer = rbuf;
0445       softc_ptr->rx_bd->length = 0;
0446       softc_ptr->rx_bd->status = (M8xx_BD_EMPTY | M8xx_BD_WRAP);
0447     }
0448   }
0449   /*
0450    * prepare TxBD
0451    */
0452   if (rc == RTEMS_SUCCESSFUL) {
0453     if (tbuf == NULL) {
0454       /*
0455        * no Tx buffer: transmit from dummy buffer
0456        */
0457       softc_ptr->tx_bd->buffer = m8xx_spi_dummy_rxbuf;
0458       softc_ptr->tx_bd->length = len;
0459       softc_ptr->tx_bd->status = (M8xx_BD_READY | M8xx_BD_WRAP |
0460                   M8xx_BD_CONTINUOUS);
0461     }
0462     else {
0463       softc_ptr->tx_bd->buffer = (char *)tbuf;
0464       softc_ptr->tx_bd->length = len;
0465       softc_ptr->tx_bd->status = (M8xx_BD_READY | M8xx_BD_WRAP);
0466     }
0467   }
0468 
0469   if (rc == RTEMS_SUCCESSFUL) {
0470     /*
0471      * set START command
0472      */
0473     m8xx.spcom = M8xx_SPCOM_STR;
0474     /*
0475      * wait for SPI to finish
0476      */
0477     rc = m8xx_spi_wait(softc_ptr);
0478   }
0479 #if defined(DEBUG)
0480   printk("... exit OK, rc=%d\r\n",bc);
0481 #endif
0482   return (rc == RTEMS_SUCCESSFUL) ? bc : -rc;
0483 }
0484 
0485 /*=========================================================================*\
0486 | Function:                                                                 |
0487 \*-------------------------------------------------------------------------*/
0488 int m8xx_spi_read_bytes
0489 (
0490 /*-------------------------------------------------------------------------*\
0491 | Purpose:                                                                  |
0492 |   receive some bytes from SPI device                                      |
0493 +---------------------------------------------------------------------------+
0494 | Input Parameters:                                                         |
0495 \*-------------------------------------------------------------------------*/
0496  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0497  unsigned char *buf,                     /* buffer to store bytes          */
0498  int len                                 /* number of bytes to receive     */
0499 )
0500 /*-------------------------------------------------------------------------*\
0501 | Return Value:                                                             |
0502 |    number of bytes received or (negative) error code                      |
0503 \*=========================================================================*/
0504 {
0505   return m8xx_spi_read_write_bytes(bh,buf,NULL,len);
0506 }
0507 
0508 /*=========================================================================*\
0509 | Function:                                                                 |
0510 \*-------------------------------------------------------------------------*/
0511 int m8xx_spi_write_bytes
0512 (
0513 /*-------------------------------------------------------------------------*\
0514 | Purpose:                                                                  |
0515 |   send some bytes to SPI device                                           |
0516 +---------------------------------------------------------------------------+
0517 | Input Parameters:                                                         |
0518 \*-------------------------------------------------------------------------*/
0519  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0520  unsigned char *buf,                     /* buffer to send                 */
0521  int len                                 /* number of bytes to send        */
0522 
0523 )
0524 /*-------------------------------------------------------------------------*\
0525 | Return Value:                                                             |
0526 |    number of bytes sent or (negative) error code                          |
0527 \*=========================================================================*/
0528 {
0529   return m8xx_spi_read_write_bytes(bh,NULL,buf,len);
0530 }
0531 
0532 /*=========================================================================*\
0533 | Function:                                                                 |
0534 \*-------------------------------------------------------------------------*/
0535 rtems_status_code m8xx_spi_set_tfr_mode
0536 (
0537 /*-------------------------------------------------------------------------*\
0538 | Purpose:                                                                  |
0539 |   set SPI to desired baudrate/clock mode/character mode                   |
0540 +---------------------------------------------------------------------------+
0541 | Input Parameters:                                                         |
0542 \*-------------------------------------------------------------------------*/
0543  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0544  const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info             */
0545 )
0546 /*-------------------------------------------------------------------------*\
0547 | Return Value:                                                             |
0548 |    rtems_status_code                                                      |
0549 \*=========================================================================*/
0550 {
0551   m8xx_spi_softc_t *softc_ptr = &(((m8xx_spi_desc_t *)(bh))->softc);
0552   uint32_t spimode_baud;
0553   uint16_t spimode;
0554   rtems_status_code rc = RTEMS_SUCCESSFUL;
0555   /*
0556    * FIXME: set proper mode
0557    */
0558   if (rc == RTEMS_SUCCESSFUL) {
0559     rc = m8xx_spi_baud_to_mode(tfr_mode->baudrate,&spimode_baud);
0560   }
0561   if (rc == RTEMS_SUCCESSFUL) {
0562     rc = m8xx_spi_char_mode(softc_ptr,
0563                    tfr_mode->bits_per_char,
0564                    tfr_mode->lsb_first,
0565                    &spimode);
0566   }
0567   if (rc == RTEMS_SUCCESSFUL) {
0568     spimode |= spimode_baud;
0569     spimode |= M8xx_SPMODE_MASTER; /* set master mode */
0570     if (!tfr_mode->lsb_first) {
0571       spimode |= M8xx_SPMODE_REV;
0572     }
0573     if (tfr_mode->clock_inv) {
0574       spimode |= M8xx_SPMODE_CI;
0575     }
0576     if (tfr_mode->clock_phs) {
0577       spimode |= M8xx_SPMODE_CP;
0578     }
0579   }
0580 
0581   if (rc == RTEMS_SUCCESSFUL) {
0582     /*
0583      * disable SPI
0584      */
0585     m8xx.spmode &= ~M8xx_SPMODE_EN;
0586     /*
0587      * set new mode and reenable SPI
0588      */
0589     m8xx.spmode = spimode | M8xx_SPMODE_EN;
0590   }
0591   return rc;
0592 }
0593 
0594 
0595 /*=========================================================================*\
0596 | Function:                                                                 |
0597 \*-------------------------------------------------------------------------*/
0598 int m8xx_spi_ioctl
0599 (
0600 /*-------------------------------------------------------------------------*\
0601 | Purpose:                                                                  |
0602 |   perform selected ioctl function for SPI                                 |
0603 +---------------------------------------------------------------------------+
0604 | Input Parameters:                                                         |
0605 \*-------------------------------------------------------------------------*/
0606  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0607  int                 cmd,                /* ioctl command code             */
0608  void               *arg                 /* additional argument array      */
0609 )
0610 /*-------------------------------------------------------------------------*\
0611 | Return Value:                                                             |
0612 |    rtems_status_code                                                      |
0613 \*=========================================================================*/
0614 {
0615   int ret_val = -1;
0616 
0617   switch(cmd) {
0618   case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0619     ret_val =
0620       -m8xx_spi_set_tfr_mode(bh,
0621                 (const rtems_libi2c_tfr_mode_t *)arg);
0622     break;
0623   case RTEMS_LIBI2C_IOCTL_READ_WRITE:
0624     ret_val =
0625       m8xx_spi_read_write_bytes(bh,
0626                 ((rtems_libi2c_read_write_t *)arg)->rd_buf,
0627                 ((rtems_libi2c_read_write_t *)arg)->wr_buf,
0628                 ((rtems_libi2c_read_write_t *)arg)->byte_cnt);
0629     break;
0630   default:
0631     ret_val = -RTEMS_NOT_DEFINED;
0632     break;
0633   }
0634   return ret_val;
0635 }
0636 
0637 /*=========================================================================*\
0638 | Board-specific adaptation functions                                       |
0639 \*=========================================================================*/
0640 
0641 /*=========================================================================*\
0642 | Function:                                                                 |
0643 \*-------------------------------------------------------------------------*/
0644 static rtems_status_code bsp_spi_send_start
0645 (
0646 /*-------------------------------------------------------------------------*\
0647 | Purpose:                                                                  |
0648 |   dummy function, SPI has no start condition                              |
0649 +---------------------------------------------------------------------------+
0650 | Input Parameters:                                                         |
0651 \*-------------------------------------------------------------------------*/
0652  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0653 )
0654 /*-------------------------------------------------------------------------*\
0655 | Return Value:                                                             |
0656 |    o = ok or error code                                                   |
0657 \*=========================================================================*/
0658 {
0659   return RTEMS_SUCCESSFUL;
0660 }
0661 
0662 /*=========================================================================*\
0663 | Function:                                                                 |
0664 \*-------------------------------------------------------------------------*/
0665 static rtems_status_code bsp_spi_sel_addr
0666 (
0667 /*-------------------------------------------------------------------------*\
0668 | Purpose:                                                                  |
0669 |   address a slave device on the bus                                       |
0670 +---------------------------------------------------------------------------+
0671 | Input Parameters:                                                         |
0672 \*-------------------------------------------------------------------------*/
0673  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0674  uint32_t addr,                          /* address to send on bus         */
0675  int rw                                  /* 0=write,1=read                 */
0676 )
0677 /*-------------------------------------------------------------------------*\
0678 | Return Value:                                                             |
0679 |    rtems_status_code                                                      |
0680 \*=========================================================================*/
0681 {               
0682 #if defined(PGHPLUS)
0683   pbdat_val = m8xx.pbdat | (PGHPLUS_SPI_PB_DISP4_RS_MSK |
0684                 PGHPLUS_SPI_PB_DISP4_CE_MSK |
0685                 PGHPLUS_SPI_PB_EEP_CE_MSK);
0686   /*
0687    * select given device
0688    */
0689   switch(addr) {
0690   case PGHPLUS_SPI_ADDR_EEPROM:
0691     pbdat_val &= ~PGHPLUS_SPI_PB_EEP_CE_MSK;
0692     break;
0693   case PGHPLUS_SPI_ADDR_DISP4_DATA:
0694     pbdat_val = (m8xx.pbdat
0695           & ~(PGHPLUS_PB_SPI_DISP4_CE_MSK |
0696               PGHPLUS_PB_SPI_DISP4_RS_MSK));
0697     break;
0698   case PGHPLUS_SPI_ADDR_DISP4_CTRL:
0699     pbdat_val = (m8xx.pbdat
0700           & ~(PGHPLUS_PB_SPI_DISP4_CE_MSK)
0701           |   PGHPLUS_PB_SPI_DISP4_RS_MSK);
0702     break;
0703   default:
0704     return RTEMS_INVALID_NUMBER;
0705   }
0706   m8xx_pbdat = pbdat_val
0707 #endif /* PGHPLUS */
0708   return  RTEMS_SUCCESSFUL;
0709 }
0710 
0711 /*=========================================================================*\
0712 | Function:                                                                 |
0713 \*-------------------------------------------------------------------------*/
0714 static rtems_status_code bsp_spi_send_stop
0715 (
0716 /*-------------------------------------------------------------------------*\
0717 | Purpose:                                                                  |
0718 |   deselect SPI                                                            |
0719 +---------------------------------------------------------------------------+
0720 | Input Parameters:                                                         |
0721 \*-------------------------------------------------------------------------*/
0722  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0723 )
0724 /*-------------------------------------------------------------------------*\
0725 | Return Value:                                                             |
0726 |    o = ok or error code                                                   |
0727 \*=========================================================================*/
0728 {
0729 #if defined(DEBUG)
0730   printk("bsp_spi_send_stop called... ");
0731 #endif
0732     m8xx.pbdat = (m8xx.pbdat
0733           | PGHPLUS_PB_SPI_DISP4_CE_MSK
0734           | PGHPLUS_PB_SPI_EEP_CE_MSK);
0735 #if defined(DEBUG)
0736   printk("... exit OK\r\n");
0737 #endif
0738   return RTEMS_SUCCESSFUL;
0739 }
0740 
0741 /*=========================================================================*\
0742 | Function:                                                                 |
0743 \*-------------------------------------------------------------------------*/
0744 static rtems_status_code bsp_spi_init
0745 (
0746 /*-------------------------------------------------------------------------*\
0747 | Purpose:                                                                  |
0748 |   do board specific init:                                                 |
0749 |   - initialize pins for addressing                                        |
0750 |   - register further drivers                                              |
0751 +---------------------------------------------------------------------------+
0752 | Input Parameters:                                                         |
0753 \*-------------------------------------------------------------------------*/
0754  int spi_busno
0755 )
0756 /*-------------------------------------------------------------------------*\
0757 | Return Value:                                                             |
0758 |    o = ok or error code                                                   |
0759 \*=========================================================================*/
0760 {
0761   int ret_code;
0762 
0763 #if defined(DEBUG)
0764   printk("bsp_spi_init called... ");
0765 #endif
0766 
0767   /*
0768    * init port pins used to address/select SPI devices
0769    */
0770 
0771   /*
0772    * set up ports
0773    * LINE      PAR  DIR  DAT
0774    * -----------------------
0775    * EEP_CE     0    1 act-high
0776    * DISP4_CS   0    1 act-high
0777    * DISP4_RS   0    1 active
0778    */
0779 
0780   /* set Port B Pin Assignment Register... */
0781   m8xx.pbpar =
0782     (m8xx.pbpar
0783      & ~(PGHPLUS_PB_SPI_EEP_CE_MSK
0784      | PGHPLUS_PB_SPI_DISP4_CE_MSK
0785      | PGHPLUS_PB_SPI_DISP4_RS_MSK));
0786 
0787     /* set Port B Data Direction Register... */
0788   m8xx.pbdir =
0789     m8xx.pbdir
0790     | PGHPLUS_PB_SPI_EEP_CE_MSK
0791     | PGHPLUS_PB_SPI_DISP4_CE_MSK
0792     | PGHPLUS_PB_SPI_DISP4_RS_MSK;
0793 
0794   /* set Port B Data Register to inactive CE state */
0795   m8xx.pbdat =
0796     m8xx.pbdat
0797     | PGHPLUS_PB_SPI_DISP4_CE_MSK
0798     | PGHPLUS_PB_SPI_DISP4_RS_MSK;
0799 
0800   /*
0801    * register devices
0802    */
0803   ret_code = rtems_libi2c_register_drv("disp",
0804                        disp_hcms29xx_driver_descriptor,
0805                        spi_busno,PGHPLUS_SPI_ADDR_DISP4);
0806   if (ret_code < 0) {
0807     return -ret_code;
0808   }
0809 
0810 #if defined(DEBUG)
0811   printk("... exit OK\r\n");
0812 #endif
0813   return RTEMS_SUCCESSFUL;
0814 }
0815 
0816 /*=========================================================================*\
0817 | list of handlers                                                          |
0818 \*=========================================================================*/
0819 
0820 rtems_libi2c_bus_ops_t bsp_spi_ops = {
0821   init:             m8xx_spi_init,
0822   send_start:       bsp_spi_send_start,
0823   send_stop:        bsp_spi_send_stop,
0824   send_addr:        bsp_spi_sel_addr,
0825   read_bytes:       m8xx_spi_read_bytes,
0826   write_bytes:      m8xx_spi_write_bytes,
0827   ioctl:            m8xx_spi_ioctl
0828 };
0829 
0830 static m8xx_spi_desc_t bsp_spi_bus_desc = {
0831   {/* public fields */
0832     ops:    &bsp_spi_ops,
0833     size:   sizeof(bsp_spi_bus_desc)
0834   },
0835   { /* our private fields */
0836     initialized: FALSE
0837   }
0838 };
0839 
0840 /*=========================================================================*\
0841 | initialization                                                            |
0842 \*=========================================================================*/
0843 
0844 /*=========================================================================*\
0845 | Function:                                                                 |
0846 \*-------------------------------------------------------------------------*/
0847 rtems_status_code bsp_register_spi
0848 (
0849 /*-------------------------------------------------------------------------*\
0850 | Purpose:                                                                  |
0851 |   register SPI bus and devices                                            |
0852 +---------------------------------------------------------------------------+
0853 | Input Parameters:                                                         |
0854 \*-------------------------------------------------------------------------*/
0855  void                                    /* <none>                         */
0856 )
0857 /*-------------------------------------------------------------------------*\
0858 | Return Value:                                                             |
0859 |    0 or error code                                                        |
0860 \*=========================================================================*/
0861 {
0862   int ret_code;
0863   int spi_busno;
0864 
0865   /*
0866    * init I2C library (if not already done)
0867    */
0868   rtems_libi2c_initialize ();
0869 
0870 
0871   /*
0872    * register SPI bus
0873    */
0874   ret_code = rtems_libi2c_register_bus("/dev/spi",
0875                        &(bsp_spi_bus_desc.bus_desc));
0876   if (ret_code < 0) {
0877     return -ret_code;
0878   }
0879   spi_busno = ret_code;
0880 
0881   bsp_spi_init(spi_busno);
0882   /*
0883    * FIXME: further drivers, when available
0884    */
0885   return RTEMS_SUCCESSFUL;
0886 }
0887 
0888