1 /*
2  * Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
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 are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <nrfx.h>
33 
34 #if NRFX_CHECK(NRFX_SPIM_ENABLED)
35 
36 #if !(NRFX_CHECK(NRFX_SPIM0_ENABLED) || NRFX_CHECK(NRFX_SPIM1_ENABLED) || \
37       NRFX_CHECK(NRFX_SPIM2_ENABLED) || NRFX_CHECK(NRFX_SPIM3_ENABLED) || \
38       NRFX_CHECK(NRFX_SPIM4_ENABLED))
39 #error "No enabled SPIM instances. Check <nrfx_config.h>."
40 #endif
41 
42 
43 #include <nrfx_spim.h>
44 #include "prs/nrfx_prs.h"
45 #include <hal/nrf_gpio.h>
46 
47 #define NRFX_LOG_MODULE SPIM
48 #include <nrfx_log.h>
49 
50 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && \
51     ((!NRF_SPIM_HW_CSN_PRESENT) || !(NRF_SPIM_DCX_PRESENT) || !(NRF_SPIM_RXDELAY_PRESENT))
52 #error "Extended options are not available in the SoC currently in use."
53 #endif
54 
55 #define SPIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \
56     (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
57      NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len))
58 
59 #define SPIMX_HW_CSN_PRESENT_VALIDATE(peripheral, drv_inst_idx)         \
60     (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
61      NRFX_CONCAT_2(peripheral, _FEATURE_HARDWARE_CSN_PRESENT))
62 
63 #define SPIMX_DCX_PRESENT_VALIDATE(peripheral, drv_inst_idx)            \
64     (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
65     NRFX_CONCAT_2(peripheral, _FEATURE_DCX_PRESENT))
66 
67 #define SPIMX_SUPPORTED_FREQ_VALIDATE(peripheral, drv_inst_idx, freq)                            \
68     (                                                                                            \
69     ((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) &&                           \
70     (                                                                                            \
71         (((freq) != NRF_SPIM_FREQ_16M) && ((freq) != NRF_SPIM_FREQ_32M)) ||                      \
72         (((freq) == NRF_SPIM_FREQ_16M) && ((NRFX_CONCAT_2(peripheral, _MAX_DATARATE) >= 16))) || \
73         (((freq) == NRF_SPIM_FREQ_32M) && ((NRFX_CONCAT_2(peripheral, _MAX_DATARATE) >= 32)))    \
74     )                                                                                            \
75     )
76 
77 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
78 #define SPIM0_LENGTH_VALIDATE(...)          SPIMX_LENGTH_VALIDATE(SPIM0, __VA_ARGS__)
79 #define SPIM0_HW_CSN_PRESENT_VALIDATE(...)  SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM0, __VA_ARGS__)
80 #define SPIM0_DCX_PRESENT_VALIDATE(...)     SPIMX_DCX_PRESENT_VALIDATE(SPIM0, __VA_ARGS__)
81 #define SPIM0_SUPPORTED_FREQ_VALIDATE(...)  SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM0, __VA_ARGS__)
82 #else
83 #define SPIM0_LENGTH_VALIDATE(...)          0
84 #define SPIM0_HW_CSN_PRESENT_VALIDATE(...)  0
85 #define SPIM0_DCX_PRESENT_VALIDATE(...)     0
86 #define SPIM0_SUPPORTED_FREQ_VALIDATE(...)  0
87 #endif
88 
89 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
90 #define SPIM1_LENGTH_VALIDATE(...)          SPIMX_LENGTH_VALIDATE(SPIM1, __VA_ARGS__)
91 #define SPIM1_HW_CSN_PRESENT_VALIDATE(...)  SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM1, __VA_ARGS__)
92 #define SPIM1_DCX_PRESENT_VALIDATE(...)     SPIMX_DCX_PRESENT_VALIDATE(SPIM1, __VA_ARGS__)
93 #define SPIM1_SUPPORTED_FREQ_VALIDATE(...)  SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM1, __VA_ARGS__)
94 #else
95 #define SPIM1_LENGTH_VALIDATE(...)          0
96 #define SPIM1_HW_CSN_PRESENT_VALIDATE(...)  0
97 #define SPIM1_DCX_PRESENT_VALIDATE(...)     0
98 #define SPIM1_SUPPORTED_FREQ_VALIDATE(...)  0
99 #endif
100 
101 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
102 #define SPIM2_LENGTH_VALIDATE(...)          SPIMX_LENGTH_VALIDATE(SPIM2, __VA_ARGS__)
103 #define SPIM2_HW_CSN_PRESENT_VALIDATE(...)  SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM2, __VA_ARGS__)
104 #define SPIM2_DCX_PRESENT_VALIDATE(...)     SPIMX_DCX_PRESENT_VALIDATE(SPIM2, __VA_ARGS__)
105 #define SPIM2_SUPPORTED_FREQ_VALIDATE(...)  SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM2, __VA_ARGS__)
106 #else
107 #define SPIM2_LENGTH_VALIDATE(...)          0
108 #define SPIM2_HW_CSN_PRESENT_VALIDATE(...)  0
109 #define SPIM2_DCX_PRESENT_VALIDATE(...)     0
110 #define SPIM2_SUPPORTED_FREQ_VALIDATE(...)  0
111 #endif
112 
113 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
114 #define SPIM3_LENGTH_VALIDATE(...)          SPIMX_LENGTH_VALIDATE(SPIM3, __VA_ARGS__)
115 #define SPIM3_HW_CSN_PRESENT_VALIDATE(...)  SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM3, __VA_ARGS__)
116 #define SPIM3_DCX_PRESENT_VALIDATE(...)     SPIMX_DCX_PRESENT_VALIDATE(SPIM3, __VA_ARGS__)
117 #define SPIM3_SUPPORTED_FREQ_VALIDATE(...)  SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM3, __VA_ARGS__)
118 #else
119 #define SPIM3_LENGTH_VALIDATE(...)          0
120 #define SPIM3_HW_CSN_PRESENT_VALIDATE(...)  0
121 #define SPIM3_DCX_PRESENT_VALIDATE(...)     0
122 #define SPIM3_SUPPORTED_FREQ_VALIDATE(...)  0
123 #endif
124 
125 #if NRFX_CHECK(NRFX_SPIM4_ENABLED)
126 #define SPIM4_LENGTH_VALIDATE(...)          SPIMX_LENGTH_VALIDATE(SPIM4, __VA_ARGS__)
127 #define SPIM4_HW_CSN_PRESENT_VALIDATE(...)  SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM4, __VA_ARGS__)
128 #define SPIM4_DCX_PRESENT_VALIDATE(...)     SPIMX_DCX_PRESENT_VALIDATE(SPIM4, __VA_ARGS__)
129 #define SPIM4_SUPPORTED_FREQ_VALIDATE(...)  SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM4, __VA_ARGS__)
130 #else
131 #define SPIM4_LENGTH_VALIDATE(...)          0
132 #define SPIM4_HW_CSN_PRESENT_VALIDATE(...)  0
133 #define SPIM4_DCX_PRESENT_VALIDATE(...)     0
134 #define SPIM4_SUPPORTED_FREQ_VALIDATE(...)  0
135 #endif
136 
137 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)  \
138     (SPIM0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
139      SPIM1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
140      SPIM2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
141      SPIM3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
142      SPIM4_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len))
143 
144 #define SPIM_HW_CSN_PRESENT_VALIDATE(drv_inst_idx)  \
145     (SPIM0_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
146      SPIM1_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
147      SPIM2_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
148      SPIM3_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
149      SPIM4_HW_CSN_PRESENT_VALIDATE(drv_inst_idx))
150 
151 #define SPIM_DCX_PRESENT_VALIDATE(drv_inst_idx)  \
152     (SPIM0_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
153      SPIM1_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
154      SPIM2_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
155      SPIM3_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
156      SPIM4_DCX_PRESENT_VALIDATE(drv_inst_idx))
157 
158 #define SPIM_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq)  \
159     (SPIM0_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
160      SPIM1_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
161      SPIM2_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
162      SPIM3_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
163      SPIM4_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq))
164 
165 #if defined(NRF52840_XXAA) && (NRFX_CHECK(NRFX_SPIM3_ENABLED))
166 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
167 #define USE_WORKAROUND_FOR_ANOMALY_195
168 #endif
169 
170 
171 // Control block - driver instance local data.
172 typedef struct
173 {
174     nrfx_spim_evt_handler_t handler;
175     void *                  p_context;
176     nrfx_spim_evt_t         evt;  // Keep the struct that is ready for event handler. Less memcpy.
177     nrfx_drv_state_t        state;
178     volatile bool           transfer_in_progress;
179 
180 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
181     bool                    use_hw_ss;
182 #endif
183 
184     // [no need for 'volatile' attribute for the following members, as they
185     //  are not concurrently used in IRQ handlers and main line code]
186     bool            ss_active_high;
187     uint8_t         ss_pin;
188     uint8_t         orc;
189 
190 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
191     size_t          tx_length;
192     size_t          rx_length;
193 #endif
194 } spim_control_block_t;
195 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
196 
197 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
198 
199 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
200 
201 static uint32_t m_anomaly_198_preserved_value;
202 
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)203 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
204 {
205     m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
206 
207     if (buf_len == 0)
208     {
209         return;
210     }
211     uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
212     uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
213     uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
214     uint32_t occupied_blocks = 0;
215 
216     if (block_addr >= 0x20010000)
217     {
218         occupied_blocks = (1UL << 8);
219     }
220     else
221     {
222         do {
223             occupied_blocks |= block_flag;
224             block_flag <<= 1;
225             block_addr  += 0x2000;
226         } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
227     }
228 
229     *((volatile uint32_t *)0x40000E00) = occupied_blocks;
230 }
231 
anomaly_198_disable(void)232 static void anomaly_198_disable(void)
233 {
234     *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
235 }
236 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
237 
spim_abort(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)238 static void spim_abort(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
239 {
240     nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP);
241     bool stopped;
242     NRFX_WAIT_FOR(nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED), 100, 1, stopped);
243     if (!stopped)
244     {
245         NRFX_LOG_ERROR("Failed to stop instance with base address: %p.", (void *)p_spim);
246     }
247     p_cb->transfer_in_progress = false;
248 }
249 
nrfx_spim_init(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config,nrfx_spim_evt_handler_t handler,void * p_context)250 nrfx_err_t nrfx_spim_init(nrfx_spim_t const *        p_instance,
251                           nrfx_spim_config_t const * p_config,
252                           nrfx_spim_evt_handler_t    handler,
253                           void *                     p_context)
254 {
255     NRFX_ASSERT(p_config);
256     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
257     nrfx_err_t err_code;
258 
259     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
260     {
261         err_code = NRFX_ERROR_INVALID_STATE;
262         NRFX_LOG_WARNING("Function: %s, error code: %s.",
263                          __func__,
264                          NRFX_LOG_ERROR_STRING_GET(err_code));
265         return err_code;
266     }
267 
268 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
269     // Check if SPIM instance supports the extended features.
270     if (
271         (!SPIM_SUPPORTED_FREQ_VALIDATE(p_instance->drv_inst_idx, p_config->frequency)) ||
272         ((p_config->use_hw_ss) &&
273          !SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx)) ||
274         ((p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) &&
275          !SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx))
276         )
277     {
278         err_code = NRFX_ERROR_NOT_SUPPORTED;
279         NRFX_LOG_WARNING("Function: %s, error code: %s.",
280                          __func__,
281                          NRFX_LOG_ERROR_STRING_GET(err_code));
282         return err_code;
283     }
284 #endif
285 
286     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
287 
288 #if NRFX_CHECK(NRFX_PRS_ENABLED)
289     static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
290         #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
291         nrfx_spim_0_irq_handler,
292         #endif
293         #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
294         nrfx_spim_1_irq_handler,
295         #endif
296         #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
297         nrfx_spim_2_irq_handler,
298         #endif
299         #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
300         nrfx_spim_3_irq_handler,
301         #endif
302         #if NRFX_CHECK(NRFX_SPIM4_ENABLED)
303         nrfx_spim_4_irq_handler,
304         #endif
305     };
306     if (nrfx_prs_acquire(p_instance->p_reg,
307             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
308     {
309         err_code = NRFX_ERROR_BUSY;
310         NRFX_LOG_WARNING("Function: %s, error code: %s.",
311                          __func__,
312                          NRFX_LOG_ERROR_STRING_GET(err_code));
313         return err_code;
314     }
315 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
316 
317     p_cb->handler = handler;
318     p_cb->p_context = p_context;
319 
320     uint32_t mosi_pin;
321     uint32_t miso_pin;
322     // Configure pins used by the peripheral:
323     // - SCK - output with initial value corresponding with the SPI mode used:
324     //   0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
325     //   according to the reference manual guidelines this pin and its input
326     //   buffer must always be connected for the SPI to work.
327     if (p_config->mode <= NRF_SPIM_MODE_1)
328     {
329         nrf_gpio_pin_clear(p_config->sck_pin);
330     }
331     else
332     {
333         nrf_gpio_pin_set(p_config->sck_pin);
334     }
335     nrf_gpio_cfg(p_config->sck_pin,
336                  NRF_GPIO_PIN_DIR_OUTPUT,
337                  NRF_GPIO_PIN_INPUT_CONNECT,
338                  NRF_GPIO_PIN_NOPULL,
339                  NRF_GPIO_PIN_S0S1,
340                  NRF_GPIO_PIN_NOSENSE);
341     // - MOSI (optional) - output with initial value 0,
342     if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED)
343     {
344         mosi_pin = p_config->mosi_pin;
345         nrf_gpio_pin_clear(mosi_pin);
346         nrf_gpio_cfg_output(mosi_pin);
347     }
348     else
349     {
350         mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED;
351     }
352     // - MISO (optional) - input,
353     if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED)
354     {
355         miso_pin = p_config->miso_pin;
356         nrf_gpio_cfg_input(miso_pin, p_config->miso_pull);
357     }
358     else
359     {
360         miso_pin = NRF_SPIM_PIN_NOT_CONNECTED;
361     }
362     // - Slave Select (optional) - output with initial value 1 (inactive).
363 
364     // 'p_cb->ss_pin' variable is used during transfers to check if SS pin should be toggled,
365     // so this field needs to be initialized even if the pin is not used.
366     p_cb->ss_pin = p_config->ss_pin;
367 
368     if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
369     {
370         if (p_config->ss_active_high)
371         {
372             nrf_gpio_pin_clear(p_config->ss_pin);
373         }
374         else
375         {
376             nrf_gpio_pin_set(p_config->ss_pin);
377         }
378         nrf_gpio_cfg_output(p_config->ss_pin);
379 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
380         if (p_config->use_hw_ss)
381         {
382             p_cb->use_hw_ss = p_config->use_hw_ss;
383             nrf_spim_csn_configure(p_spim,
384                                    p_config->ss_pin,
385                                    (p_config->ss_active_high == true ?
386                                         NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
387                                    p_config->ss_duration);
388         }
389 #endif
390         p_cb->ss_active_high = p_config->ss_active_high;
391     }
392 
393 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
394     // - DCX (optional) - output.
395     if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED)
396     {
397         nrf_gpio_pin_set(p_config->dcx_pin);
398         nrf_gpio_cfg_output(p_config->dcx_pin);
399         nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin);
400     }
401 
402     // Change rx delay
403     nrf_spim_iftiming_set(p_spim, p_config->rx_delay);
404 #endif
405 
406 
407     nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin);
408     nrf_spim_frequency_set(p_spim, p_config->frequency);
409     nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order);
410 
411     nrf_spim_orc_set(p_spim, p_config->orc);
412 
413     nrf_spim_enable(p_spim);
414 
415     if (p_cb->handler)
416     {
417         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
418             p_config->irq_priority);
419         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
420     }
421 
422     p_cb->transfer_in_progress = false;
423     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
424 
425     err_code = NRFX_SUCCESS;
426     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
427     return err_code;
428 }
429 
nrfx_spim_uninit(nrfx_spim_t const * p_instance)430 void nrfx_spim_uninit(nrfx_spim_t const * p_instance)
431 {
432     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
433     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
434     NRF_SPIM_Type * p_spim = p_instance->p_reg;
435 
436     if (p_cb->handler)
437     {
438         NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
439         nrf_spim_int_disable(p_spim, NRF_SPIM_ALL_INTS_MASK);
440         if (p_cb->transfer_in_progress)
441         {
442             // Ensure that SPI is not performing any transfer.
443             spim_abort(p_spim, p_cb);
444         }
445     }
446 
447     nrf_spim_disable(p_spim);
448 
449     nrf_gpio_cfg_default(nrf_spim_sck_pin_get(p_spim));
450 
451     uint32_t miso_pin = nrf_spim_miso_pin_get(p_spim);
452     if (miso_pin != NRF_SPIM_PIN_NOT_CONNECTED)
453     {
454         nrf_gpio_cfg_default(miso_pin);
455     }
456 
457     uint32_t mosi_pin = nrf_spim_mosi_pin_get(p_spim);
458     if (mosi_pin != NRF_SPIM_PIN_NOT_CONNECTED)
459     {
460         nrf_gpio_cfg_default(mosi_pin);
461     }
462 
463     if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
464     {
465         nrf_gpio_cfg_default(p_cb->ss_pin);
466     }
467 
468 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
469     uint32_t dcx_pin = nrf_spim_dcx_pin_get(p_spim);
470     if (dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED)
471     {
472         nrf_gpio_cfg_default(dcx_pin);
473     }
474 #endif
475 
476 #ifdef USE_WORKAROUND_FOR_ANOMALY_195
477     if (p_spim == NRF_SPIM3)
478     {
479         *(volatile uint32_t *)0x4002F004 = 1;
480     }
481 #endif
482 
483 #if NRFX_CHECK(NRFX_PRS_ENABLED)
484     nrfx_prs_release(p_instance->p_reg);
485 #endif
486 
487     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
488 }
489 
490 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
nrfx_spim_xfer_dcx(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags,uint8_t cmd_length)491 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const *           p_instance,
492                               nrfx_spim_xfer_desc_t const * p_xfer_desc,
493                               uint32_t                      flags,
494                               uint8_t                       cmd_length)
495 {
496     NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
497     nrf_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
498     return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
499 }
500 #endif
501 
finish_transfer(spim_control_block_t * p_cb)502 static void finish_transfer(spim_control_block_t * p_cb)
503 {
504     // If Slave Select signal is used, this is the time to deactivate it.
505     if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
506     {
507 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
508         if (!p_cb->use_hw_ss)
509 #endif
510         {
511             if (p_cb->ss_active_high)
512             {
513                 nrf_gpio_pin_clear(p_cb->ss_pin);
514             }
515             else
516             {
517                 nrf_gpio_pin_set(p_cb->ss_pin);
518             }
519         }
520     }
521 
522     // By clearing this flag before calling the handler we allow subsequent
523     // transfers to be started directly from the handler function.
524     p_cb->transfer_in_progress = false;
525 
526     p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
527     p_cb->handler(&p_cb->evt, p_cb->p_context);
528 }
529 
spim_int_enable(NRF_SPIM_Type * p_spim,bool enable)530 static void spim_int_enable(NRF_SPIM_Type * p_spim, bool enable)
531 {
532     if (!enable)
533     {
534         nrf_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
535     }
536     else
537     {
538         nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
539     }
540 }
541 
spim_list_enable_handle(NRF_SPIM_Type * p_spim,uint32_t flags)542 static void spim_list_enable_handle(NRF_SPIM_Type * p_spim, uint32_t flags)
543 {
544     if (NRFX_SPIM_FLAG_TX_POSTINC & flags)
545     {
546         nrf_spim_tx_list_enable(p_spim);
547     }
548     else
549     {
550         nrf_spim_tx_list_disable(p_spim);
551     }
552 
553     if (NRFX_SPIM_FLAG_RX_POSTINC & flags)
554     {
555         nrf_spim_rx_list_enable(p_spim);
556     }
557     else
558     {
559         nrf_spim_rx_list_disable(p_spim);
560     }
561 }
562 
spim_xfer(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)563 static nrfx_err_t spim_xfer(NRF_SPIM_Type               * p_spim,
564                             spim_control_block_t        * p_cb,
565                             nrfx_spim_xfer_desc_t const * p_xfer_desc,
566                             uint32_t                      flags)
567 {
568     nrfx_err_t err_code;
569     // EasyDMA requires that transfer buffers are placed in Data RAM region;
570     // signal error if they are not.
571     if ((p_xfer_desc->p_tx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_tx_buffer)) ||
572         (p_xfer_desc->p_rx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_rx_buffer)))
573     {
574         p_cb->transfer_in_progress = false;
575         err_code = NRFX_ERROR_INVALID_ADDR;
576         NRFX_LOG_WARNING("Function: %s, error code: %s.",
577                          __func__,
578                          NRFX_LOG_ERROR_STRING_GET(err_code));
579         return err_code;
580     }
581 
582 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
583     p_cb->tx_length = 0;
584     p_cb->rx_length = 0;
585 #endif
586 
587     nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
588     nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, p_xfer_desc->rx_length);
589 
590 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
591     if (p_spim == NRF_SPIM3)
592     {
593         anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
594     }
595 #endif
596 
597     nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
598 
599     spim_list_enable_handle(p_spim, flags);
600 
601     if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
602     {
603         nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
604     }
605 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
606     if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
607     {
608         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
609         p_cb->tx_length = p_xfer_desc->tx_length;
610         p_cb->rx_length = p_xfer_desc->rx_length;
611         nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, 0);
612         nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, 0);
613         nrf_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
614     }
615 #endif
616 
617     if (!p_cb->handler)
618     {
619         if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
620         {
621             while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
622             {}
623         }
624 
625 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
626         if (p_spim == NRF_SPIM3)
627         {
628             anomaly_198_disable();
629         }
630 #endif
631         if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
632         {
633 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
634             if (!p_cb->use_hw_ss)
635 #endif
636             {
637                 if (p_cb->ss_active_high)
638                 {
639                     nrf_gpio_pin_clear(p_cb->ss_pin);
640                 }
641                 else
642                 {
643                     nrf_gpio_pin_set(p_cb->ss_pin);
644                 }
645             }
646         }
647     }
648     else
649     {
650         spim_int_enable(p_spim, !(flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER));
651     }
652     err_code = NRFX_SUCCESS;
653     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
654     return err_code;
655 }
656 
nrfx_spim_xfer(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)657 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const *           p_instance,
658                           nrfx_spim_xfer_desc_t const * p_xfer_desc,
659                           uint32_t                      flags)
660 {
661     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
662     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
663     NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
664     NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
665     NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
666                                      p_xfer_desc->rx_length,
667                                      p_xfer_desc->tx_length));
668     NRFX_ASSERT(!(flags & NRFX_SPIM_FLAG_HOLD_XFER) ||
669                 (p_cb->ss_pin == NRFX_SPIM_PIN_NOT_USED));
670 
671     nrfx_err_t err_code = NRFX_SUCCESS;
672 
673     if (p_cb->transfer_in_progress)
674     {
675         err_code = NRFX_ERROR_BUSY;
676         NRFX_LOG_WARNING("Function: %s, error code: %s.",
677                          __func__,
678                          NRFX_LOG_ERROR_STRING_GET(err_code));
679         return err_code;
680     }
681     else
682     {
683         if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
684                                         NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
685         {
686             p_cb->transfer_in_progress = true;
687         }
688     }
689 
690     p_cb->evt.xfer_desc = *p_xfer_desc;
691 
692     if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
693     {
694 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
695         if (!p_cb->use_hw_ss)
696 #endif
697         {
698             if (p_cb->ss_active_high)
699             {
700                 nrf_gpio_pin_set(p_cb->ss_pin);
701             }
702             else
703             {
704                 nrf_gpio_pin_clear(p_cb->ss_pin);
705             }
706         }
707     }
708 
709     return spim_xfer(p_instance->p_reg, p_cb,  p_xfer_desc, flags);
710 }
711 
nrfx_spim_abort(nrfx_spim_t const * p_instance)712 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
713 {
714     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
715     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
716 
717     spim_abort(p_instance->p_reg, p_cb);
718 }
719 
nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)720 uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)
721 {
722     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
723     return nrf_spim_task_address_get(p_spim, NRF_SPIM_TASK_START);
724 }
725 
nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)726 uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)
727 {
728     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
729     return nrf_spim_event_address_get(p_spim, NRF_SPIM_EVENT_END);
730 }
731 
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)732 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
733 {
734 
735 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
736     if ((nrf_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK)) &&
737         (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED)) )
738     {
739         /* Handle first, zero-length, auxiliary transmission. */
740         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
741         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
742 
743         NRFX_ASSERT(p_spim->TXD.MAXCNT == 0);
744         p_spim->TXD.MAXCNT = p_cb->tx_length;
745 
746         NRFX_ASSERT(p_spim->RXD.MAXCNT == 0);
747         p_spim->RXD.MAXCNT = p_cb->rx_length;
748 
749         /* Disable STARTED interrupt, used only in auxiliary transmission. */
750         nrf_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
751 
752         /* Start the actual, glitch-free transmission. */
753         nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
754         return;
755     }
756 #endif
757 
758     if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
759     {
760 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
761         if (p_spim == NRF_SPIM3)
762         {
763             anomaly_198_disable();
764         }
765 #endif
766         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
767         NRFX_ASSERT(p_cb->handler);
768         NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
769         finish_transfer(p_cb);
770     }
771 }
772 
773 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
nrfx_spim_0_irq_handler(void)774 void nrfx_spim_0_irq_handler(void)
775 {
776     irq_handler(NRF_SPIM0, &m_cb[NRFX_SPIM0_INST_IDX]);
777 }
778 #endif
779 
780 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
nrfx_spim_1_irq_handler(void)781 void nrfx_spim_1_irq_handler(void)
782 {
783     irq_handler(NRF_SPIM1, &m_cb[NRFX_SPIM1_INST_IDX]);
784 }
785 #endif
786 
787 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
nrfx_spim_2_irq_handler(void)788 void nrfx_spim_2_irq_handler(void)
789 {
790     irq_handler(NRF_SPIM2, &m_cb[NRFX_SPIM2_INST_IDX]);
791 }
792 #endif
793 
794 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
nrfx_spim_3_irq_handler(void)795 void nrfx_spim_3_irq_handler(void)
796 {
797     irq_handler(NRF_SPIM3, &m_cb[NRFX_SPIM3_INST_IDX]);
798 }
799 #endif
800 
801 #if NRFX_CHECK(NRFX_SPIM4_ENABLED)
nrfx_spim_4_irq_handler(void)802 void nrfx_spim_4_irq_handler(void)
803 {
804     irq_handler(NRF_SPIM4, &m_cb[NRFX_SPIM4_INST_IDX]);
805 }
806 #endif
807 
808 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
809