Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * RTEMS support for MPC83xx
0005  *
0006  * This file contains the MPC83xx SPI driver.
0007  * NOTE: it uses the same API as the I2C driver.
0008  */
0009 
0010 /*
0011  * Copyright (c) 2007 embedded brains GmbH & Co. KG
0012  *
0013  * Redistribution and use in source and binary forms, with or without
0014  * modification, are permitted provided that the following conditions
0015  * are met:
0016  * 1. Redistributions of source code must retain the above copyright
0017  *    notice, this list of conditions and the following disclaimer.
0018  * 2. Redistributions in binary form must reproduce the above copyright
0019  *    notice, this list of conditions and the following disclaimer in the
0020  *    documentation and/or other materials provided with the distribution.
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0032  * POSSIBILITY OF SUCH DAMAGE.
0033  */
0034 
0035 #include <stdlib.h>
0036 #include <bsp.h>
0037 #include <bsp/irq.h>
0038 #include <mpc83xx/mpc83xx.h>
0039 #include <mpc83xx/mpc83xx_spidrv.h>
0040 #include <rtems/error.h>
0041 #include <rtems/bspIo.h>
0042 #include <errno.h>
0043 #include <rtems/libi2c.h>
0044 
0045 #undef DEBUG
0046 
0047 /*=========================================================================*\
0048 | Function:                                                                 |
0049 \*-------------------------------------------------------------------------*/
0050 static rtems_status_code mpc83xx_spi_baud_to_mode
0051 (
0052 /*-------------------------------------------------------------------------*\
0053 | Purpose:                                                                  |
0054 |   determine proper divider value                                          |
0055 +---------------------------------------------------------------------------+
0056 | Input Parameters:                                                         |
0057 \*-------------------------------------------------------------------------*/
0058  uint32_t baudrate,                      /* desired baudrate               */
0059  uint32_t base_frq,                      /* input frequency                */
0060  uint32_t *spimode                       /* result value                   */
0061 )
0062 /*-------------------------------------------------------------------------*\
0063 | Return Value:                                                             |
0064 |    o = ok or error code                                                   |
0065 \*=========================================================================*/
0066 {
0067   uint32_t divider;
0068   uint32_t tmpmode = 0;
0069   /*
0070    * determine clock divider and DIV16 bit
0071    */
0072   divider = (base_frq+baudrate-1)/baudrate;
0073   if (divider > 64) {
0074     tmpmode = MPC83XX_SPIMODE_DIV16;
0075     divider /= 16;
0076   }
0077   if ((divider <  1) ||
0078       (divider > 64)) {
0079     return RTEMS_INVALID_NUMBER;
0080   }
0081   else {
0082     tmpmode |= MPC83XX_SPIMODE_PM(divider/4-1);
0083   }
0084   *spimode = tmpmode;
0085   return RTEMS_SUCCESSFUL;
0086 }
0087 
0088 /*=========================================================================*\
0089 | Function:                                                                 |
0090 \*-------------------------------------------------------------------------*/
0091 static rtems_status_code mpc83xx_spi_char_mode
0092 (
0093 /*-------------------------------------------------------------------------*\
0094 | Purpose:                                                                  |
0095 |   determine proper value for character size                               |
0096 +---------------------------------------------------------------------------+
0097 | Input Parameters:                                                         |
0098 \*-------------------------------------------------------------------------*/
0099  mpc83xx_spi_softc_t *softc_ptr,         /* handle                         */
0100  uint32_t bits_per_char,                 /* bits per character             */
0101  bool     lsb_first,                     /* TRUE: send LSB first           */
0102  uint32_t *spimode                       /* result value                   */
0103 )
0104 /*-------------------------------------------------------------------------*\
0105 | Return Value:                                                             |
0106 |    o = ok or error code                                                   |
0107 \*=========================================================================*/
0108 {
0109   uint32_t tmpmode;
0110 
0111   if (bits_per_char == 32) {
0112     tmpmode = 0;
0113     softc_ptr->bytes_per_char = 4;
0114     softc_ptr->bit_shift      = 0;
0115   }
0116   else {
0117     if (lsb_first) {
0118       /*
0119        * non-reversed data (LSB first): 4..16 bits valid
0120        * always aligned to bit 16 of data register
0121        */
0122       if ((bits_per_char >= 4) &&
0123       (bits_per_char <= 16)) {
0124     tmpmode = MPC83XX_SPIMODE_LEN( bits_per_char-1);
0125     softc_ptr->bytes_per_char = (bits_per_char > 8) ? 2 : 1;
0126     softc_ptr->bit_shift      = 16-bits_per_char;
0127       }
0128       else {
0129     return RTEMS_INVALID_NUMBER;
0130       }
0131     }
0132     else {
0133       /*
0134        * reversed data (MSB first): only 8/16/32 bits valid,
0135        * always in lowest bits of data register
0136        */
0137       if (bits_per_char == 8) {
0138     tmpmode = MPC83XX_SPIMODE_LEN(8-1);
0139     softc_ptr->bytes_per_char = 1;
0140     softc_ptr->bit_shift      = 0;
0141       }
0142       else if (bits_per_char == 16) {
0143     tmpmode = MPC83XX_SPIMODE_LEN(16-1);
0144     softc_ptr->bytes_per_char = 2;
0145     softc_ptr->bit_shift      = 0;
0146       }
0147       else {
0148     return RTEMS_INVALID_NUMBER;
0149       }
0150     }
0151   }
0152 
0153   *spimode = tmpmode;
0154   return 0;
0155 }
0156 
0157 /*=========================================================================*\
0158 | Function:                                                                 |
0159 \*-------------------------------------------------------------------------*/
0160 static int mpc83xx_spi_wait
0161 (
0162 /*-------------------------------------------------------------------------*\
0163 | Purpose:                                                                  |
0164 |   wait for spi to become idle                                             |
0165 +---------------------------------------------------------------------------+
0166 | Input Parameters:                                                         |
0167 \*-------------------------------------------------------------------------*/
0168  mpc83xx_spi_softc_t *softc_ptr,          /* handle              */
0169  uint32_t             irq_mask,           /* irq mask to use     */
0170  uint32_t             desired_status,     /* desired status word */
0171  uint32_t             status_mask         /* status word mask    */
0172 )
0173 /*-------------------------------------------------------------------------*\
0174 | Return Value:                                                             |
0175 |    o = ok or error code                                                   |
0176 \*=========================================================================*/
0177 {
0178   uint32_t act_status;
0179   rtems_status_code rc;
0180   uint32_t tout;
0181 
0182 #if defined(DEBUG)
0183   printk("mpc83xx_spi_wait called... ");
0184 #endif
0185   if (softc_ptr->initialized) {
0186     /*
0187      * allow interrupts, when receiver is not empty
0188      */
0189     softc_ptr->reg_ptr->spim = irq_mask;
0190     rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100);
0191     if (rc != RTEMS_SUCCESSFUL) {
0192       return rc;
0193     }
0194   }
0195   else {
0196     tout = 0;
0197     do {
0198       if (tout++ > 1000000) {
0199 #if defined(DEBUG)
0200     printk("... exit with RTEMS_TIMEOUT\r\n");
0201 #endif
0202     return RTEMS_TIMEOUT;
0203       }
0204       /*
0205        * wait for SPI to terminate
0206        */
0207     } while (!(softc_ptr->reg_ptr->spie & MPC83XX_SPIE_NE));
0208   }
0209 
0210   act_status = softc_ptr->reg_ptr->spie;
0211   if ((act_status  & status_mask)!= desired_status) {
0212 #if defined(DEBUG)
0213     printk("... exit with RTEMS_IO_ERROR,"
0214        "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n",
0215        act_status,status_mask,desired_status);
0216 #endif
0217     return RTEMS_IO_ERROR;
0218   }
0219 #if defined(DEBUG)
0220     printk("... exit OK\r\n");
0221 #endif
0222   return RTEMS_SUCCESSFUL;
0223 }
0224 
0225 /*=========================================================================*\
0226 | Function:                                                                 |
0227 \*-------------------------------------------------------------------------*/
0228 static void mpc83xx_spi_irq_handler
0229 (
0230 /*-------------------------------------------------------------------------*\
0231 | Purpose:                                                                  |
0232 |   handle interrupts                                                       |
0233 +---------------------------------------------------------------------------+
0234 | Input Parameters:                                                         |
0235 \*-------------------------------------------------------------------------*/
0236  rtems_irq_hdl_param handle     /* handle, is softc_ptr structure          */
0237 )
0238 /*-------------------------------------------------------------------------*\
0239 | Return Value:                                                             |
0240 |    <none>                                                                 |
0241 \*=========================================================================*/
0242 {
0243   mpc83xx_spi_softc_t *softc_ptr = (mpc83xx_spi_softc_t *)handle;
0244 
0245   /*
0246    * disable interrupt mask
0247    */
0248   softc_ptr->reg_ptr->spim = 0;
0249   if (softc_ptr->initialized) {
0250     rtems_semaphore_release(softc_ptr->irq_sema_id);
0251   }
0252 }
0253 
0254 /*=========================================================================*\
0255 | Function:                                                                 |
0256 \*-------------------------------------------------------------------------*/
0257 static void mpc83xx_spi_irq_on_off
0258 (
0259 /*-------------------------------------------------------------------------*\
0260 | Purpose:                                                                  |
0261 |   enable/disable interrupts (void, handled at different position)         |
0262 +---------------------------------------------------------------------------+
0263 | Input Parameters:                                                         |
0264 \*-------------------------------------------------------------------------*/
0265  const
0266  rtems_irq_connect_data *irq_conn_data   /* irq connect data                */
0267 )
0268 /*-------------------------------------------------------------------------*\
0269 | Return Value:                                                             |
0270 |    <none>                                                                 |
0271 \*=========================================================================*/
0272 {
0273 }
0274 
0275 
0276 /*=========================================================================*\
0277 | Function:                                                                 |
0278 \*-------------------------------------------------------------------------*/
0279 static int mpc83xx_spi_irq_isOn
0280 (
0281 /*-------------------------------------------------------------------------*\
0282 | Purpose:                                                                  |
0283 |   check state of interrupts, void, done differently                       |
0284 +---------------------------------------------------------------------------+
0285 | Input Parameters:                                                         |
0286 \*-------------------------------------------------------------------------*/
0287  const
0288  rtems_irq_connect_data *irq_conn_data  /* irq connect data                */
0289 )
0290 /*-------------------------------------------------------------------------*\
0291 | Return Value:                                                             |
0292 |    TRUE, if enabled                                                       |
0293 \*=========================================================================*/
0294 {
0295   return (TRUE);
0296 }
0297 
0298 /*=========================================================================*\
0299 | Function:                                                                 |
0300 \*-------------------------------------------------------------------------*/
0301 static void mpc83xx_spi_install_irq_handler
0302 (
0303 /*-------------------------------------------------------------------------*\
0304 | Purpose:                                                                  |
0305 |   (un-)install the interrupt handler                                      |
0306 +---------------------------------------------------------------------------+
0307 | Input Parameters:                                                         |
0308 \*-------------------------------------------------------------------------*/
0309  mpc83xx_spi_softc_t *softc_ptr,        /* ptr to control structure        */
0310  int install                            /* TRUE: install, FALSE: remove    */
0311 )
0312 /*-------------------------------------------------------------------------*\
0313 | Return Value:                                                             |
0314 |    <none>                                                                 |
0315 \*=========================================================================*/
0316 {
0317   rtems_status_code rc = RTEMS_SUCCESSFUL;
0318 
0319   rtems_irq_connect_data irq_conn_data = {
0320     softc_ptr->irq_number,
0321     mpc83xx_spi_irq_handler,        /* rtems_irq_hdl           */
0322     (rtems_irq_hdl_param)softc_ptr, /* (rtems_irq_hdl_param)   */
0323     mpc83xx_spi_irq_on_off,         /* (rtems_irq_enable)      */
0324     mpc83xx_spi_irq_on_off,         /* (rtems_irq_disable)     */
0325     mpc83xx_spi_irq_isOn            /* (rtems_irq_is_enabled)  */
0326   };
0327 
0328   /*
0329    * (un-)install handler for SPI device
0330    */
0331   if (install) {
0332     /*
0333      * create semaphore for IRQ synchronization
0334      */
0335     rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
0336                 0,
0337                 RTEMS_FIFO
0338                 | RTEMS_SIMPLE_BINARY_SEMAPHORE,
0339                 0,
0340                 &softc_ptr->irq_sema_id);
0341     if (rc != RTEMS_SUCCESSFUL) {
0342       rtems_panic("SPI: cannot create semaphore");
0343     }
0344     if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
0345       rtems_panic("SPI: cannot install IRQ handler");
0346     }
0347   }
0348   else {
0349     if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) {
0350       rtems_panic("SPI: cannot uninstall IRQ handler");
0351     }
0352     /*
0353      * delete sync semaphore
0354      */
0355     if (softc_ptr->irq_sema_id != 0) {
0356       rc = rtems_semaphore_delete(softc_ptr->irq_sema_id);
0357       if (rc != RTEMS_SUCCESSFUL) {
0358     rtems_panic("SPI: cannot delete semaphore");
0359       }
0360     }
0361   }
0362 }
0363 
0364 /*=========================================================================*\
0365 | Function:                                                                 |
0366 \*-------------------------------------------------------------------------*/
0367 rtems_status_code mpc83xx_spi_init
0368 (
0369 /*-------------------------------------------------------------------------*\
0370 | Purpose:                                                                  |
0371 |   initialize the driver                                                   |
0372 +---------------------------------------------------------------------------+
0373 | Input Parameters:                                                         |
0374 \*-------------------------------------------------------------------------*/
0375  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0376 )
0377 /*-------------------------------------------------------------------------*\
0378 | Return Value:                                                             |
0379 |    o = ok or error code                                                   |
0380 \*=========================================================================*/
0381 {
0382   mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc);
0383 #if defined(DEBUG)
0384   printk("mpc83xx_spi_init called... ");
0385 #endif
0386   /*
0387    * init HW registers:
0388    */
0389   /*
0390    * FIXME: set default mode in SPIM
0391    */
0392 
0393   /*
0394    * init interrupt stuff
0395    */
0396   mpc83xx_spi_install_irq_handler(softc_ptr,TRUE);
0397 
0398   /*
0399    * mark, that we have initialized
0400    */
0401   softc_ptr->initialized = TRUE;
0402 #if defined(DEBUG)
0403   printk("... exit OK\r\n");
0404 #endif
0405   return RTEMS_SUCCESSFUL;
0406 }
0407 
0408 /*=========================================================================*\
0409 | Function:                                                                 |
0410 \*-------------------------------------------------------------------------*/
0411 int mpc83xx_spi_read_write_bytes
0412 (
0413 /*-------------------------------------------------------------------------*\
0414 | Purpose:                                                                  |
0415 |   transmit/receive some bytes from SPI device                             |
0416 +---------------------------------------------------------------------------+
0417 | Input Parameters:                                                         |
0418 \*-------------------------------------------------------------------------*/
0419  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0420  unsigned char *rbuf,                    /* buffer to store bytes          */
0421  const unsigned char *tbuf,              /* buffer to send  bytes          */
0422  int len                                 /* number of bytes to transceive  */
0423 )
0424 /*-------------------------------------------------------------------------*\
0425 | Return Value:                                                             |
0426 |    number of bytes received or (negative) error code                      |
0427 \*=========================================================================*/
0428 {
0429   mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc);
0430   rtems_status_code rc;
0431   int bc = 0;
0432   int bytes_per_char = softc_ptr->bytes_per_char;
0433   int bit_shift      = softc_ptr->bit_shift;
0434   uint32_t spird_val;
0435 
0436 #if defined(DEBUG)
0437   printk("mpc83xx_spi_read_write_bytes called... ");
0438 #endif
0439 
0440   while (len > bytes_per_char-1) {
0441     len -= bytes_per_char;
0442     /*
0443      * mark last byte in SPCOM
0444      */
0445 #if defined(USE_LAST_BIT)
0446     softc_ptr->reg_ptr->spcom = (len < bytes_per_char) ? MPC83XX_SPCOM_LST : 0;
0447 #else
0448     softc_ptr->reg_ptr->spcom = 0;
0449 #endif
0450     if (tbuf == NULL) {
0451       /*
0452        * perform idle char write to read byte
0453        */
0454       softc_ptr->reg_ptr->spitd = softc_ptr->idle_char << bit_shift;
0455     }
0456     else {
0457       switch(bytes_per_char) {
0458       case 1:
0459     softc_ptr->reg_ptr->spitd = (*(uint8_t *)tbuf) << bit_shift;
0460     break;
0461       case 2:
0462     softc_ptr->reg_ptr->spitd = (*(uint16_t *)tbuf) << bit_shift;
0463     break;
0464       case 4:
0465     softc_ptr->reg_ptr->spitd = (*(uint32_t *)tbuf) << bit_shift;
0466     break;
0467       }
0468       tbuf += softc_ptr->bytes_per_char;
0469     }
0470     /*
0471      * wait 'til end of transfer
0472      */
0473 #if defined(USE_LAST_BIT)
0474     rc = mpc83xx_spi_wait(softc_ptr,
0475               ((len == 0)
0476                ? MPC83XX_SPIE_LT
0477                : MPC83XX_SPIE_NE),
0478               ((len == 0)
0479                ? MPC83XX_SPIE_LT
0480                : MPC83XX_SPIE_NF)
0481               | MPC83XX_SPIE_NE,
0482               MPC83XX_SPIE_LT
0483                 | MPC83XX_SPIE_OV
0484               | MPC83XX_SPIE_UN
0485               | MPC83XX_SPIE_NE
0486               | MPC83XX_SPIE_NF);
0487     if (len == 0) {
0488       /*
0489        * clear the "last transfer complete" event
0490        */
0491       softc_ptr->reg_ptr->spie = MPC83XX_SPIE_LT;
0492     }
0493 #else
0494     rc = mpc83xx_spi_wait(softc_ptr,
0495               MPC83XX_SPIE_NE,
0496               MPC83XX_SPIE_NF
0497               | MPC83XX_SPIE_NE,
0498               MPC83XX_SPIE_OV
0499               | MPC83XX_SPIE_UN
0500               | MPC83XX_SPIE_NE
0501               | MPC83XX_SPIE_NF);
0502 #endif
0503     if (rc != RTEMS_SUCCESSFUL) {
0504 #if defined(DEBUG)
0505       printk("... exit rc=%d\r\n",-rc);
0506 #endif
0507       return -rc;
0508     }
0509     spird_val = softc_ptr->reg_ptr->spird;
0510     if (rbuf != NULL) {
0511       switch(bytes_per_char) {
0512       case 1:
0513      (*(uint8_t  *)rbuf) = spird_val >> bit_shift;
0514     break;
0515       case 2:
0516      (*(uint16_t *)rbuf) = spird_val >> bit_shift;
0517     break;
0518       case 4:
0519      (*(uint32_t *)rbuf) = spird_val >> bit_shift;
0520     break;
0521       }
0522       rbuf += bytes_per_char;
0523     }
0524     bc += bytes_per_char;
0525   }
0526 #if defined(DEBUG)
0527   printk("... exit OK, rc=%d\r\n",bc);
0528 #endif
0529   return bc;
0530 }
0531 
0532 /*=========================================================================*\
0533 | Function:                                                                 |
0534 \*-------------------------------------------------------------------------*/
0535 int mpc83xx_spi_read_bytes
0536 (
0537 /*-------------------------------------------------------------------------*\
0538 | Purpose:                                                                  |
0539 |   receive some bytes from SPI device                                      |
0540 +---------------------------------------------------------------------------+
0541 | Input Parameters:                                                         |
0542 \*-------------------------------------------------------------------------*/
0543  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0544  unsigned char *buf,                     /* buffer to store bytes          */
0545  int len                                 /* number of bytes to receive     */
0546 )
0547 /*-------------------------------------------------------------------------*\
0548 | Return Value:                                                             |
0549 |    number of bytes received or (negative) error code                      |
0550 \*=========================================================================*/
0551 {
0552   return mpc83xx_spi_read_write_bytes(bh,buf,NULL,len);
0553 }
0554 
0555 /*=========================================================================*\
0556 | Function:                                                                 |
0557 \*-------------------------------------------------------------------------*/
0558 int mpc83xx_spi_write_bytes
0559 (
0560 /*-------------------------------------------------------------------------*\
0561 | Purpose:                                                                  |
0562 |   send some bytes to SPI device                                           |
0563 +---------------------------------------------------------------------------+
0564 | Input Parameters:                                                         |
0565 \*-------------------------------------------------------------------------*/
0566  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0567  unsigned char *buf,                     /* buffer to send                 */
0568  int len                                 /* number of bytes to send        */
0569 
0570 )
0571 /*-------------------------------------------------------------------------*\
0572 | Return Value:                                                             |
0573 |    number of bytes sent or (negative) error code                          |
0574 \*=========================================================================*/
0575 {
0576   return mpc83xx_spi_read_write_bytes(bh,NULL,buf,len);
0577 }
0578 
0579 /*=========================================================================*\
0580 | Function:                                                                 |
0581 \*-------------------------------------------------------------------------*/
0582 rtems_status_code mpc83xx_spi_set_tfr_mode
0583 (
0584 /*-------------------------------------------------------------------------*\
0585 | Purpose:                                                                  |
0586 |   set SPI to desired baudrate/clock mode/character mode                   |
0587 +---------------------------------------------------------------------------+
0588 | Input Parameters:                                                         |
0589 \*-------------------------------------------------------------------------*/
0590  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0591  const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info             */
0592 )
0593 /*-------------------------------------------------------------------------*\
0594 | Return Value:                                                             |
0595 |    rtems_status_code                                                      |
0596 \*=========================================================================*/
0597 {
0598   mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc);
0599   uint32_t spimode_baud,spimode;
0600   rtems_status_code rc = RTEMS_SUCCESSFUL;
0601 
0602   /* Set idle character */
0603   softc_ptr->idle_char = tfr_mode->idle_char;
0604 
0605   /*
0606    * FIXME: set proper mode
0607    */
0608   if (rc == RTEMS_SUCCESSFUL) {
0609     rc = mpc83xx_spi_baud_to_mode(tfr_mode->baudrate,
0610                   softc_ptr->base_frq,
0611                   &spimode_baud);
0612   }
0613   if (rc == RTEMS_SUCCESSFUL) {
0614     rc = mpc83xx_spi_char_mode(softc_ptr,
0615                    tfr_mode->bits_per_char,
0616                    tfr_mode->lsb_first,
0617                    &spimode);
0618   }
0619   if (rc == RTEMS_SUCCESSFUL) {
0620     spimode |= spimode_baud;
0621     spimode |= MPC83XX_SPIMODE_M_S; /* set master mode */
0622     if (!tfr_mode->lsb_first) {
0623       spimode |= MPC83XX_SPIMODE_REV;
0624     }
0625     if (tfr_mode->clock_inv) {
0626       spimode |= MPC83XX_SPIMODE_CI;
0627     }
0628     if (tfr_mode->clock_phs) {
0629       spimode |= MPC83XX_SPIMODE_CP;
0630     }
0631   }
0632 
0633   if (rc == RTEMS_SUCCESSFUL) {
0634     /*
0635      * disable SPI
0636      */
0637     softc_ptr->reg_ptr->spmode &= ~MPC83XX_SPIMODE_EN;
0638     /*
0639      * set new mode and reenable SPI
0640      */
0641     softc_ptr->reg_ptr->spmode = spimode | MPC83XX_SPIMODE_EN;
0642   }
0643   return rc;
0644 }
0645 
0646 
0647 /*=========================================================================*\
0648 | Function:                                                                 |
0649 \*-------------------------------------------------------------------------*/
0650 int mpc83xx_spi_ioctl
0651 (
0652 /*-------------------------------------------------------------------------*\
0653 | Purpose:                                                                  |
0654 |   perform selected ioctl function for SPI                                 |
0655 +---------------------------------------------------------------------------+
0656 | Input Parameters:                                                         |
0657 \*-------------------------------------------------------------------------*/
0658  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0659  int                 cmd,                /* ioctl command code             */
0660  void               *arg                 /* additional argument array      */
0661 )
0662 /*-------------------------------------------------------------------------*\
0663 | Return Value:                                                             |
0664 |    rtems_status_code                                                      |
0665 \*=========================================================================*/
0666 {
0667   int ret_val = -1;
0668 
0669   switch(cmd) {
0670   case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0671     ret_val =
0672       -mpc83xx_spi_set_tfr_mode(bh,
0673                 (const rtems_libi2c_tfr_mode_t *)arg);
0674     break;
0675   case RTEMS_LIBI2C_IOCTL_READ_WRITE:
0676     ret_val =
0677       mpc83xx_spi_read_write_bytes(bh,
0678                    ((rtems_libi2c_read_write_t *)arg)->rd_buf,
0679                    ((rtems_libi2c_read_write_t *)arg)->wr_buf,
0680                    ((rtems_libi2c_read_write_t *)arg)->byte_cnt);
0681     break;
0682   default:
0683     ret_val = -RTEMS_NOT_DEFINED;
0684     break;
0685   }
0686   return ret_val;
0687 }
0688 
0689 
0690