1 /*
2  * Copyright (c) 2015 - 2023, 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 #include <nrfx.h>
35 
36 #if NRFX_CHECK(NRFX_SPI_ENABLED)
37 
38 #if !NRFX_FEATURE_PRESENT(NRFX_SPI, _ENABLED)
39 #error "No enabled SPI instances. Check <nrfx_config.h>."
40 #endif
41 
42 #include <nrfx_spi.h>
43 #include "prs/nrfx_prs.h"
44 #include <hal/nrf_gpio.h>
45 
46 #define NRFX_LOG_MODULE SPI
47 #include <nrfx_log.h>
48 
49 // Control block - driver instance local data.
50 typedef struct
51 {
52     nrfx_spi_evt_handler_t  handler;
53     void *                  p_context;
54     nrfx_spi_evt_t          evt;  // Keep the struct that is ready for event handler. Less memcpy.
55     nrfx_drv_state_t        state;
56     volatile bool           transfer_in_progress;
57 
58     uint8_t ss_pin;
59     uint8_t orc;
60     size_t  bytes_transferred;
61     bool    abort;
62     bool    skip_gpio_cfg;
63 } spi_control_block_t;
64 static spi_control_block_t m_cb[NRFX_SPI_ENABLED_COUNT];
65 
pins_configure(nrfx_spi_config_t const * p_config)66 static void pins_configure(nrfx_spi_config_t const * p_config)
67 {
68     if (!p_config->skip_gpio_cfg)
69     {
70         // Configure pins used by the peripheral:
71         // - SCK - output with initial value corresponding with the SPI mode used:
72         //   0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
73         //   according to the reference manual guidelines this pin and its input
74         //   buffer must always be connected for the SPI to work.
75         if (p_config->mode <= NRF_SPI_MODE_1)
76         {
77             nrf_gpio_pin_clear(p_config->sck_pin);
78         }
79         else
80         {
81             nrf_gpio_pin_set(p_config->sck_pin);
82         }
83         nrf_gpio_cfg(p_config->sck_pin,
84                      NRF_GPIO_PIN_DIR_OUTPUT,
85                      NRF_GPIO_PIN_INPUT_CONNECT,
86                      NRF_GPIO_PIN_NOPULL,
87                      NRF_GPIO_PIN_S0S1,
88                      NRF_GPIO_PIN_NOSENSE);
89         // - MOSI (optional) - output with initial value 0,
90         if (p_config->mosi_pin != NRFX_SPI_PIN_NOT_USED)
91         {
92             nrf_gpio_pin_clear(p_config->mosi_pin);
93             nrf_gpio_cfg_output(p_config->mosi_pin);
94         }
95         // - MISO (optional) - input,
96         if (p_config->miso_pin != NRFX_SPI_PIN_NOT_USED)
97         {
98             nrf_gpio_cfg_input(p_config->miso_pin, p_config->miso_pull);
99         }
100         // - Slave Select (optional) - output with initial value 1 (inactive).
101         if (p_config->ss_pin != NRFX_SPI_PIN_NOT_USED)
102         {
103             nrf_gpio_pin_set(p_config->ss_pin);
104             nrf_gpio_cfg_output(p_config->ss_pin);
105         }
106     }
107 }
108 
spi_configure(nrfx_spi_t const * p_instance,nrfx_spi_config_t const * p_config)109 static void spi_configure(nrfx_spi_t const *        p_instance,
110                           nrfx_spi_config_t const * p_config)
111 {
112     pins_configure(p_config);
113     m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin;
114 
115     if (!p_config->skip_psel_cfg)
116     {
117         uint32_t mosi_pin = p_config->mosi_pin != NRFX_SPI_PIN_NOT_USED ?
118                             p_config->mosi_pin : NRF_SPI_PIN_NOT_CONNECTED;
119         uint32_t miso_pin = p_config->miso_pin != NRFX_SPI_PIN_NOT_USED ?
120                             p_config->miso_pin : NRF_SPI_PIN_NOT_CONNECTED;
121 
122         nrf_spi_pins_set(p_instance->p_reg, p_config->sck_pin, mosi_pin, miso_pin);
123     }
124     nrf_spi_frequency_set(p_instance->p_reg, p_config->frequency);
125     nrf_spi_configure(p_instance->p_reg, p_config->mode, p_config->bit_order);
126 
127     m_cb[p_instance->drv_inst_idx].orc = p_config->orc;
128 
129     if (m_cb[p_instance->drv_inst_idx].handler)
130     {
131         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
132             p_config->irq_priority);
133         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
134     }
135 }
136 
nrfx_spi_init(nrfx_spi_t const * p_instance,nrfx_spi_config_t const * p_config,nrfx_spi_evt_handler_t handler,void * p_context)137 nrfx_err_t nrfx_spi_init(nrfx_spi_t const *        p_instance,
138                          nrfx_spi_config_t const * p_config,
139                          nrfx_spi_evt_handler_t    handler,
140                          void *                    p_context)
141 {
142     NRFX_ASSERT(p_config);
143 
144     spi_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
145     nrfx_err_t err_code;
146 
147     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
148     {
149 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
150         err_code = NRFX_ERROR_ALREADY;
151 #else
152         err_code = NRFX_ERROR_INVALID_STATE;
153 #endif
154         NRFX_LOG_WARNING("Function: %s, error code: %s.",
155                          __func__,
156                          NRFX_LOG_ERROR_STRING_GET(err_code));
157         return err_code;
158     }
159 
160 #if NRFX_CHECK(NRFX_PRS_ENABLED)
161     static nrfx_irq_handler_t const irq_handlers[NRFX_SPI_ENABLED_COUNT] = {
162         NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPI, spi)
163     };
164     if (nrfx_prs_acquire(p_instance->p_reg,
165             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
166     {
167         err_code = NRFX_ERROR_BUSY;
168         NRFX_LOG_WARNING("Function: %s, error code: %s.",
169                          __func__,
170                          NRFX_LOG_ERROR_STRING_GET(err_code));
171         return err_code;
172     }
173 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
174 
175     p_cb->handler = handler;
176     p_cb->p_context = p_context;
177 
178     if (p_config)
179     {
180         p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
181         p_cb->ss_pin = p_config->ss_pin;
182         p_cb->orc = p_config->orc;
183 
184         spi_configure(p_instance, p_config);
185     }
186     nrf_spi_enable(p_instance->p_reg);
187 
188     p_cb->transfer_in_progress = false;
189     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
190 
191     err_code = NRFX_SUCCESS;
192     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
193     return err_code;
194 }
195 
nrfx_spi_reconfigure(nrfx_spi_t const * p_instance,nrfx_spi_config_t const * p_config)196 nrfx_err_t nrfx_spi_reconfigure(nrfx_spi_t const *        p_instance,
197                                 nrfx_spi_config_t const * p_config)
198 {
199     NRFX_ASSERT(p_config);
200 
201     spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
202 
203     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
204     {
205         return NRFX_ERROR_INVALID_STATE;
206     }
207     if (p_cb->transfer_in_progress)
208     {
209         return NRFX_ERROR_BUSY;
210     }
211     nrf_spi_disable(p_instance->p_reg);
212     spi_configure(p_instance, p_config);
213     nrf_spi_enable(p_instance->p_reg);
214     return NRFX_SUCCESS;
215 }
216 
nrfx_spi_uninit(nrfx_spi_t const * p_instance)217 void nrfx_spi_uninit(nrfx_spi_t const * p_instance)
218 {
219     spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
220     NRF_SPI_Type * p_spi = p_instance->p_reg;
221 
222     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
223 
224     if (p_cb->handler)
225     {
226         NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
227         nrf_spi_int_disable(p_spi, NRF_SPI_ALL_INTS_MASK);
228     }
229 
230     nrf_spi_disable(p_spi);
231 
232     if (!p_cb->skip_gpio_cfg)
233     {
234         nrf_gpio_cfg_default(nrf_spi_sck_pin_get(p_spi));
235 
236         uint32_t miso_pin = nrf_spi_miso_pin_get(p_spi);
237         if (miso_pin != NRF_SPI_PIN_NOT_CONNECTED)
238         {
239             nrf_gpio_cfg_default(miso_pin);
240         }
241 
242         uint32_t mosi_pin = nrf_spi_mosi_pin_get(p_spi);
243         if (mosi_pin != NRF_SPI_PIN_NOT_CONNECTED)
244         {
245             nrf_gpio_cfg_default(mosi_pin);
246         }
247 
248         if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
249         {
250             nrf_gpio_cfg_default(p_cb->ss_pin);
251         }
252     }
253 
254 #if NRFX_CHECK(NRFX_PRS_ENABLED)
255     nrfx_prs_release(p_instance->p_reg);
256 #endif
257 
258     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
259     NRFX_LOG_INFO("Uninitialized.");
260 }
261 
nrfx_spi_init_check(nrfx_spi_t const * p_instance)262 bool nrfx_spi_init_check(nrfx_spi_t const * p_instance)
263 {
264     spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
265 
266     return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
267 }
268 
finish_transfer(spi_control_block_t * p_cb)269 static void finish_transfer(spi_control_block_t * p_cb)
270 {
271     // If Slave Select signal is used, this is the time to deactivate it.
272     if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
273     {
274         nrf_gpio_pin_write(p_cb->ss_pin, 1);
275     }
276 
277     // By clearing this flag before calling the handler we allow subsequent
278     // transfers to be started directly from the handler function.
279     p_cb->transfer_in_progress = false;
280 
281     p_cb->evt.type = NRFX_SPI_EVENT_DONE;
282     p_cb->handler(&p_cb->evt, p_cb->p_context);
283 }
284 
285 // This function is called from the IRQ handler or, in blocking mode, directly
286 // from the 'spi_xfer' function.
287 // It returns true as long as the transfer should be continued, otherwise (when
288 // there is nothing more to send/receive) it returns false.
transfer_byte(NRF_SPI_Type * p_spi,spi_control_block_t * p_cb)289 static bool transfer_byte(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb)
290 {
291     // Read the data byte received in this transfer (always, because no further
292     // READY event can be generated until the current byte is read out from the
293     // RXD register), and store it in the RX buffer (only when needed).
294     volatile uint8_t rx_data = nrf_spi_rxd_get(p_spi);
295     if (p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length)
296     {
297         p_cb->evt.xfer_desc.p_rx_buffer[p_cb->bytes_transferred] = rx_data;
298     }
299 
300     ++p_cb->bytes_transferred;
301 
302     // Check if there are more bytes to send or receive and write proper data
303     // byte (next one from TX buffer or over-run character) to the TXD register
304     // when needed.
305     // NOTE - we've already used 'p_cb->bytes_transferred + 1' bytes from our
306     //        buffers, because we take advantage of double buffering of TXD
307     //        register (so in effect one byte is still being transmitted now);
308     //        see how the transfer is started in the 'spi_xfer' function.
309     size_t bytes_used = p_cb->bytes_transferred + 1;
310 
311     if (p_cb->abort)
312     {
313         if (bytes_used < p_cb->evt.xfer_desc.tx_length)
314         {
315             p_cb->evt.xfer_desc.tx_length = bytes_used;
316         }
317         if (bytes_used < p_cb->evt.xfer_desc.rx_length)
318         {
319             p_cb->evt.xfer_desc.rx_length = bytes_used;
320         }
321     }
322 
323     if (bytes_used < p_cb->evt.xfer_desc.tx_length)
324     {
325         nrf_spi_txd_set(p_spi, p_cb->evt.xfer_desc.p_tx_buffer[bytes_used]);
326         return true;
327     }
328     else if (bytes_used < p_cb->evt.xfer_desc.rx_length)
329     {
330         nrf_spi_txd_set(p_spi, p_cb->orc);
331         return true;
332     }
333 
334     return (p_cb->bytes_transferred < p_cb->evt.xfer_desc.tx_length ||
335             p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length);
336 }
337 
spi_xfer(NRF_SPI_Type * p_spi,spi_control_block_t * p_cb,nrfx_spi_xfer_desc_t const * p_xfer_desc)338 static void spi_xfer(NRF_SPI_Type               * p_spi,
339                      spi_control_block_t        * p_cb,
340                      nrfx_spi_xfer_desc_t const * p_xfer_desc)
341 {
342     p_cb->bytes_transferred = 0;
343     nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK);
344 
345     nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
346 
347     // Start the transfer by writing some byte to the TXD register;
348     // if TX buffer is not empty, take the first byte from this buffer,
349     // otherwise - use over-run character.
350     nrf_spi_txd_set(p_spi,
351         (p_xfer_desc->tx_length > 0 ? p_xfer_desc->p_tx_buffer[0] : p_cb->orc));
352 
353     // TXD register is double buffered, so next byte to be transmitted can
354     // be written immediately, if needed, i.e. if TX or RX transfer is to
355     // be more that 1 byte long. Again - if there is something more in TX
356     // buffer send it, otherwise use over-run character.
357     if (p_xfer_desc->tx_length > 1)
358     {
359         nrf_spi_txd_set(p_spi, p_xfer_desc->p_tx_buffer[1]);
360     }
361     else if (p_xfer_desc->rx_length > 1)
362     {
363         nrf_spi_txd_set(p_spi, p_cb->orc);
364     }
365 
366     // For blocking mode (user handler not provided) wait here for READY
367     // events (indicating that the byte from TXD register was transmitted
368     // and a new incoming byte was moved to the RXD register) and continue
369     // transaction until all requested bytes are transferred.
370     // In non-blocking mode - IRQ service routine will do this stuff.
371     if (p_cb->handler)
372     {
373         nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK);
374     }
375     else
376     {
377         do {
378             while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {}
379             nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
380             NRFX_LOG_DEBUG("SPI: Event: NRF_SPI_EVENT_READY.");
381         } while (transfer_byte(p_spi, p_cb));
382         if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
383         {
384             nrf_gpio_pin_write(p_cb->ss_pin, 1);
385         }
386     }
387 }
388 
nrfx_spi_xfer(nrfx_spi_t const * p_instance,nrfx_spi_xfer_desc_t const * p_xfer_desc,uint32_t flags)389 nrfx_err_t nrfx_spi_xfer(nrfx_spi_t const *           p_instance,
390                          nrfx_spi_xfer_desc_t const * p_xfer_desc,
391                          uint32_t                     flags)
392 {
393     spi_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
394 
395     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
396     NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
397     NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
398 
399     nrfx_err_t err_code = NRFX_SUCCESS;
400 
401     if (p_cb->transfer_in_progress)
402     {
403         err_code = NRFX_ERROR_BUSY;
404         NRFX_LOG_WARNING("Function: %s, error code: %s.",
405                          __func__,
406                          NRFX_LOG_ERROR_STRING_GET(err_code));
407         return err_code;
408     }
409     else
410     {
411         if (p_cb->handler)
412         {
413             p_cb->transfer_in_progress = true;
414         }
415     }
416 
417     p_cb->evt.xfer_desc = *p_xfer_desc;
418     p_cb->abort = false;
419 
420     if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
421     {
422         nrf_gpio_pin_write(p_cb->ss_pin, 0);
423     }
424     if (flags)
425     {
426         p_cb->transfer_in_progress = false;
427         err_code = NRFX_ERROR_NOT_SUPPORTED;
428     }
429     else
430     {
431         spi_xfer(p_instance->p_reg, p_cb, p_xfer_desc);
432     }
433     NRFX_LOG_INFO("Function: %s, error code: %s.",
434                   __func__,
435                   NRFX_LOG_ERROR_STRING_GET(err_code));
436     return err_code;
437 }
438 
nrfx_spi_abort(nrfx_spi_t const * p_instance)439 void nrfx_spi_abort(nrfx_spi_t const * p_instance)
440 {
441     spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
442 
443     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
444 
445     p_cb->abort = true;
446 }
447 
irq_handler(NRF_SPI_Type * p_spi,spi_control_block_t * p_cb)448 static void irq_handler(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb)
449 {
450     NRFX_ASSERT(p_cb->handler);
451 
452     nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
453     NRFX_LOG_DEBUG("Event: NRF_SPI_EVENT_READY.");
454 
455     if (!transfer_byte(p_spi, p_cb))
456     {
457         finish_transfer(p_cb);
458     }
459 }
460 
461 NRFX_INSTANCE_IRQ_HANDLERS(SPI, spi)
462 
463 #endif // NRFX_CHECK(NRFX_SPI_ENABLED)
464