1 /*
2  * Copyright (c) 2015-2019, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*!*****************************************************************************
33  *  @file       SPICC32XXDMA.h
34  *
35  *  @brief      SPI driver implementation for a CC32XX SPI controller using the
36  *              micro DMA controller.
37  *
38  *  The SPI header file should be included in an application as follows:
39  *  @code
40  *  #include <ti/drivers/SPI.h>
41  *  #include <ti/drivers/spi/SPICC32XXDMA.h>
42  *  @endcode
43  *
44  *  Refer to @ref SPI.h for a complete description of APIs & example of use.
45  *
46  *  This SPI driver implementation is designed to operate on a CC32XX SPI
47  *  controller using a micro DMA controller.
48  *
49  *  @warning This driver does not support queueing multiple SPI transactions.
50  *
51  *  ## Frame Formats #
52  *  This SPI controller supports 4 phase & polarity formats. Refer to the device
53  *  specific data sheets & technical reference manuals for specifics on each
54  *  format.
55  *
56  *  ## SPI Chip Select #
57  *  This SPI controller supports a hardware chip select pin. Refer to the
58  *  device's user manual on how this hardware chip select pin behaves in regards
59  *  to the SPI frame format.
60  *
61  *  <table>
62  *  <tr>
63  *  <th>Chip select type</th>
64  *  <th>SPI_MASTER mode</th>
65  *  <th>SPI_SLAVE mode</th>
66  *  </tr>
67  *  <tr>
68  *  <td>Hardware chip select</td>
69  *  <td>No action is needed by the application to select the peripheral.</td>
70  *  <td>See the device documentation on it's chip select requirements.</td>
71  *  </tr>
72  *  <tr>
73  *  <td>Software chip select</td>
74  *  <td>The application is responsible to ensure that correct SPI slave is
75  *      selected before performing a SPI_transfer().</td>
76  *  <td>See the device documentation on it's chip select requirements.</td>
77  *  </tr>
78  *  </table>
79  *
80  *  ## SPI data frames #
81  *  SPI data frames can be any size from 4-bits to 32-bits.  The SPI data
82  *  frame size is set in #SPI_Params.dataSize passed to SPI_open.
83  *  The SPICC32XXDMA driver implementation makes assumptions on the element
84  *  size of the #SPI_Transaction txBuf and rxBuf arrays, based on the data
85  *  frame size.  If the data frame size is less than or equal to 8 bits,
86  *  txBuf and rxBuf are assumed to be arrays of 8-bit uint8_t elements.
87  *  If the data frame size is greater than 8 bits, but less than or equal
88  *  to 16 bits, txBuf and rxBuf are assumed to be arrays of 16-bit uint16_t
89  *  elements.  Otherwise, txBuf and rxBuf are assumed to point to 32-bit
90  *  uint32_t elements.
91  *
92  *  data frame size  | buffer element size |
93  *  --------------   | ------------------- |
94  *  4-8 bits         | uint8_t             |
95  *  9-16 bits        | uint16_t            |
96  *  17-32 bits       | uint32_t            |
97  *
98  *  Data buffers in transactions (rxBuf & txBuf) must be address aligned
99  *  according to the data frame size.  For example, if data frame is 9-bit
100  *  (driver assumes buffers are uint16_t) rxBuf & txBuf must be aligned
101  *  on a 16-bit address boundary, if data frame is 20-bit (driver assumes
102  *  buffers are uint32_t) rxBuf & txBuf must be aligned on a 32-bit address
103  *  boundary.
104  *
105  *  ## DMA Interrupts #
106  *  This driver is designed to operate with the micro DMA. The micro DMA
107  *  generates an interrupt on the perpheral's interrupt vector. This
108  *  implementation automatically installs a DMA aware hardware ISR to service
109  *  the assigned micro DMA channels.
110  *
111  *  ## DMA and Queueing
112  *  This driver utilizes DMA channels in ping pong mode (see device TRM) in
113  *  order to overcome the 1024 item DMA channel limit. This means the driver
114  *  can execute multi kilo-item transactions without pausing to reconfigure the
115  *  DMA and causing gaps in transmission. In addition, the driver also allows
116  *  the user to queue up transfers when opened in #SPI_MODE_CALLBACK by calling
117  *  SPI_transfer() multiple times. Note that each transaction's
118  *  #SPI_Transaction struct must still be persistent and unmodified until that
119  *  transaction is complete.
120  *
121  *  @anchor ti_drivers_spi_SPICC32XXDMA_example_queueing
122  *  Below is an example of queueing three transactions
123  *  @code
124  *  // SPI already opened in callback mode
125  *  SPI_Transaction t0, t1, t2;
126  *
127  *  t0.txBuf = txBuff0;
128  *  t0.rxBuf = rxBuff0;
129  *  t0.count = 2000;
130  *
131  *  t1.txBuf = txBuff1;
132  *  t1.rxBuf = rxBuff1;
133  *  t1.count = 1000;
134  *
135  *  t2.txBuf = txBuff2;
136  *  t2.rxBuf = NULL;
137  *  t2.count = 1000;
138  *
139  *  bool transferOk = false;
140  *
141  *  if (SPI_transfer(spiHandle, &t0)) {
142  *      if (SPI_transfer(spiHandle, &t1)) {
143  *              transferOk = SPI_transfer(spiHandle, &t2);
144  *          }
145  *      }
146  *  }
147  *  @endcode
148  *
149  *  ## DMA accessible memory #
150  *  As this driver uses uDMA to transfer data/from data buffers, it is the
151  *  responsibility of the application to ensure that these buffers reside in
152  *  memory that is accessible by the DMA.
153  *
154  *  ## Scratch Buffers #
155  *  A uint32_t scratch buffer is used to allow SPI_transfers where txBuf or
156  *  rxBuf are NULL. Rather than requiring txBuf or rxBuf to have a dummy buffer
157  *  of size of the transfer count, a single DMA accessible uint32_t scratch
158  *  buffer is used. When rxBuf is NULL, the uDMA will transfer all the SPI data
159  *  receives into the scratch buffer as a "bit-bucket". When txBuf is NULL, the
160  *  scratch buffer is initialized to defaultTxBufValue so the uDMA will send
161  *  some known value. Each SPI driver instance must have its own scratch buffer.
162  *
163  *  ## Polling SPI transfers #
164  *  When used in blocking mode small SPI transfers are can be done by polling
165  *  the peripheral & sending data frame-by-frame.  This will not block the task
166  *  which requested the transfer, but instead immediately perform the transfer
167  *  & return.  The minDmaTransferSize field in the hardware attributes is
168  *  the threshold; if the transaction count is below the threshold a polling
169  *  transfer is performed; otherwise a DMA transfer is done.  This is intended
170  *  to reduce the overhead of setting up a DMA transfer to only send a few
171  *  data frames.  Keep in mind that during polling transfers the current task
172  *  is still being executed; there is no context switch to another task.
173  *******************************************************************************
174  */
175 
176 #ifndef ti_drivers_spi_SPICC32XXDMA__include
177 #define ti_drivers_spi_SPICC32XXDMA__include
178 
179 #include <ti/drivers/dpl/HwiP.h>
180 #include <ti/drivers/dpl/SemaphoreP.h>
181 #include <ti/drivers/Power.h>
182 #include <ti/drivers/SPI.h>
183 #include <ti/drivers/dma/UDMACC32XX.h>
184 
185 #ifdef __cplusplus
186 extern "C" {
187 #endif
188 
189 /**
190  *  @addtogroup SPI_STATUS
191  *  SPICC32XXDMA_STATUS_* macros are command codes only defined in the
192  *  SPICC32XXDMA.h driver implementation and need to:
193  *  @code
194  *  #include <ti/drivers/sdspi/SPICC32XXDMA.h>
195  *  @endcode
196  *  @{
197  */
198 
199 /* Add SPICC32XXDMA_STATUS_* macros here */
200 
201 /** @}*/
202 
203 /**
204  *  @addtogroup SPI_CMD
205  *  SPICC32XXDMA_CMD_* macros are command codes only defined in the
206  *  SPICC32XXDMA.h driver implementation and need to:
207  *  @code
208  *  #include <ti/drivers/sdspi/SPICC32XXDMA.h>
209  *  @endcode
210  *  @{
211  */
212 
213 /* Add SPICC32XXDMA_CMD_* macros here */
214 
215 
216 /** @}*/
217 
218 /*
219  *  Macros defining possible SPI signal pin mux options
220  *
221  *  The lower 8 bits of the macro refer to the pin, offset by 1, to match
222  *  driverlib pin defines.  For example, SPICC32XXDMA_PIN_05_CLK & 0xff = 4,
223  *  which equals PIN_05 in driverlib pin.h.  By matching the PIN_xx defines in
224  *  driverlib pin.h, we can pass the pin directly to the driverlib functions.
225  *  The upper 8 bits of the macro correspond to the pin mux confg mode
226  *  value for the pin to operate in the SPI mode.
227  *
228  *  PIN_62 is special for the SDSPI driver when using an SD BoosterPack,
229  *  as PIN_62 doesn't have an assigned SPI function yet the SD BoosterPack
230  *  has it tied to the CS signal.
231  */
232 /*! @cond HIDDEN_DEFINES */
233 #define SPICC32XXDMA_PIN_05_CLK     0x0704 /*!< PIN 5 is used for SPI CLK */
234 #define SPICC32XXDMA_PIN_06_MISO    0x0705 /*!< PIN 6 is used for MISO */
235 #define SPICC32XXDMA_PIN_07_MOSI    0x0706 /*!< PIN 7 is used for MOSI */
236 #define SPICC32XXDMA_PIN_08_CS      0x0707 /*!< PIN 8 is used for CS */
237 #define SPICC32XXDMA_PIN_45_CLK     0x072C /*!< PIN 45 is used for SPI CLK */
238 #define SPICC32XXDMA_PIN_50_CS      0x0931 /*!< PIN 50 is used for CS */
239 #define SPICC32XXDMA_PIN_52_MOSI    0x0833 /*!< PIN 52 is used for MOSI */
240 #define SPICC32XXDMA_PIN_53_MISO    0x0734 /*!< PIN 53 is used for MISO */
241 
242 /*! @endcond*/
243 
244 /*!
245  * @brief Indicates a pin is not to be configured by the SPICC32XXDMA driver.
246  */
247 #define SPICC32XXDMA_PIN_NO_CONFIG  0xFFFF
248 
249 /* SPI function table pointer */
250 extern const SPI_FxnTable SPICC32XXDMA_fxnTable;
251 
252 /*!
253  *  @brief  SPICC32XXDMA Hardware attributes
254  *
255  *  These fields, with the exception of intPriority,
256  *  are used by driverlib APIs and therefore must be populated by
257  *  driverlib macro definitions. For CCWare these definitions are found in:
258  *      - driverlib/prcm.h
259  *      - driverlib/spi.h
260  *      - driverlib/udma.h
261  *      - inc/hw_memmap.h
262  *      - inc/hw_ints.h
263  *
264  *  intPriority is the SPI peripheral's interrupt priority, as defined by the
265  *  underlying OS.  It is passed unmodified to the underlying OS's interrupt
266  *  handler creation code, so you need to refer to the OS documentation
267  *  for usage.  For example, for SYS/BIOS applications, refer to the
268  *  ti.sysbios.family.arm.m3.Hwi documentation for SYS/BIOS usage of
269  *  interrupt priorities.  If the driver uses the ti.dpl interface
270  *  instead of making OS calls directly, then the HwiP port handles the
271  *  interrupt priority in an OS specific way.  In the case of the SYS/BIOS
272  *  port, intPriority is passed unmodified to Hwi_create().
273  *
274  *  A sample structure is shown below:
275  *  @code
276  *  #if defined(__TI_COMPILER_VERSION__)
277  *  #pragma DATA_ALIGN(scratchBuf, 32)
278  *  #elif defined(__IAR_SYSTEMS_ICC__)
279  *  #pragma data_alignment=32
280  *  #elif defined(__GNUC__)
281  *  __attribute__ ((aligned (32)))
282  *  #endif
283  *  uint32_t scratchBuf;
284  *
285  *  const SPICC32XXDMA_HWAttrsV1 SPICC32XXDMAHWAttrs[] = {
286  *      {
287  *          .baseAddr = GSPI_BASE,
288  *          .intNum = INT_GSPI,
289  *          .intPriority = (~0),
290  *          .spiPRCM = PRCM_GSPI,
291  *          .csControl = SPI_HW_CTRL_CS,
292  *          .csPolarity = SPI_CS_ACTIVELOW,
293  *          .pinMode = SPI_4PIN_MODE,
294  *          .turboMode = SPI_TURBO_OFF,
295  *          .scratchBufPtr = &scratchBuf,
296  *          .defaultTxBufValue = 0,
297  *          .rxChannelIndex = UDMA_CH6_GSPI_RX,
298  *          .txChannelIndex = UDMA_CH7_GSPI_TX,
299  *          .minDmaTransferSize = 100,
300  *          .mosiPin = SPICC32XXDMA_PIN_07_MOSI,
301  *          .misoPin = SPICC32XXDMA_PIN_06_MISO,
302  *          .clkPin = SPICC32XXDMA_PIN_05_CLK,
303  *          .csPin = SPICC32XXDMA_PIN_08_CS,
304  *      },
305  *      ...
306  *  };
307  *  @endcode
308  */
309 typedef struct {
310     /*! SPICC32XXDMA Peripheral's base address */
311     uint32_t   baseAddr;
312 
313 
314     /*! SPICC32XXDMA Peripheral's interrupt vector */
315     uint32_t   intNum;
316 
317     /*! SPICC32XXDMA Peripheral's interrupt priority */
318     uint32_t   intPriority;
319 
320     /*! SPI PRCM peripheral number */
321     uint32_t   spiPRCM;
322 
323     /*! Specify if chip select line will be controlled by SW or HW */
324     uint32_t   csControl;
325 
326     uint32_t   csPolarity;
327 
328     /*! Set peripheral to work in 3-pin or 4-pin mode */
329     uint32_t   pinMode;
330 
331     /*! Enable or disable SPI TURBO mode */
332     uint32_t   turboMode;
333 
334     /*! Address of a scratch buffer of size uint32_t */
335     uint32_t  *scratchBufPtr;
336 
337     /*! Default TX value if txBuf == NULL */
338     uint32_t   defaultTxBufValue;
339 
340     /*! uDMA RX channel index */
341     uint32_t   rxChannelIndex;
342 
343     /*! uDMA TX channel index */
344     uint32_t   txChannelIndex;
345 
346     /*! Minimum amout of data to start a uDMA transfer */
347     uint32_t   minDmaTransferSize;
348 
349     /*! GSPI MOSI pin assignment */
350     uint16_t   mosiPin;
351 
352     /*! GSPI MISO pin assignment */
353     uint16_t   misoPin;
354 
355     /*! GSPI CLK pin assignment */
356     uint16_t   clkPin;
357 
358     /*! GSPI CS pin assignment */
359     uint16_t   csPin;
360 } SPICC32XXDMA_HWAttrsV1;
361 
362 /*!
363  *  @brief  SPICC32XXDMA Object
364  *
365  *  The application must not access any member variables of this structure!
366  */
367 typedef struct {
368     HwiP_Handle        hwiHandle;
369     Power_NotifyObj    notifyObj;
370     SemaphoreP_Handle  transferComplete;
371     SPI_CallbackFxn    transferCallbackFxn;
372     SPI_Transaction   *transaction;
373     UDMACC32XX_Handle  dmaHandle;
374 
375     size_t             amtDataXferred;
376     size_t             currentXferAmt;
377     uint32_t           bitRate;
378     uint32_t           dataSize;
379     uint32_t           transferTimeout;
380 
381     SPI_Mode           spiMode;
382     SPI_TransferMode   transferMode;
383     SPI_FrameFormat    frameFormat;
384 
385     bool               cancelInProgress;
386     bool               isOpen;
387     uint8_t            rxFifoTrigger;
388     uint8_t            txFifoTrigger;
389 } SPICC32XXDMA_Object, *SPICC32XXDMA_Handle;
390 
391 #ifdef __cplusplus
392 }
393 #endif
394 
395 #endif /* ti_drivers_spi_SPICC32XXDMA__include */
396