Back to home page

LXR

 
 

    


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

0001 /**
0002  * @file
0003  *
0004  * @ingroup raspberrypi_spi
0005  *
0006  * @brief Support for the SPI bus on the Raspberry Pi GPIO P1 header (model A/B)
0007  *        and GPIO J8 header on model B+.
0008  */
0009 
0010 /*
0011  *  Copyright (c) 2014-2015 Andre Marques <andre.lousa.marques at gmail.com>
0012  *
0013  *  The license and distribution terms for this file may be
0014  *  found in the file LICENSE in this distribution or at
0015  *  http://www.rtems.org/license/LICENSE.
0016  */
0017 
0018 /*
0019  * STATUS:
0020  * - Bi-directional mode untested
0021  * - Write-only devices not supported
0022  */
0023 
0024 #include <bsp.h>
0025 #include <bsp/raspberrypi.h>
0026 #include <bsp/gpio.h>
0027 #include <bsp/rpi-gpio.h>
0028 #include <bsp/irq.h>
0029 #include <bsp/spi.h>
0030 #include <assert.h>
0031 
0032 #define SPI_POLLING(condition)                  \
0033   while ( condition ) {                         \
0034     ;                                           \
0035   }
0036 
0037 /**
0038  * @brief Object containing the SPI bus configuration settings.
0039  *
0040  * Encapsulates the current SPI bus configuration.
0041  */
0042 typedef struct
0043 {
0044   int initialized;
0045   uint8_t bytes_per_char;
0046 
0047   /* Shift to be applied on data transfers with
0048    * least significative bit first (LSB) devices. */
0049   uint8_t bit_shift;
0050   uint32_t dummy_char;
0051   uint32_t current_slave_addr;
0052   rtems_id task_id;
0053   int irq_write;
0054 } rpi_spi_softc_t;
0055 
0056 /**
0057  * @brief Object containing the SPI bus description.
0058  *
0059  * Encapsulates the current SPI bus description.
0060  */
0061 typedef struct
0062 {
0063   rtems_libi2c_bus_t bus_desc;
0064   rpi_spi_softc_t softc;
0065 } rpi_spi_desc_t;
0066 
0067 /* If set to FALSE uses 3-wire SPI, with 2 separate data lines (MOSI and MISO),
0068  * if set to TRUE uses 2-wire SPI, where the MOSI data line doubles as the
0069  * slave out (SO) and slave in (SI) data lines. */
0070 static bool bidirectional = false;
0071 
0072 /* Calculates a clock divider to be used with the GPU core clock rate
0073  * to set a SPI clock rate the closest (<=) to a desired frequency. */
0074 static rtems_status_code rpi_spi_calculate_clock_divider(
0075   uint32_t clock_hz,
0076   uint16_t *clock_divider
0077 ) {
0078   uint16_t divider;
0079   uint32_t clock_rate;
0080 
0081   assert( clock_hz > 0 );
0082 
0083   /* Calculates an initial clock divider. */
0084   divider = GPU_CORE_CLOCK_RATE / clock_hz;
0085 
0086   /* Because the divider must be a power of two (as per the BCM2835 datasheet),
0087    * calculate the next greater power of two. */
0088   --divider;
0089 
0090   divider |= (divider >> 1);
0091   divider |= (divider >> 2);
0092   divider |= (divider >> 4);
0093   divider |= (divider >> 8);
0094 
0095   ++divider;
0096 
0097   clock_rate = GPU_CORE_CLOCK_RATE / divider;
0098 
0099   /* If the resulting clock rate is greater than the desired frequency,
0100    * try the next greater power of two divider. */
0101   while ( clock_rate > clock_hz ) {
0102     divider = (divider << 1);
0103 
0104     clock_rate = GPU_CORE_CLOCK_RATE / divider;
0105   }
0106 
0107   *clock_divider = divider;
0108 
0109   return RTEMS_SUCCESSFUL;
0110 }
0111 
0112 /**
0113  * @brief Set the SPI bus transfer mode.
0114  *
0115  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0116  * @param[in] tfr_mode Pointer to a libi2c API transfer mode data structure.
0117  *
0118  * @retval RTEMS_SUCCESSFUL Successfully setup the bus transfer mode as desired.
0119  * @retval RTEMS_INVALID_NUMBER This can have two meanings:
0120  *                              1. The specified number of bytes per char is not
0121  *                                 8, 16, 24 or 32;
0122  *                              2. @see rpi_spi_calculate_clock_divider()
0123  */
0124 static rtems_status_code rpi_spi_set_tfr_mode(
0125   rtems_libi2c_bus_t *bushdl,
0126   const rtems_libi2c_tfr_mode_t *tfr_mode
0127 ) {
0128   rpi_spi_softc_t *softc_ptr = &(((rpi_spi_desc_t *)(bushdl))->softc);
0129   rtems_status_code sc = RTEMS_SUCCESSFUL;
0130   uint16_t clock_divider;
0131 
0132   /* Set the dummy character. */
0133   softc_ptr->dummy_char = tfr_mode->idle_char;
0134 
0135   /* Calculate the most appropriate clock divider. */
0136   sc = rpi_spi_calculate_clock_divider(tfr_mode->baudrate, &clock_divider);
0137 
0138   if ( sc != RTEMS_SUCCESSFUL ) {
0139     return sc;
0140   }
0141 
0142   /* Set the bus clock divider. */
0143   BCM2835_REG(BCM2835_SPI_CLK) = clock_divider;
0144 
0145   /* Calculate how many bytes each character has.
0146    * Only multiples of 8 bits are accepted for the transaction. */
0147   switch ( tfr_mode->bits_per_char ) {
0148     case 8:
0149     case 16:
0150     case 24:
0151     case 32:
0152       softc_ptr->bytes_per_char = tfr_mode->bits_per_char / 8;
0153       break;
0154 
0155     default:
0156       return RTEMS_INVALID_NUMBER;
0157   }
0158 
0159   /* Check the data mode (most or least significant bit first) and calculate
0160    * the correcting bit shift value to apply on the data before sending. */
0161   if ( tfr_mode->lsb_first ) {
0162     softc_ptr->bit_shift = 32 - tfr_mode->bits_per_char;
0163   }
0164   /* If MSB first. */
0165   else {
0166     softc_ptr->bit_shift = 0;
0167   }
0168 
0169   /* Set SPI clock polarity.
0170    * If clock_inv is TRUE, the clock is active high.*/
0171   if ( tfr_mode->clock_inv ) {
0172     /* Rest state of clock is low. */
0173     BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 3);
0174   }
0175   else {
0176     /* Rest state of clock is high. */
0177     BCM2835_REG(BCM2835_SPI_CS) |= (1 << 3);
0178   }
0179 
0180   /* Set SPI clock phase.
0181    * If clock_phs is true, clock starts toggling
0182    * at the start of the data transfer. */
0183   if ( tfr_mode->clock_phs ) {
0184     /* First SCLK transition at beginning of data bit. */
0185     BCM2835_REG(BCM2835_SPI_CS) |= (1 << 2);
0186   }
0187   else {
0188     /* First SCLK transition at middle of data bit. */
0189     BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 2);
0190   }
0191 
0192   return sc;
0193 }
0194 
0195 /**
0196  * @brief Reads/writes to/from the SPI bus.
0197  *
0198  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0199  * @param[in] rd_buf Read buffer. If not NULL the function will read from
0200  *                   the bus and store the read on this buffer.
0201  * @param[in] wr_buf Write buffer. If not NULL the function will write the
0202  *                   contents of this buffer to the bus.
0203  * @param[in] buffer_size Size of the non-NULL buffer.
0204  *
0205  * @retval -1 Could not send/receive data to/from the bus.
0206  * @retval >=0 The number of bytes read/written.
0207  */
0208 static int rpi_spi_read_write(
0209   rtems_libi2c_bus_t * bushdl,
0210   unsigned char *rd_buf,
0211   const unsigned char *wr_buf,
0212   int buffer_size
0213 ) {
0214   rpi_spi_softc_t *softc_ptr = &(((rpi_spi_desc_t *)(bushdl))->softc);
0215 
0216   uint8_t bytes_per_char = softc_ptr->bytes_per_char;
0217   uint8_t bit_shift =  softc_ptr->bit_shift;
0218   uint32_t dummy_char = softc_ptr->dummy_char;
0219 
0220   uint32_t bytes_sent = buffer_size;
0221   uint32_t fifo_data;
0222 
0223   /* Clear SPI bus FIFOs. */
0224   BCM2835_REG(BCM2835_SPI_CS) |= (3 << 4);
0225 
0226   /* Set SPI transfer active. */
0227   BCM2835_REG(BCM2835_SPI_CS) |= (1 << 7);
0228 
0229   /* If using the SPI bus in interrupt-driven mode. */
0230 #if SPI_IO_MODE == 1
0231   softc_ptr->irq_write = 1;
0232 
0233   BCM2835_REG(BCM2835_SPI_CS) |= (1 << 9);
0234 
0235   if ( rtems_event_transient_receive(RTEMS_WAIT, 0) != RTEMS_SUCCESSFUL ) {
0236     rtems_event_transient_clear();
0237 
0238     return -1;
0239   }
0240 
0241   /* If using the bus in polling mode. */
0242 #else
0243   /* Poll TXD bit until there is space to write at least one byte
0244    * on the TX FIFO. */
0245   SPI_POLLING((BCM2835_REG(BCM2835_SPI_CS) & (1 << 18)) == 0);
0246 #endif
0247 
0248   /* While there is data to be transferred. */
0249   while ( buffer_size >= bytes_per_char ) {
0250     /* If reading from the bus, send a dummy character to the device. */
0251     if ( rd_buf != NULL ) {
0252       BCM2835_REG(BCM2835_SPI_FIFO) = dummy_char;
0253     }
0254     /* If writing to the bus, move the buffer data to the TX FIFO. */
0255     else {
0256       switch ( bytes_per_char ) {
0257         case 1:
0258           BCM2835_REG(BCM2835_SPI_FIFO) = (((*wr_buf) & 0xFF) << bit_shift);
0259           break;
0260 
0261         case 2:
0262           BCM2835_REG(BCM2835_SPI_FIFO) = (((*wr_buf) & 0xFFFF) << bit_shift);
0263           break;
0264 
0265         case 3:
0266           BCM2835_REG(BCM2835_SPI_FIFO) = (((*wr_buf) & 0xFFFFFF) << bit_shift);
0267           break;
0268 
0269         case 4:
0270           BCM2835_REG(BCM2835_SPI_FIFO) = ((*wr_buf) << bit_shift);
0271           break;
0272 
0273         default:
0274           return -1;
0275       }
0276 
0277       wr_buf += bytes_per_char;
0278 
0279       buffer_size -= bytes_per_char;
0280     }
0281 
0282     /* If using bi-directional SPI. */
0283     if ( bidirectional ) {
0284       /* Change bus direction to read from the slave device. */
0285       BCM2835_REG(BCM2835_SPI_CS) |= (1 << 12);
0286     }
0287 
0288     /* If using the SPI bus in interrupt-driven mode. */
0289 #if SPI_IO_MODE == 1
0290     softc_ptr->irq_write = 0;
0291 
0292     BCM2835_REG(BCM2835_SPI_CS) |= (1 << 9);
0293 
0294     if ( rtems_event_transient_receive(RTEMS_WAIT, 0) != RTEMS_SUCCESSFUL ) {
0295       rtems_event_transient_clear();
0296 
0297       return -1;
0298     }
0299 
0300     /* If using the bus in polling mode. */
0301 #else
0302     /* Poll the Done bit until the data transfer is complete. */
0303     SPI_POLLING((BCM2835_REG(BCM2835_SPI_CS) & (1 << 16)) == 0);
0304 
0305     /* Poll the RXD bit until there is at least one byte
0306      * on the RX FIFO to be read. */
0307     SPI_POLLING((BCM2835_REG(BCM2835_SPI_CS) & (1 << 17)) == 0);
0308 #endif
0309 
0310     /* If writing to the bus, read the dummy char sent by the slave device. */
0311     if ( rd_buf == NULL ) {
0312       fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFF;
0313     }
0314 
0315     /* If reading from the bus, retrieve data from the RX FIFO and
0316      * store it on the buffer. */
0317     if ( rd_buf != NULL ) {
0318       switch ( bytes_per_char ) {
0319         case 1:
0320           fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFF;
0321           (*rd_buf) = (fifo_data >> bit_shift);
0322           break;
0323 
0324         case 2:
0325           fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFFFF;
0326           (*rd_buf) = (fifo_data >> bit_shift);
0327           break;
0328 
0329         case 3:
0330           fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFFFFFF;
0331           (*rd_buf) = (fifo_data >> bit_shift);
0332           break;
0333 
0334         case 4:
0335           fifo_data = BCM2835_REG(BCM2835_SPI_FIFO);
0336           (*rd_buf) = (fifo_data >> bit_shift);
0337           break;
0338 
0339         default:
0340           return -1;
0341       }
0342 
0343       rd_buf += bytes_per_char;
0344 
0345       buffer_size -= bytes_per_char;
0346     }
0347 
0348     /* If using bi-directional SPI. */
0349     if ( bidirectional ) {
0350       /* Restore bus direction to write to the slave. */
0351       BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 12);
0352     }
0353   }
0354 
0355   /* If using the SPI bus in interrupt-driven mode. */
0356 #if SPI_IO_MODE == 1
0357   softc_ptr->irq_write = 1;
0358 
0359   BCM2835_REG(BCM2835_SPI_CS) |= (1 << 9);
0360 
0361   if ( rtems_event_transient_receive(RTEMS_WAIT, 0) != RTEMS_SUCCESSFUL ) {
0362     rtems_event_transient_clear();
0363 
0364     return -1;
0365   }
0366 
0367   /* If using the bus in polling mode. */
0368 #else
0369   /* Poll the Done bit until the data transfer is complete. */
0370   SPI_POLLING((BCM2835_REG(BCM2835_SPI_CS) & (1 << 16)) == 0);
0371 #endif
0372 
0373   bytes_sent -= buffer_size;
0374 
0375   return bytes_sent;
0376 }
0377 
0378 /**
0379  * @brief Handler function that is called on any SPI interrupt.
0380  *
0381  *        There are 2 situations that can generate an interrupt:
0382  *
0383  *        1. Transfer (read/write) complete;
0384  *        2. RX FIFO full.
0385  *
0386  *        Because the 2. situation is not useful to many applications,
0387  *        the only interrupt that is generated and handled is the
0388  *        transfer complete interrupt.
0389  *
0390  *        The objective of the handler is then, depending on the transfer
0391  *        context (reading or writing on the bus), to check if there is enough
0392  *        space available on the TX FIFO to send data over the bus (if writing)
0393  *        or if the slave device has sent enough data to be fetched from the
0394  *        RX FIFO (if reading).
0395  *
0396  *        When any of these two conditions occur, disables further interrupts
0397  *        to be generated and sends a waking event to the transfer task
0398  *        which will allow the following transfer to proceed.
0399  *
0400  * @param[in] arg Void pointer to the bus data structure.
0401  */
0402 #if SPI_IO_MODE == 1
0403 static void spi_handler(void* arg)
0404 {
0405   rpi_spi_softc_t *softc_ptr = (rpi_spi_softc_t *) arg;
0406 
0407   /* If waiting to write to the bus, expect the TXD bit to be set, or
0408    * if waiting to read from the bus, expect the RXD bit to be set
0409    * before sending a waking event to the transfer task. */
0410   if (
0411       ( softc_ptr->irq_write == 1 &&
0412         (BCM2835_REG(BCM2835_SPI_CS) & (1 << 18)) != 0
0413       ) ||
0414       ( softc_ptr->irq_write == 0 &&
0415         (BCM2835_REG(BCM2835_SPI_CS) & (1 << 17)) != 0
0416       )
0417   ) {
0418     /* Disable the SPI interrupt generation when a transfer is complete. */
0419     BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 9);
0420 
0421     /* Allow the transfer process to continue. */
0422     rtems_event_transient_send(softc_ptr->task_id);
0423   }
0424 }
0425 #endif
0426 
0427 /**
0428  * @brief Low level function to initialize the SPI bus.
0429  *        This function is used by the libi2c API.
0430  *
0431  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0432  *
0433  * @retval RTEMS_SUCCESSFUL SPI bus successfully initialized.
0434  * @retval Any other status code @see rtems_interrupt_handler_install().
0435  */
0436 static rtems_status_code rpi_libi2c_spi_init(rtems_libi2c_bus_t * bushdl)
0437 {
0438   rpi_spi_softc_t *softc_ptr = &(((rpi_spi_desc_t *)(bushdl))->softc);
0439   rtems_status_code sc = RTEMS_SUCCESSFUL;
0440 
0441   if ( softc_ptr->initialized == 1 ) {
0442     return sc;
0443   }
0444 
0445   softc_ptr->initialized = 1;
0446 
0447   /* If using the SPI bus in interrupt-driven mode. */
0448 #if SPI_IO_MODE == 1
0449   softc_ptr->task_id = rtems_task_self();
0450 
0451   sc = rtems_interrupt_handler_install(
0452          BCM2835_IRQ_ID_SPI,
0453          NULL,
0454          RTEMS_INTERRUPT_UNIQUE,
0455          (rtems_interrupt_handler) spi_handler,
0456          softc_ptr
0457        );
0458 #endif
0459 
0460   return sc;
0461 }
0462 
0463 /**
0464  * @brief Low level function that would send a start condition over an I2C bus.
0465  *        As it is not required to access a SPI bus it is here just to satisfy
0466  *        the libi2c API, which requires this function.
0467  *
0468  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0469  *
0470  * @retval RTEMS_SUCCESSFUL
0471  */
0472 static rtems_status_code rpi_libi2c_spi_send_start(rtems_libi2c_bus_t * bushdl)
0473 {
0474   return RTEMS_SUCCESSFUL;
0475 }
0476 
0477 /**
0478  * @brief Low level function that terminates a SPI transfer.
0479  *        It stops the SPI transfer and unselects the current SPI slave device.
0480  *        This function is used by the libi2c API.
0481  *
0482  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0483  *
0484  * @retval RTEMS_SUCCESSFUL The slave device has been successfully unselected.
0485  * @retval RTEMS_INVALID_ADDRESS The stored slave address is neither 0 or 1.
0486  */
0487 static rtems_status_code rpi_libi2c_spi_stop(rtems_libi2c_bus_t * bushdl)
0488 {
0489   rpi_spi_softc_t *softc_ptr = &(((rpi_spi_desc_t *)(bushdl))->softc);
0490 
0491   uint32_t addr = softc_ptr->current_slave_addr;
0492   uint32_t chip_select_bit = 21 + addr;
0493 
0494   /* Set SPI transfer as not active. */
0495   BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 7);
0496 
0497   /* Unselect the active SPI slave. */
0498   switch ( addr ) {
0499     case 0:
0500     case 1:
0501       BCM2835_REG(BCM2835_SPI_CS) |= (1 << chip_select_bit);
0502 
0503       break;
0504 
0505     default:
0506       return RTEMS_INVALID_ADDRESS;
0507   }
0508 
0509   return RTEMS_SUCCESSFUL;
0510 }
0511 
0512 /**
0513  * @brief Low level function which addresses a SPI slave device.
0514  *        This function is used by the libi2c API.
0515  *
0516  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0517  * @param[in] addr SPI slave select line address (0 for CE0 or 1 for CE1).
0518  * @param[in] rw This values is unnecessary to address a SPI device and its
0519  *               presence here is only to fulfill a libi2c requirement.
0520  *
0521  * @retval RTEMS_SUCCESSFUL The slave device has been successfully addressed.
0522  * @retval RTEMS_INVALID_ADDRESS The received address is neither 0 or 1.
0523  */
0524 static rtems_status_code rpi_libi2c_spi_send_addr(
0525   rtems_libi2c_bus_t * bushdl,
0526   uint32_t addr,
0527   int rw
0528 ) {
0529   rpi_spi_softc_t *softc_ptr = &(((rpi_spi_desc_t *)(bushdl))->softc);
0530 
0531   /* Calculates the bit corresponding to the received address
0532    * on the SPI control register. */
0533   uint32_t chip_select_bit = 21 + addr;
0534 
0535   /* Save which slave will be currently addressed,
0536    * so it can be unselected later. */
0537   softc_ptr->current_slave_addr = addr;
0538 
0539   /* Select one of the two available SPI slave address lines. */
0540   switch ( addr ) {
0541     case 0:
0542     case 1:
0543       BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << chip_select_bit);
0544       break;
0545 
0546     default:
0547       return RTEMS_INVALID_ADDRESS;
0548   }
0549 
0550   return RTEMS_SUCCESSFUL;
0551 }
0552 
0553 /**
0554  * @brief Low level function that reads a number of bytes from the SPI bus
0555  *        on to a buffer.
0556  *        This function is used by the libi2c API.
0557  *
0558  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0559  * @param[in] bytes Buffer where the data read from the bus will be stored.
0560  * @param[in] nbytes Number of bytes to be read from the bus to the bytes buffer.
0561  *
0562  * @retval @see rpi_spi_read_write().
0563  */
0564 static int rpi_libi2c_spi_read_bytes(
0565   rtems_libi2c_bus_t * bushdl,
0566   unsigned char *bytes,
0567   int nbytes
0568 ) {
0569   return rpi_spi_read_write(bushdl, bytes, NULL, nbytes);
0570 }
0571 
0572 /**
0573  * @brief Low level function that writes a number of bytes from a buffer
0574  *        to the SPI bus.
0575  *        This function is used by the libi2c API.
0576  *
0577  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0578  * @param[in] bytes Buffer with data to send over the SPI bus.
0579  * @param[in] nbytes Number of bytes to be written from the bytes buffer
0580                      to the bus.
0581  *
0582  * @retval @see rpi_spi_read_write().
0583  */
0584 static int rpi_libi2c_spi_write_bytes(
0585   rtems_libi2c_bus_t * bushdl,
0586   unsigned char *bytes,
0587   int nbytes
0588 ) {
0589   return rpi_spi_read_write(bushdl, NULL, bytes, nbytes);
0590 }
0591 
0592 /**
0593  * @brief Low level function that is used to perform ioctl
0594  *        operations on the bus. Currently only setups
0595  *        the bus transfer mode.
0596  *        This function is used by the libi2c API.
0597  *
0598  * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
0599  * @param[in] cmd IOCTL request command.
0600  * @param[in] arg Arguments needed to fulfill the requested IOCTL command.
0601  *
0602  * @retval -1 Unknown request command.
0603  * @retval >=0 @see rpi_spi_set_tfr_mode().
0604  */
0605 static int rpi_libi2c_spi_ioctl(rtems_libi2c_bus_t * bushdl, int cmd, void *arg)
0606 {
0607   switch ( cmd ) {
0608     case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0609       return rpi_spi_set_tfr_mode(
0610                bushdl,
0611                (const rtems_libi2c_tfr_mode_t *)arg
0612              );
0613     default:
0614       return -1;
0615   }
0616 
0617   return 0;
0618 }
0619 
0620 static rtems_libi2c_bus_ops_t rpi_spi_ops = {
0621   .init = rpi_libi2c_spi_init,
0622   .send_start = rpi_libi2c_spi_send_start,
0623   .send_stop = rpi_libi2c_spi_stop,
0624   .send_addr = rpi_libi2c_spi_send_addr,
0625   .read_bytes = rpi_libi2c_spi_read_bytes,
0626   .write_bytes = rpi_libi2c_spi_write_bytes,
0627   .ioctl = rpi_libi2c_spi_ioctl
0628 };
0629 
0630 static rpi_spi_desc_t rpi_spi_bus_desc = {
0631   {
0632     .ops = &rpi_spi_ops,
0633     .size = sizeof(rpi_spi_bus_desc)
0634   },
0635   {
0636     .initialized = 0
0637   }
0638 };
0639 
0640 int rpi_spi_init(bool bidirectional_mode)
0641 {
0642   /* Initialize the libi2c API. */
0643   rtems_libi2c_initialize();
0644 
0645   /* Enable the SPI interface on the Raspberry Pi. */
0646   rtems_gpio_initialize();
0647 
0648   assert ( rpi_gpio_select_spi() == RTEMS_SUCCESSFUL );
0649 
0650   bidirectional = bidirectional_mode;
0651 
0652   /* Clear SPI control register and clear SPI FIFOs. */
0653   BCM2835_REG(BCM2835_SPI_CS) = (3 << 4);
0654 
0655   /* Register the SPI bus. */
0656   return rtems_libi2c_register_bus("/dev/spi", &(rpi_spi_bus_desc.bus_desc));
0657 }