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_SPIM_ENABLED)
37 
38 #if !NRFX_FEATURE_PRESENT(NRFX_SPIM, _ENABLED)
39 #error "No enabled SPIM instances. Check <nrfx_config.h>."
40 #endif
41 
42 #include <nrfx_spim.h>
43 #include "prs/nrfx_prs.h"
44 
45 #define NRFX_LOG_MODULE SPIM
46 #include <nrfx_log.h>
47 
48 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && !NRFY_SPIM_HAS_EXTENDED
49 #error "Extended options are not available in the SoC currently in use."
50 #endif
51 
52 #define _NRFX_NUM_FEATURE_TOKEN(periph, inst, feature) \
53     NRFX_CONCAT(NRFX_CONCAT(periph, _, feature, _TOKEN), NRFX_CONCAT(inst, _, feature))
54 
55 #define _NRFX_NUM_FEATURE_SUPPORTED_MASK(periph, prefix, i, feature)                           \
56     NRFX_COND_CODE_1(_NRFX_NUM_FEATURE_TOKEN(periph, NRFX_CONCAT(periph, prefix, i), feature), \
57                     ((1UL << NRFX_CONCAT(NRFX_, periph, prefix, i, _INST_IDX))), (0))
58 
59 /**
60  * @brief Macro initializes a mask with n bit set if nth driver instance supports the given numeric feature.
61  *
62  * Bits associated with non existing instances are set so that if all enabled instances supports
63  * the given feature mask has all 1 (and potentially can be optimized by the compiler).
64  *
65  * In order to determine if a given flag is set to a specific numeric value a token must be defined.
66  * Token must be defined to 1 and follow the name convention \<periph_name\>_\<feature\>_TOKEN\<value\>.
67  *
68  * @param periph  Peripheral name.
69  * @param feature Feature name as used in the _peripherals.h.
70  */
71 #define NRFX_NUM_FEATURE_SUPPORTED_MASK(periph, feature)                                     \
72         (~(NRFX_BIT(NRFX_CONCAT(NRFX_, periph, _ENABLED_COUNT)) - 1) |                       \
73          (NRFX_FOREACH_ENABLED(periph, _NRFX_NUM_FEATURE_SUPPORTED_MASK, (|), (0), feature)))
74 
75 /* Internal helper macro which returns a bit mask set if nth driver instance supports the given feature. */
76 #define _NRFX_SUPPORTED_FEATURE_MASK(periph, prefix, i, feature) \
77     NRFX_COND_CODE_1(NRFX_CONCAT(periph, prefix, i, _, feature), \
78                     ((1UL << NRFX_CONCAT(NRFX_, periph, prefix, i, _INST_IDX))), (0))
79 
80 /**
81  * @brief Macro initializes a mask with n bit set if nth driver instance supports the given feature.
82  *
83  * Bits associated with non existing instances are set so that if all enabled instances supports
84  * the given feature mask has all 1 (and potentially can be optimized by the compiler).
85  *
86  * @param periph  Peripheral name.
87  * @param feature Feature name as used in the _peripherals.h.
88  */
89 #define NRFX_FEATURE_SUPPORTED_MASK(periph, feature)                                    \
90         (~(NRFX_BIT(NRFX_CONCAT(NRFX_, periph, _ENABLED_COUNT)) - 1) |                  \
91         (NRFX_FOREACH_ENABLED(periph, _NRFX_SUPPORTED_FEATURE_MASK, (|), (0), feature)))
92 
93 #define _NRFX_INST_FEATURE_FLAG(periph, prefix, i, feature) NRFX_CONCAT(periph, prefix, i, _, feature),
94 
95 /**
96  * @brief Macro initializes an array with numeric, feature value for each enabled driver instance.
97  *
98  * Array can be used as a lookup table to determine how the given feature is supported by the
99  * instance.
100  *
101  * @param periph  Peripheral name.
102  * @param feature Feature name as used in the _peripherals.h.
103  */
104 #define NRFX_FEATURE_ARRAY_INITIALIZE(periph, feature) \
105     { NRFX_FOREACH_ENABLED(periph, _NRFX_INST_FEATURE_FLAG, (), (), feature) }
106 
107 /* Token used to determine if SPIM instance supports 32M data rate. */
108 #define SPIM_MAX_DATARATE_TOKEN32 1
109 
110 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
111 static const uint32_t dcx_support_mask =
112     NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_DCX_PRESENT);
113 static const uint32_t hw_csn_support_mask =
114     NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_HARDWARE_CSN_PRESENT);
115 static const uint32_t datarate32_support_mask =
116     NRFX_NUM_FEATURE_SUPPORTED_MASK(SPIM, MAX_DATARATE);
117 #endif
118 
119 static const uint8_t easydma_support_bits[] __UNUSED =
120     NRFX_FEATURE_ARRAY_INITIALIZE(SPIM, EASYDMA_MAXCNT_SIZE);
121 
122 #define SPIM_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq)          \
123             (((freq != NRFX_MHZ_TO_HZ(32)) && (freq != NRFX_MHZ_TO_HZ(16))) || \
124              ((NRFX_BIT(drv_inst_idx)) & datarate32_support_mask))
125 
126 #define SPIM_DCX_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & dcx_support_mask)
127 
128 #define SPIM_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & hw_csn_support_mask)
129 
130 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)          \
131             ((rx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])) && \
132              (tx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])))
133 
134 // Requested pin can either match dedicated pin or be not connected at all.
135 #define SPIM_DEDICATED_PIN_VALIDATE(requested_pin, supported_pin) \
136     (((requested_pin) == NRF_SPIM_PIN_NOT_CONNECTED) || ((requested_pin) == (supported_pin)))
137 
138 #if !defined(USE_WORKAROUND_FOR_ANOMALY_195) && \
139     defined(NRF52840_XXAA) && NRFX_CHECK(NRFX_SPIM3_ENABLED)
140 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
141 #define USE_WORKAROUND_FOR_ANOMALY_195 1
142 #endif
143 
144 // Control block - driver instance local data.
145 typedef struct
146 {
147     nrfx_spim_evt_handler_t handler;
148     void *                  p_context;
149     nrfx_spim_evt_t         evt;  // Keep the struct that is ready for event handler. Less memcpy.
150     nrfx_drv_state_t        state;
151     volatile bool           transfer_in_progress;
152     bool                    skip_gpio_cfg  : 1;
153     bool                    ss_active_high;
154     uint32_t                ss_pin;
155 } spim_control_block_t;
156 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
157 
158 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
159 
160 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
161 
162 static uint32_t m_anomaly_198_preserved_value;
163 
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)164 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
165 {
166     m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
167 
168     if (buf_len == 0)
169     {
170         return;
171     }
172     uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
173     uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
174     uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
175     uint32_t occupied_blocks = 0;
176 
177     if (block_addr >= 0x20010000)
178     {
179         occupied_blocks = (1UL << 8);
180     }
181     else
182     {
183         do {
184             occupied_blocks |= block_flag;
185             block_flag <<= 1;
186             block_addr  += 0x2000;
187         } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
188     }
189 
190     *((volatile uint32_t *)0x40000E00) = occupied_blocks;
191 }
192 
anomaly_198_disable(void)193 static void anomaly_198_disable(void)
194 {
195     *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
196 }
197 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
198 
spim_abort(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)199 static void spim_abort(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
200 {
201     nrfy_spim_abort(p_spim, NULL);
202     bool stopped;
203     uint32_t stopped_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_STOPPED);
204     NRFX_WAIT_FOR(nrfy_spim_events_process(p_spim, stopped_mask, NULL), 100, 1, stopped);
205     if (!stopped)
206     {
207         NRFX_LOG_ERROR("Failed to stop instance with base address: %p.", (void *)p_spim);
208     }
209     p_cb->transfer_in_progress = false;
210     nrfy_spim_disable(p_spim);
211 }
212 
pin_init(uint32_t pin,nrf_gpio_pin_dir_t dir,nrf_gpio_pin_pull_t pull,nrf_gpio_pin_drive_t drive,uint32_t initial_state)213 static void pin_init(uint32_t             pin,
214                      nrf_gpio_pin_dir_t   dir,
215                      nrf_gpio_pin_pull_t  pull,
216                      nrf_gpio_pin_drive_t drive,
217                      uint32_t             initial_state)
218 {
219     nrf_gpio_pin_input_t input;
220 
221     if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
222     {
223         return;
224     }
225 
226     if (dir == NRF_GPIO_PIN_DIR_OUTPUT)
227     {
228         if (initial_state)
229         {
230             nrfy_gpio_pin_set(pin);
231         }
232         else
233         {
234             nrfy_gpio_pin_clear(pin);
235         }
236         input = NRF_GPIO_PIN_INPUT_DISCONNECT;
237     }
238     else
239     {
240         input = NRF_GPIO_PIN_INPUT_CONNECT;
241     }
242 
243     nrfy_gpio_cfg(pin, dir, input, pull, drive, NRF_GPIO_PIN_NOSENSE);
244 }
245 
configure_pins(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)246 static void configure_pins(nrfx_spim_t const *        p_instance,
247                            nrfx_spim_config_t const * p_config)
248 {
249     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
250 
251     p_cb->ss_active_high = p_config->ss_active_high;
252 
253     if (p_config->skip_gpio_cfg)
254     {
255         return;
256     }
257 
258     nrf_gpio_pin_drive_t pin_drive;
259     // Configure pin drive - high drive for 32 MHz clock frequency.
260 #if (NRF_SPIM_HAS_FREQUENCY && NRF_SPIM_HAS_32_MHZ_FREQ) || NRF_SPIM_HAS_PRESCALER
261     pin_drive = (p_config->frequency == NRFX_MHZ_TO_HZ(32)) ? NRF_GPIO_PIN_H0H1 : NRF_GPIO_PIN_S0S1;
262 #else
263     pin_drive = NRF_GPIO_PIN_S0S1;
264 #endif
265     // Configure pins used by the peripheral:
266     // - SCK - output with initial value corresponding with the SPI mode used:
267     //   0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
268     //   according to the reference manual guidelines this pin and its input
269     //   buffer must always be connected for the SPI to work.
270     uint32_t sck_val = (p_config->mode <= NRF_SPIM_MODE_1) ? 0 : 1;
271     pin_init(p_config->sck_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, sck_val);
272 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_SCK_NEEDED)
273     nrfy_gpio_pin_clock_set(p_config->sck_pin, true);
274 #endif
275     // - MOSI (optional) - output with initial value 0
276     pin_init(p_config->mosi_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 0);
277 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_MOSI_NEEDED)
278     nrfy_gpio_pin_clock_set(p_config->mosi_pin, true);
279 #endif
280     // - MISO (optional) - input
281     pin_init(p_config->miso_pin, NRF_GPIO_PIN_DIR_INPUT, p_config->miso_pull, pin_drive, 0);
282     // - Slave Select (optional) - output with initial value 1 (inactive).
283     uint32_t ss_val = !p_config->ss_active_high;
284     pin_init(p_config->ss_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, ss_val);
285 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
286     // - DCX (optional) - output.
287     pin_init(p_config->dcx_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 1);
288 #endif
289 }
290 
291 #if NRF_SPIM_HAS_FREQUENCY
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)292 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
293 {
294     (void)p_instance;
295     switch (frequency)
296     {
297         case NRFX_KHZ_TO_HZ(125):
298             /* FALLTHROUGH */
299         case NRFX_KHZ_TO_HZ(250):
300             /* FALLTHROUGH */
301         case NRFX_KHZ_TO_HZ(500):
302             /* FALLTHROUGH */
303         case NRFX_MHZ_TO_HZ(1):
304             /* FALLTHROUGH */
305         case NRFX_MHZ_TO_HZ(2):
306             /* FALLTHROUGH */
307         case NRFX_MHZ_TO_HZ(4):
308             /* FALLTHROUGH */
309         case NRFX_MHZ_TO_HZ(8):
310             return true;
311 #if NRF_SPIM_HAS_16_MHZ_FREQ
312         case NRFX_MHZ_TO_HZ(16):
313             return true;
314 #endif
315 #if NRF_SPIM_HAS_32_MHZ_FREQ
316         case NRFX_MHZ_TO_HZ(32):
317             return true;
318 #endif
319         default:
320             return false;
321     }
322 }
323 
spim_frequency_bit_decode(uint32_t frequency)324 static nrf_spim_frequency_t spim_frequency_bit_decode(uint32_t frequency)
325 {
326     switch (frequency)
327     {
328         case NRFX_KHZ_TO_HZ(125):
329             return NRF_SPIM_FREQ_125K;
330         case NRFX_KHZ_TO_HZ(250):
331             return NRF_SPIM_FREQ_250K;
332         case NRFX_KHZ_TO_HZ(500):
333             return NRF_SPIM_FREQ_500K;
334         case NRFX_MHZ_TO_HZ(1):
335             return NRF_SPIM_FREQ_1M;
336         case NRFX_MHZ_TO_HZ(2):
337             return NRF_SPIM_FREQ_2M;
338         case NRFX_MHZ_TO_HZ(4):
339             return NRF_SPIM_FREQ_4M;
340         case NRFX_MHZ_TO_HZ(8):
341             return NRF_SPIM_FREQ_8M;
342 #if NRF_SPIM_HAS_16_MHZ_FREQ
343         case NRFX_MHZ_TO_HZ(16):
344             return NRF_SPIM_FREQ_16M;
345 #endif
346 #if NRF_SPIM_HAS_32_MHZ_FREQ
347         case NRFX_MHZ_TO_HZ(32):
348             return NRF_SPIM_FREQ_32M;
349 #endif
350         default:
351             NRFX_ASSERT(false);
352             return NRF_SPIM_FREQ_4M;
353     }
354 }
355 #elif NRF_SPIM_HAS_PRESCALER
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)356 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
357 {
358     uint32_t base_frequency = NRFX_SPIM_BASE_FREQUENCY_GET(p_instance);
359     uint32_t prescaler = NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
360 
361     return ((base_frequency % frequency) < prescaler) &&
362             NRFX_IS_EVEN(prescaler) &&
363             (prescaler <= NRF_SPIM_PRESCALER_MAX_GET(p_instance->p_reg)) &&
364             (prescaler >= NRF_SPIM_PRESCALER_MIN_GET(p_instance->p_reg));
365 }
366 
spim_prescaler_calculate(nrfx_spim_t const * p_instance,uint32_t frequency)367 static uint32_t spim_prescaler_calculate(nrfx_spim_t const * p_instance, uint32_t frequency)
368 {
369     return NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
370 }
371 #else
372     #error "Unable to determine frequency division support type."
373 #endif
374 
spim_configuration_verify(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)375 static nrfx_err_t spim_configuration_verify(nrfx_spim_t const *        p_instance,
376                                             nrfx_spim_config_t const * p_config)
377 {
378     nrfx_err_t err_code;
379     if (!spim_frequency_valid_check(p_instance, p_config->frequency))
380     {
381         err_code = NRFX_ERROR_INVALID_PARAM;
382         NRFX_LOG_WARNING("Function: %s, error code: %s.",
383                          __func__,
384                          NRFX_LOG_ERROR_STRING_GET(err_code));
385         return err_code;
386     }
387 
388 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
389     // Check if SPIM instance supports the extended features.
390     if (!SPIM_SUPPORTED_FREQ_VALIDATE(p_instance->drv_inst_idx, p_config->frequency) ||
391          (p_config->use_hw_ss && (p_config->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
392           !SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx)) ||
393          ((p_config->dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
394           !SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx)))
395     {
396         err_code = NRFX_ERROR_NOT_SUPPORTED;
397         NRFX_LOG_WARNING("Function: %s, error code: %s.",
398                          __func__,
399                          NRFX_LOG_ERROR_STRING_GET(err_code));
400         return err_code;
401     }
402 
403 #if NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
404     // Check if dedicated SPIM pins are used, unless both GPIO configuration
405     // and pin selection are to be skipped (pin numbers may be not specified
406     // in such case).
407     if (!(p_config->skip_gpio_cfg && p_config->skip_psel_cfg) &&
408         (p_instance->p_reg == NRF_SPIM4) && (p_config->frequency == NRFX_MHZ_TO_HZ(32)))
409     {
410         enum {
411             SPIM_SCK_DEDICATED  = NRF_GPIO_PIN_MAP(0, 8),
412             SPIM_MOSI_DEDICATED = NRF_GPIO_PIN_MAP(0, 9),
413             SPIM_MISO_DEDICATED = NRF_GPIO_PIN_MAP(0, 10),
414             SPIM_CSN_DEDICATED  = NRF_GPIO_PIN_MAP(0, 11),
415             SPIM_DCX_DEDICATED  = NRF_GPIO_PIN_MAP(0, 12),
416         };
417 
418         if (!SPIM_DEDICATED_PIN_VALIDATE(p_config->sck_pin, SPIM_SCK_DEDICATED) ||
419             !SPIM_DEDICATED_PIN_VALIDATE(p_config->mosi_pin, SPIM_MOSI_DEDICATED) ||
420             !SPIM_DEDICATED_PIN_VALIDATE(p_config->miso_pin, SPIM_MISO_DEDICATED) ||
421             (p_config->use_hw_ss &&
422              !SPIM_DEDICATED_PIN_VALIDATE(p_config->ss_pin, SPIM_CSN_DEDICATED)) ||
423             !SPIM_DEDICATED_PIN_VALIDATE(p_config->dcx_pin, SPIM_DCX_DEDICATED))
424         {
425             err_code = NRFX_ERROR_INVALID_PARAM;
426             NRFX_LOG_WARNING("Function: %s, error code: %s.",
427                              __func__,
428                              NRFX_LOG_ERROR_STRING_GET(err_code));
429             return err_code;
430         }
431     }
432 #endif // NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
433 
434 #else
435     (void)p_instance;
436     (void)p_config;
437 #endif // NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
438     return NRFX_SUCCESS;
439 }
440 
spim_configure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)441 static void spim_configure(nrfx_spim_t const *        p_instance,
442                            nrfx_spim_config_t const * p_config)
443 {
444     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
445 
446 #if NRF_SPIM_HAS_FREQUENCY
447     nrf_spim_frequency_t frequency = spim_frequency_bit_decode(p_config->frequency);
448 #elif NRF_SPIM_HAS_PRESCALER
449     uint32_t prescaler = spim_prescaler_calculate(p_instance, p_config->frequency);
450 #endif
451 
452     p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
453     configure_pins(p_instance, p_config);
454 
455 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
456     bool ext_support = NRFX_BIT(p_instance->drv_inst_idx) & hw_csn_support_mask;
457     bool hw_csn = p_config->use_hw_ss;
458     if (ext_support && hw_csn)
459     {
460         p_cb->ss_pin = NRF_SPIM_PIN_NOT_CONNECTED;
461     }
462     else
463 #endif
464     {
465         p_cb->ss_pin = p_config->ss_pin;
466         p_cb->ss_active_high = p_config->ss_active_high;
467     }
468 
469     nrfy_spim_config_t nrfy_config =
470     {
471         .pins =
472         {
473             .sck_pin  = p_config->sck_pin,
474             .mosi_pin = p_config->mosi_pin,
475             .miso_pin = p_config->miso_pin
476         },
477         .orc       = p_config->orc,
478 #if NRF_SPIM_HAS_FREQUENCY
479         .frequency = frequency,
480 #elif NRF_SPIM_HAS_PRESCALER
481         .prescaler = prescaler,
482 #endif
483         .mode      = p_config->mode,
484         .bit_order = p_config->bit_order,
485 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
486         .ext_config =
487         {
488             .pins =
489             {
490                 .dcx_pin = p_config->dcx_pin,
491                 .csn_pin = p_config->use_hw_ss ? p_config->ss_pin : NRF_SPIM_PIN_NOT_CONNECTED
492             },
493             .csn_pol      = p_config->ss_active_high ? NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW,
494             .csn_duration = p_config->ss_duration,
495             .rx_delay     = p_config->rx_delay
496         },
497         .ext_enable = ext_support && (hw_csn || (p_config->dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED)),
498 #endif // NRFX_SPIM_EXTENDED_ENABLED
499         .skip_psel_cfg = p_config->skip_psel_cfg
500     };
501 
502     nrfy_spim_periph_configure(p_instance->p_reg, &nrfy_config);
503     if (m_cb[p_instance->drv_inst_idx].handler)
504     {
505         nrfy_spim_int_init(p_instance->p_reg, 0, p_config->irq_priority, false);
506     }
507 }
508 
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)509 nrfx_err_t nrfx_spim_init(nrfx_spim_t const *        p_instance,
510                           nrfx_spim_config_t const * p_config,
511                           nrfx_spim_evt_handler_t    handler,
512                           void *                     p_context)
513 {
514     NRFX_ASSERT(p_config);
515 
516     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
517     nrfx_err_t err_code;
518 
519     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
520     {
521 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
522         err_code = NRFX_ERROR_ALREADY;
523 #else
524         err_code = NRFX_ERROR_INVALID_STATE;
525 #endif
526         NRFX_LOG_WARNING("Function: %s, error code: %s.",
527                          __func__,
528                          NRFX_LOG_ERROR_STRING_GET(err_code));
529         return err_code;
530     }
531 
532     if (p_config)
533     {
534         err_code = spim_configuration_verify(p_instance, p_config);
535         if (err_code != NRFX_SUCCESS)
536         {
537             return err_code;
538         }
539     }
540 
541 #if NRFX_CHECK(NRFX_PRS_ENABLED)
542     static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
543         NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPIM, spim)
544     };
545     if (nrfx_prs_acquire(p_instance->p_reg, irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
546     {
547         err_code = NRFX_ERROR_BUSY;
548         NRFX_LOG_WARNING("Function: %s, error code: %s.",
549                          __func__,
550                          NRFX_LOG_ERROR_STRING_GET(err_code));
551         return err_code;
552     }
553 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
554 
555     p_cb->handler = handler;
556     p_cb->p_context = p_context;
557 
558     if (p_config)
559     {
560         spim_configure(p_instance, p_config);
561     }
562 
563     p_cb->transfer_in_progress = false;
564     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
565 
566     err_code = NRFX_SUCCESS;
567     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
568     return err_code;
569 }
570 
nrfx_spim_reconfigure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)571 nrfx_err_t nrfx_spim_reconfigure(nrfx_spim_t const *        p_instance,
572                                  nrfx_spim_config_t const * p_config)
573 {
574     NRFX_ASSERT(p_config);
575 
576     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
577 
578     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
579     {
580         return NRFX_ERROR_INVALID_STATE;
581     }
582     if (p_cb->transfer_in_progress)
583     {
584         return NRFX_ERROR_BUSY;
585     }
586     nrfx_err_t err_code = spim_configuration_verify(p_instance, p_config);
587     if (err_code != NRFX_SUCCESS)
588     {
589         return err_code;
590     }
591 
592     spim_configure(p_instance, p_config);
593 
594     return NRFX_SUCCESS;
595 }
596 
spim_pin_uninit(uint32_t pin)597 static void spim_pin_uninit(uint32_t pin)
598 {
599     if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
600     {
601         return;
602     }
603 
604     nrfy_gpio_cfg_default(pin);
605 }
606 
nrfx_spim_uninit(nrfx_spim_t const * p_instance)607 void nrfx_spim_uninit(nrfx_spim_t const * p_instance)
608 {
609     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
610 
611     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
612 
613     nrfy_spim_int_uninit(p_instance->p_reg);
614     if (p_cb->handler)
615     {
616         nrfy_spim_int_disable(p_instance->p_reg, NRF_SPIM_ALL_INTS_MASK);
617         spim_abort(p_instance->p_reg, p_cb);
618     }
619 
620     nrfy_spim_pins_t pins;
621     nrfy_spim_pins_get(p_instance->p_reg, &pins);
622 
623     if (!p_cb->skip_gpio_cfg)
624     {
625         spim_pin_uninit(pins.sck_pin);
626         spim_pin_uninit(pins.miso_pin);
627         spim_pin_uninit(pins.mosi_pin);
628         spim_pin_uninit(p_cb->ss_pin);
629 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
630         if (SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx) &&
631             SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx))
632         {
633             nrfy_spim_ext_pins_t ext_pins;
634             nrfy_spim_ext_pins_get(p_instance->p_reg, &ext_pins);
635             spim_pin_uninit(ext_pins.dcx_pin);
636             spim_pin_uninit(ext_pins.csn_pin);
637         }
638 #endif
639     }
640 
641 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_195)
642     if (p_instance->p_reg == NRF_SPIM3)
643     {
644         *(volatile uint32_t *)0x4002F004 = 1;
645     }
646 #endif
647 
648 #if NRFX_CHECK(NRFX_PRS_ENABLED)
649     nrfx_prs_release(p_instance->p_reg);
650 #endif
651 
652     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
653     NRFX_LOG_INFO("Uninitialized.");
654 }
655 
nrfx_spim_init_check(nrfx_spim_t const * p_instance)656 bool nrfx_spim_init_check(nrfx_spim_t const * p_instance)
657 {
658     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
659 
660     return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
661 }
662 
663 #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)664 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const *           p_instance,
665                               nrfx_spim_xfer_desc_t const * p_xfer_desc,
666                               uint32_t                      flags,
667                               uint8_t                       cmd_length)
668 {
669     (void)flags;
670 
671     NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
672 
673     nrfy_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
674     return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
675 }
676 #endif
677 
set_ss_pin_state(spim_control_block_t * p_cb,bool active)678 static void set_ss_pin_state(spim_control_block_t * p_cb, bool active)
679 {
680     if (p_cb->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED)
681     {
682         if (p_cb->ss_active_high)
683         {
684             if (active)
685             {
686                 nrfy_gpio_pin_set(p_cb->ss_pin);
687             }
688             else
689             {
690                 nrfy_gpio_pin_clear(p_cb->ss_pin);
691             }
692         }
693         else
694         {
695             if (active)
696             {
697                 nrfy_gpio_pin_clear(p_cb->ss_pin);
698             }
699             else
700             {
701                 nrfy_gpio_pin_set(p_cb->ss_pin);
702             }
703         }
704     }
705 }
706 
finish_transfer(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)707 static void finish_transfer(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
708 {
709     // If Slave Select signal is used, this is the time to deactivate it.
710     set_ss_pin_state(p_cb, false);
711 
712     // By clearing this flag before calling the handler we allow subsequent
713     // transfers to be started directly from the handler function.
714     if (p_cb->transfer_in_progress)
715     {
716         spim_abort(p_spim, p_cb);
717     }
718 
719     p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
720     p_cb->handler(&p_cb->evt, p_cb->p_context);
721 }
722 
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)723 static nrfx_err_t spim_xfer(NRF_SPIM_Type               * p_spim,
724                             spim_control_block_t        * p_cb,
725                             nrfx_spim_xfer_desc_t const * p_xfer_desc,
726                             uint32_t                      flags)
727 {
728     nrfx_err_t err_code;
729     // EasyDMA requires that transfer buffers are placed in Data RAM region;
730     // signal error if they are not.
731     if ((p_xfer_desc->p_tx_buffer != NULL &&
732          !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_tx_buffer)) ||
733         (p_xfer_desc->p_rx_buffer != NULL &&
734          !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_rx_buffer)))
735     {
736         p_cb->transfer_in_progress = false;
737         err_code = NRFX_ERROR_INVALID_ADDR;
738         NRFX_LOG_WARNING("Function: %s, error code: %s.",
739                          __func__,
740                          NRFX_LOG_ERROR_STRING_GET(err_code));
741         return err_code;
742     }
743 
744 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
745     if (p_spim == NRF_SPIM3)
746     {
747         anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
748     }
749 #endif
750 
751 #if NRFY_SPIM_HAS_ARRAY_LIST
752     nrfy_spim_tx_list_set(p_spim, NRFX_SPIM_FLAG_TX_POSTINC & flags);
753     nrfy_spim_rx_list_set(p_spim, NRFX_SPIM_FLAG_RX_POSTINC & flags);
754 #endif
755 
756     nrfy_spim_xfer_desc_t xfer_desc = *p_xfer_desc;
757 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
758     if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
759     {
760         nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
761         xfer_desc.tx_length = 0;
762         xfer_desc.rx_length = 0;
763         nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
764     }
765 #endif
766     nrfy_spim_buffers_set(p_spim, &xfer_desc);
767 
768     nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
769     nrfy_spim_enable(p_spim);
770 
771     if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
772     {
773         nrfy_spim_xfer_start(p_spim, p_cb->handler ? NULL : &xfer_desc);
774     }
775 
776     if (!p_cb->handler)
777     {
778 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
779         if (p_spim == NRF_SPIM3)
780         {
781             anomaly_198_disable();
782         }
783 #endif
784         set_ss_pin_state(p_cb, false);
785         if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
786         {
787             spim_abort(p_spim, p_cb);
788         }
789     }
790     else
791     {
792         if (flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)
793         {
794             nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
795         }
796         else
797         {
798             nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
799         }
800     }
801     err_code = NRFX_SUCCESS;
802     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
803     return err_code;
804 }
805 
nrfx_spim_xfer(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)806 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const *           p_instance,
807                           nrfx_spim_xfer_desc_t const * p_xfer_desc,
808                           uint32_t                      flags)
809 {
810     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
811 
812     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
813     NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
814     NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
815     NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
816                                      p_xfer_desc->rx_length,
817                                      p_xfer_desc->tx_length));
818     NRFX_ASSERT(!(flags & NRFX_SPIM_FLAG_HOLD_XFER) ||
819                 (p_cb->ss_pin == NRF_SPIM_PIN_NOT_CONNECTED));
820 
821     nrfx_err_t err_code = NRFX_SUCCESS;
822 
823 #if !NRFY_SPIM_HAS_ARRAY_LIST
824     if ((NRFX_SPIM_FLAG_TX_POSTINC | NRFX_SPIM_FLAG_RX_POSTINC) & flags)
825     {
826         err_code = NRFX_ERROR_NOT_SUPPORTED;
827         NRFX_LOG_WARNING("Function: %s, error code: %s.",
828                          __func__,
829                          NRFX_LOG_ERROR_STRING_GET(err_code));
830         return err_code;
831     }
832 #endif
833 
834     if (p_cb->transfer_in_progress)
835     {
836         err_code = NRFX_ERROR_BUSY;
837         NRFX_LOG_WARNING("Function: %s, error code: %s.",
838                          __func__,
839                          NRFX_LOG_ERROR_STRING_GET(err_code));
840         return err_code;
841     }
842     else
843     {
844         if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
845                                         NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
846         {
847             p_cb->transfer_in_progress = true;
848         }
849     }
850 
851     p_cb->evt.xfer_desc = *p_xfer_desc;
852 
853     set_ss_pin_state(p_cb, true);
854 
855     return spim_xfer(p_instance->p_reg, p_cb,  p_xfer_desc, flags);
856 }
857 
nrfx_spim_abort(nrfx_spim_t const * p_instance)858 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
859 {
860     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
861 
862     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
863 
864     spim_abort(p_instance->p_reg, p_cb);
865 }
866 
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)867 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
868 {
869 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
870     if (nrfy_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK) &&
871         nrfy_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED))
872     {
873         /* Handle first, zero-length, auxiliary transmission. */
874         nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
875         nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
876 
877         NRFX_ASSERT(nrfy_spim_tx_maxcnt_get(p_spim) == 0);
878         NRFX_ASSERT(nrfy_spim_rx_maxcnt_get(p_spim) == 0);
879 
880         /* Disable STARTED interrupt, used only in auxiliary transmission. */
881         nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
882 
883         /* Start the actual, glitch-free transmission. */
884         nrfy_spim_buffers_set(p_spim, &p_cb->evt.xfer_desc);
885         nrfy_spim_xfer_start(p_spim, NULL);
886         return;
887     }
888 #endif
889 
890     if (nrfy_spim_events_process(p_spim,
891                                  NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_END),
892                                  &p_cb->evt.xfer_desc))
893     {
894 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
895         if (p_spim == NRF_SPIM3)
896         {
897             anomaly_198_disable();
898         }
899 #endif
900         NRFX_ASSERT(p_cb->handler);
901         NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
902         finish_transfer(p_spim, p_cb);
903     }
904 }
905 
906 NRFX_INSTANCE_IRQ_HANDLERS(SPIM, spim)
907 
908 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
909