1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*******************************************************************************
8  * NOTICE
9  * The hal is not public api, don't use in application code.
10  * See readme.md in hal/include/hal/readme.md
11  ******************************************************************************/
12 
13 // The HAL layer for SPI slave (common part)
14 
15 // SPI slave HAL usages:
16 // 1. initialize the bus
17 // 2. initialize the DMA descriptors if DMA used
18 // 3. call setup_device to update parameters for the device
19 // 4. prepare data to send, and prepare the receiving buffer
20 // 5. trigger user defined SPI transaction to start
21 // 6. wait until the user transaction is done
22 // 7. store the received data and get the length
23 // 8. check and reset the DMA (if needed) before the next transaction
24 
25 #pragma once
26 
27 #include <esp_types.h>
28 #include "soc/lldesc.h"
29 #include "soc/spi_struct.h"
30 #include "soc/soc_caps.h"
31 #include "hal/spi_ll.h"
32 
33 /**
34  * Context that should be maintained by both the driver and the HAL.
35  */
36 typedef struct {
37     /* configured by driver at initialization, don't touch */
38     spi_dev_t     *hw;              ///< Beginning address of the peripheral registers.
39     spi_dma_dev_t *dma_in;          ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
40     spi_dma_dev_t *dma_out;         ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
41     /* should be configured by driver at initialization */
42     lldesc_t      *dmadesc_rx;      /**< Array of DMA descriptor used by the TX DMA.
43                                      *   The amount should be larger than dmadesc_n. The driver should ensure that
44                                      *   the data to be sent is shorter than the descriptors can hold.
45                                      */
46     lldesc_t      *dmadesc_tx;      /**< Array of DMA descriptor used by the RX DMA.
47                                      *   The amount should be larger than dmadesc_n. The driver should ensure that
48                                      *   the data to be sent is shorter than the descriptors can hold.
49                                      */
50     int           dmadesc_n;        ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
51     uint32_t      tx_dma_chan;      ///< TX DMA channel
52     uint32_t      rx_dma_chan;      ///< RX DMA channel
53 
54     /*
55      * configurations to be filled after ``spi_slave_hal_init``. Updated to
56      * peripheral registers when ``spi_slave_hal_setup_device`` is called.
57      */
58     struct {
59         uint32_t rx_lsbfirst : 1;
60         uint32_t tx_lsbfirst : 1;
61         uint32_t use_dma     : 1;
62     };
63     int mode;
64 
65     /*
66      * Transaction specific (data), all these parameters will be updated to the
67      * peripheral every transaction.
68      */
69     uint32_t bitlen;                ///< Expected maximum length of the transaction, in bits.
70     const void *tx_buffer;          ///< Data to be sent
71     void *rx_buffer;                ///< Buffer to hold the received data.
72 
73     /*  Other transaction result after one transaction */
74     uint32_t rcv_bitlen;            ///< Length of the last transaction, in bits.
75 } spi_slave_hal_context_t;
76 
77 typedef struct {
78     uint32_t host_id;               ///< SPI controller ID
79     spi_dma_dev_t *dma_in;          ///< Input  DMA(DMA -> RAM) peripheral register address
80     spi_dma_dev_t *dma_out;         ///< Output DMA(RAM -> DMA) peripheral register address
81 } spi_slave_hal_config_t;
82 
83 /**
84  * Init the peripheral and the context.
85  *
86  * @param hal        Context of the HAL layer.
87  * @param hal_config Configuration of the HAL
88  */
89 void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config);
90 
91 /**
92  * Deinit the peripheral (and the context if needed).
93  *
94  * @param hal Context of the HAL layer.
95  */
96 void spi_slave_hal_deinit(spi_slave_hal_context_t *hal);
97 
98 /**
99  * Setup device-related configurations according to the settings in the context.
100  *
101  * @param hal Context of the HAL layer.
102  */
103 void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal);
104 
105 /**
106  * Prepare the data for the current transaction.
107  *
108  * @param hal Context of the HAL layer.
109  */
110 void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal);
111 
112 /**
113  * Trigger start a user-defined transaction.
114  *
115  * @param hal Context of the HAL layer.
116  */
117 void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal);
118 
119 /**
120  * Check whether the transaction is done (trans_done is set).
121  *
122  * @param hal Context of the HAL layer.
123  */
124 bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal);
125 
126 /**
127  * Post transaction operations, fetch data from the buffer and recored the length.
128  *
129  * @param hal Context of the HAL layer.
130  */
131 void spi_slave_hal_store_result(spi_slave_hal_context_t *hal);
132 
133 /**
134  * Get the length of last transaction, in bits. Should be called after ``spi_slave_hal_store_result``.
135  *
136  * Note that if last transaction is longer than configured before, the return
137  * value will be truncated to the configured length.
138  *
139  * @param hal Context of the HAL layer.
140  *
141  * @return Length of the last transaction, in bits.
142  */
143 uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal);
144 
145 #if CONFIG_IDF_TARGET_ESP32
146 /**
147  * Check whether we need to reset the DMA according to the status of last transactions.
148  *
149  * In ESP32, sometimes we may need to reset the DMA for the slave before the
150  * next transaction. Call this to check it.
151  *
152  * @param hal Context of the HAL layer.
153  *
154  * @return true if reset is needed, else false.
155  */
156 bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal);
157 #endif //#if CONFIG_IDF_TARGET_ESP32
158