1 /*
2  * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef NRFX_SPIS_H__
35 #define NRFX_SPIS_H__
36 
37 #include <nrfx.h>
38 #include <hal/nrf_spis.h>
39 #include <haly/nrfy_gpio.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /**
46  * @defgroup nrfx_spis SPIS driver
47  * @{
48  * @ingroup nrf_spis
49  * @brief   Serial Peripheral Interface Slave with EasyDMA (SPIS) driver.
50  */
51 
52 /** @brief Data structure for the Serial Peripheral Interface Slave with EasyDMA (SPIS) driver instance. */
53 typedef struct
54 {
55     NRF_SPIS_Type * p_reg;          //!< Pointer to a structure with SPIS registers.
56     uint8_t         drv_inst_idx;   //!< Index of the driver instance. For internal use only.
57 } nrfx_spis_t;
58 
59 #ifndef __NRFX_DOXYGEN__
60 enum {
61     /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */
62     NRFX_INSTANCE_ENUM_LIST(SPIS)
63     NRFX_SPIS_ENABLED_COUNT
64 };
65 #endif
66 
67 /** @brief Macro for creating an instance of the SPI slave driver. */
68 #define NRFX_SPIS_INSTANCE(id)                               \
69 {                                                            \
70     .p_reg        = NRFX_CONCAT(NRF_, SPIS, id),             \
71     .drv_inst_idx = NRFX_CONCAT(NRFX_SPIS, id, _INST_IDX),   \
72 }
73 
74 /** @brief SPI slave driver event types. */
75 typedef enum
76 {
77     NRFX_SPIS_BUFFERS_SET_DONE, //!< Memory buffer set event. Memory buffers have been set successfully to the SPI slave device, and SPI transaction can be done.
78     NRFX_SPIS_XFER_DONE,        //!< SPI transaction event. SPI transaction has been completed.
79     NRFX_SPIS_EVT_TYPE_MAX      //!< Enumeration upper bound.
80 } nrfx_spis_evt_type_t;
81 
82 /** @brief SPI slave driver event structure. */
83 typedef struct
84 {
85     nrfx_spis_evt_type_t evt_type;    //!< Type of the event.
86     size_t               rx_amount;   //!< Number of bytes received in the last transaction. This parameter is only valid for @ref NRFX_SPIS_XFER_DONE events.
87     size_t               tx_amount;   //!< Number of bytes transmitted in the last transaction. This parameter is only valid for @ref NRFX_SPIS_XFER_DONE events.
88     void *               p_tx_buf;    //!< Pointer to the TX buffer used in the last transaction. This parameter is only valid for @ref NRFX_SPIS_XFER_DONE events.
89     void *               p_rx_buf;    //!< Pointer to the RX buffer used in the last transaction. This parameter is only valid for @ref NRFX_SPIS_XFER_DONE events.
90     size_t               tx_buf_size; //!< Size of the TX buffer used int the last transaction. This parameter is only valid for @ref NRFX_SPIS_XFER_DONE events.
91     size_t               rx_buf_size; //!< Size of the RX buffer used int the last transaction. This parameter is only valid for @ref NRFX_SPIS_XFER_DONE events.
92 } nrfx_spis_evt_t;
93 
94 /**
95  * @brief SPIS driver default configuration.
96  *
97  * This configuration sets up SPIS with the following options:
98  * - mode: 0 (SCK active high, sample on leading edge of the clock signal)
99  * - MSB shifted out first
100  * - CSN pull-up disabled
101  * - MISO pin drive set to standard '0' and standard '1'
102  * - default character set to 0xFF
103  * - over-read character set to 0xFE
104  *
105  * @param[in] _pin_sck  SCK pin.
106  * @param[in] _pin_mosi MOSI pin.
107  * @param[in] _pin_miso MISO pin.
108  * @param[in] _pin_csn  CSN pin.
109  */
110 #define NRFX_SPIS_DEFAULT_CONFIG(_pin_sck, _pin_mosi, _pin_miso, _pin_csn)   \
111 {                                                                            \
112     .miso_pin      = _pin_miso,                                              \
113     .mosi_pin      = _pin_mosi,                                              \
114     .sck_pin       = _pin_sck,                                               \
115     .csn_pin       = _pin_csn,                                               \
116     .mode          = NRF_SPIS_MODE_0,                                        \
117     .bit_order     = NRF_SPIS_BIT_ORDER_MSB_FIRST,                           \
118     .csn_pullup    = NRF_GPIO_PIN_NOPULL,                                    \
119     .miso_drive    = NRF_GPIO_PIN_S0S1,                                      \
120     .def           = 0xFF,                                                   \
121     .orc           = 0xFE,                                                   \
122     .irq_priority  = NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY,                  \
123     .skip_gpio_cfg = false,                                                  \
124     .skip_psel_cfg = false,                                                  \
125 }
126 
127 /** @brief SPI peripheral device configuration data. */
128 typedef struct
129 {
130     uint32_t             miso_pin;      ///< SPI MISO pin (optional).
131                                         /**< Set @ref NRF_SPIS_PIN_NOT_CONNECTED
132                                          *   if this signal is not needed. */
133     uint32_t             mosi_pin;      ///< SPI MOSI pin (optional).
134                                         /**< Set @ref NRF_SPIS_PIN_NOT_CONNECTED
135                                          *   if this signal is not needed. */
136     uint32_t             sck_pin;       ///< SPI SCK pin.
137     uint32_t             csn_pin;       ///< SPI CSN pin.
138     nrf_spis_mode_t      mode;          ///< SPI mode.
139     nrf_spis_bit_order_t bit_order;     ///< SPI transaction bit order.
140     nrf_gpio_pin_pull_t  csn_pullup;    ///< CSN pin pull-up configuration.
141     nrf_gpio_pin_drive_t miso_drive;    ///< MISO pin drive configuration.
142     uint8_t              def;           ///< Character clocked out in case of an ignored transaction.
143     uint8_t              orc;           ///< Character clocked out after an over-read of the transmit buffer.
144     uint8_t              irq_priority;  ///< Interrupt priority.
145     bool                 skip_gpio_cfg; ///< Skip GPIO configuration of pins.
146                                         /**< When set to true, the driver does not modify
147                                          *   any GPIO parameters of the used pins. Those
148                                          *   parameters are supposed to be configured
149                                          *   externally before the driver is initialized. */
150     bool                 skip_psel_cfg; ///< Skip pin selection configuration.
151                                         /**< When set to true, the driver does not modify
152                                          *   pin select registers in the peripheral.
153                                          *   Those registers are supposed to be set up
154                                          *   externally before the driver is initialized.
155                                          *   @note When both GPIO configuration and pin
156                                          *   selection are to be skipped, the structure
157                                          *   fields that specify pins can be omitted,
158                                          *   as they are ignored anyway. */
159 } nrfx_spis_config_t;
160 
161 
162 /**
163  * @brief SPI slave driver event handler type.
164  *
165  * @param[in] p_event    Pointer to the event structure. The structure is
166  *                       allocated on the stack so it is valid only until
167  *                       the event handler returns.
168  * @param[in] p_context  Context set on initialization.
169  */
170 typedef void (*nrfx_spis_event_handler_t)(nrfx_spis_evt_t const * p_event,
171                                           void *                  p_context);
172 
173 /**
174  * @brief Function for initializing the SPI slave driver instance.
175  *
176  * @note When the nRF52 Anomaly 109 workaround for SPIS is enabled, this function
177  *       initializes the GPIOTE driver as well, and uses one of GPIOTE channels
178  *       to detect falling edges on CSN pin.
179  *
180  * @param[in] p_instance    Pointer to the driver instance structure.
181  * @param[in] p_config      Pointer to the structure with the initial configuration.
182  * @param[in] event_handler Function to be called by the SPI slave driver upon event.
183  *                          Must not be NULL.
184  * @param[in] p_context     Context passed to the event handler.
185  *
186  * @retval NRFX_SUCCESS             The initialization was successful.
187  * @retval NRFX_ERROR_ALREADY       The driver is already initialized.
188  * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
189  *                                  Deprecated - use @ref NRFX_ERROR_ALREADY instead.
190  * @retval NRFX_ERROR_INVALID_PARAM Invalid parameter is supplied.
191  * @retval NRFX_ERROR_BUSY          Some other peripheral with the same
192  *                                  instance ID is already in use. This is
193  *                                  possible only if @ref nrfx_prs module
194  *                                  is enabled.
195  * @retval NRFX_ERROR_INTERNAL      GPIOTE channel for detecting falling edges
196  *                                  on CSN pin cannot be initialized. Possible
197  *                                  only when using nRF52 Anomaly 109 workaround.
198  */
199 nrfx_err_t nrfx_spis_init(nrfx_spis_t const *        p_instance,
200                           nrfx_spis_config_t const * p_config,
201                           nrfx_spis_event_handler_t  event_handler,
202                           void *                     p_context);
203 
204 /**
205  * @brief Function for reconfiguring the SPI slave driver instance.
206  *
207  * @param[in] p_instance Pointer to the driver instance structure.
208  * @param[in] p_config   Pointer to the structure with the configuration.
209  *
210  * @retval NRFX_SUCCESS             Reconfiguration was successful.
211  * @retval NRFX_ERROR_BUSY          The driver is during transfer.
212  * @retval NRFX_ERROR_INVALID_STATE The driver is uninitialized.
213  */
214 nrfx_err_t nrfx_spis_reconfigure(nrfx_spis_t const *        p_instance,
215                                  nrfx_spis_config_t const * p_config);
216 
217 /**
218  * @brief Function for uninitializing the SPI slave driver instance.
219  *
220  * @param[in] p_instance Pointer to the driver instance structure.
221  */
222 void nrfx_spis_uninit(nrfx_spis_t const * p_instance);
223 
224 /**
225  * @brief Function for checking if the SPIS driver instance is initialized.
226  *
227  * @param[in] p_instance Pointer to the driver instance structure.
228  *
229  * @retval true  Instance is already initialized.
230  * @retval false Instance is not initialized.
231  */
232 bool nrfx_spis_init_check(nrfx_spis_t const * p_instance);
233 
234 /**
235  * @brief Function for preparing the SPI slave instance for a single SPI transaction.
236  *
237  * This function prepares the SPI slave device to be ready for a single SPI transaction. It configures
238  * the SPI slave device to use the memory supplied with the function call in SPI transactions.
239  *
240  * When either the memory buffer configuration or the SPI transaction has been
241  * completed, the event callback function will be called with the appropriate event
242  * @ref nrfx_spis_evt_type_t. The callback function can be called before returning from
243  * this function, because it is called from the SPI slave interrupt context.
244  *
245  * @note This function can be called from the callback function context.
246  *
247  * @note Client applications must call this function after every @ref NRFX_SPIS_XFER_DONE event if
248  * the SPI slave driver must be prepared for a possible new SPI transaction.
249  *
250  * @note Peripherals using EasyDMA (including SPIS) require the transfer buffers
251  *       to be placed in the Data RAM region. If this condition is not met,
252  *       this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
253  *
254  * @param[in] p_instance       Pointer to the driver instance structure.
255  * @param[in] p_tx_buffer      Pointer to the TX buffer. Can be NULL when the buffer length is zero.
256  * @param[in] p_rx_buffer      Pointer to the RX buffer. Can be NULL when the buffer length is zero.
257  * @param[in] tx_buffer_length Length of the TX buffer in bytes.
258  * @param[in] rx_buffer_length Length of the RX buffer in bytes.
259  *
260  * @retval NRFX_SUCCESS              The operation was successful.
261  * @retval NRFX_ERROR_INVALID_STATE  The operation failed because the SPI slave device is in an incorrect state.
262  * @retval NRFX_ERROR_INVALID_ADDR   The provided buffers are not placed in the Data
263  *                                   RAM region.
264  * @retval NRFX_ERROR_INVALID_LENGTH Provided lengths exceed the EasyDMA limits for the peripheral.
265  * @retval NRFX_ERROR_INTERNAL       The operation failed because of an internal error.
266  */
267 nrfx_err_t nrfx_spis_buffers_set(nrfx_spis_t const * p_instance,
268                                  uint8_t const *     p_tx_buffer,
269                                  size_t              tx_buffer_length,
270                                  uint8_t *           p_rx_buffer,
271                                  size_t              rx_buffer_length);
272 
273 /**
274  * @brief Macro returning SPIS interrupt handler.
275  *
276  * param[in] idx SPIS index.
277  *
278  * @return Interrupt handler.
279  */
280 #define NRFX_SPIS_INST_HANDLER_GET(idx) NRFX_CONCAT_3(nrfx_spis_, idx, _irq_handler)
281 
282 /** @} */
283 
284 /*
285  * Declare interrupt handlers for all enabled driver instances in the following format:
286  * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_spis_0_irq_handler).
287  *
288  * A specific interrupt handler for the driver instance can be retrieved by using
289  * the NRFX_SPIS_INST_HANDLER_GET macro.
290  *
291  * Here is a sample of using the NRFX_SPIS_INST_HANDLER_GET macro to map an interrupt handler
292  * in a Zephyr application:
293  *
294  * IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIS_INST_GET(\<instance_index\>)), \<priority\>,
295  *             NRFX_SPIS_INST_HANDLER_GET(\<instance_index\>), 0, 0);
296  */
297 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(SPIS, spis)
298 
299 #ifdef __cplusplus
300 }
301 #endif
302 
303 #endif // NRFX_SPIS_H__
304 
305