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 #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 rxdelay_support_mask =
112     NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_RXDELAY_PRESENT);
113 static const uint32_t dcx_support_mask =
114     NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_HARDWARE_DCX_PRESENT) |
115     NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_DCX_PRESENT);
116 static const uint32_t hw_csn_support_mask =
117     NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_HARDWARE_CSN_PRESENT);
118 static const uint32_t datarate32_support_mask =
119     NRFX_NUM_FEATURE_SUPPORTED_MASK(SPIM, MAX_DATARATE);
120 #endif
121 
122 static const uint8_t easydma_support_bits[] __UNUSED =
123     NRFX_FEATURE_ARRAY_INITIALIZE(SPIM, EASYDMA_MAXCNT_SIZE);
124 
125 #define SPIM_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq)          \
126             (((freq != NRFX_MHZ_TO_HZ(32)) && (freq != NRFX_MHZ_TO_HZ(16))) || \
127              ((NRFX_BIT(drv_inst_idx)) & datarate32_support_mask))
128 
129 #define SPIM_RXDELAY_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & rxdelay_support_mask)
130 
131 #define SPIM_DCX_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & dcx_support_mask)
132 
133 #define SPIM_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & hw_csn_support_mask)
134 
135 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)          \
136             ((rx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])) && \
137              (tx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])))
138 
139 // Requested pin can either match dedicated pin or be not connected at all.
140 #define SPIM_DEDICATED_PIN_VALIDATE(requested_pin, supported_pin) \
141     (((requested_pin) == NRF_SPIM_PIN_NOT_CONNECTED) || ((requested_pin) == (supported_pin)))
142 
143 #if !defined(USE_WORKAROUND_FOR_ANOMALY_195) && \
144     defined(NRF52840_XXAA) && NRFX_CHECK(NRFX_SPIM3_ENABLED)
145 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
146 #define USE_WORKAROUND_FOR_ANOMALY_195 1
147 #endif
148 
149 #if NRFX_CHECK(NRF54L_ERRATA_8_PRESENT) || NRFX_CHECK(NRF54H_ERRATA_212_PRESENT)
150 #define USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212 1
apply_errata_nrf54l_8_nrf54h_212(void)151 static inline bool apply_errata_nrf54l_8_nrf54h_212(void)
152 {
153     return (NRFX_COND_CODE_1(NRF54L_ERRATA_8_PRESENT, (nrf54l_errata_8()), (false)) ||
154             NRFX_COND_CODE_1(NRF54H_ERRATA_212_PRESENT, (nrf54h_errata_212()), (false)));
155 }
156 #endif
157 
158 // Control block - driver instance local data.
159 typedef struct
160 {
161     nrfx_spim_evt_handler_t handler;
162     void *                  p_context;
163     nrfx_spim_evt_t         evt;  // Keep the struct that is ready for event handler. Less memcpy.
164     nrfx_drv_state_t        state;
165     volatile bool           transfer_in_progress;
166     bool                    skip_gpio_cfg       : 1;
167     bool                    ss_active_high      : 1;
168     bool                    disable_on_xfer_end : 1;
169 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
170     bool                    apply_errata_8_212  : 1;
171 #endif
172     uint32_t                ss_pin;
173 } spim_control_block_t;
174 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
175 
176 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
177 
178 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
179 
180 static uint32_t m_anomaly_198_preserved_value;
181 
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)182 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
183 {
184     m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
185 
186     if (buf_len == 0)
187     {
188         return;
189     }
190     uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
191     uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
192     uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
193     uint32_t occupied_blocks = 0;
194 
195     if (block_addr >= 0x20010000)
196     {
197         occupied_blocks = (1UL << 8);
198     }
199     else
200     {
201         do {
202             occupied_blocks |= block_flag;
203             block_flag <<= 1;
204             block_addr  += 0x2000;
205         } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
206     }
207 
208     *((volatile uint32_t *)0x40000E00) = occupied_blocks;
209 }
210 
anomaly_198_disable(void)211 static void anomaly_198_disable(void)
212 {
213     *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
214 }
215 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
216 
spim_abort(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)217 static void spim_abort(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
218 {
219     nrfy_spim_abort(p_spim, NULL);
220     bool stopped;
221     uint32_t stopped_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_STOPPED);
222     NRFX_WAIT_FOR(nrfy_spim_events_process(p_spim, stopped_mask, NULL), 100, 1, stopped);
223     if (!stopped)
224     {
225         NRFX_LOG_ERROR("Failed to stop instance with base address: %p.", (void *)p_spim);
226     }
227     p_cb->transfer_in_progress = false;
228 #if defined(HALTIUM_XXAA)
229     if (p_cb->disable_on_xfer_end)
230 #endif
231     {
232         nrfy_spim_disable(p_spim);
233     }
234 }
235 
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)236 static void pin_init(uint32_t             pin,
237                      nrf_gpio_pin_dir_t   dir,
238                      nrf_gpio_pin_pull_t  pull,
239                      nrf_gpio_pin_drive_t drive,
240                      uint32_t             initial_state)
241 {
242     nrf_gpio_pin_input_t input;
243 
244     if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
245     {
246         return;
247     }
248 
249     if (dir == NRF_GPIO_PIN_DIR_OUTPUT)
250     {
251         if (initial_state)
252         {
253             nrfy_gpio_pin_set(pin);
254         }
255         else
256         {
257             nrfy_gpio_pin_clear(pin);
258         }
259         input = NRF_GPIO_PIN_INPUT_DISCONNECT;
260     }
261     else
262     {
263         input = NRF_GPIO_PIN_INPUT_CONNECT;
264     }
265 
266     nrfy_gpio_cfg(pin, dir, input, pull, drive, NRF_GPIO_PIN_NOSENSE);
267 }
268 
configure_pins(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)269 static void configure_pins(nrfx_spim_t const *        p_instance,
270                            nrfx_spim_config_t const * p_config)
271 {
272     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
273 
274     p_cb->ss_active_high = p_config->ss_active_high;
275 
276     if (p_config->skip_gpio_cfg)
277     {
278         return;
279     }
280 
281     nrf_gpio_pin_drive_t pin_drive;
282     // Configure pin drive - high drive for 32 MHz clock frequency.
283 #if defined(LUMOS_XXAA)
284     pin_drive = NRF_GPIO_PIN_H0H1;
285 #elif (NRF_SPIM_HAS_FREQUENCY && NRF_SPIM_HAS_32_MHZ_FREQ) || NRF_SPIM_HAS_PRESCALER
286     pin_drive = (p_config->frequency == NRFX_MHZ_TO_HZ(32)) ? NRF_GPIO_PIN_H0H1 : NRF_GPIO_PIN_S0S1;
287 #else
288     pin_drive = NRF_GPIO_PIN_S0S1;
289 #endif
290     // Configure pins used by the peripheral:
291     // - SCK - output with initial value corresponding with the SPI mode used:
292     //   0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
293     //   according to the reference manual guidelines this pin and its input
294     //   buffer must always be connected for the SPI to work.
295     uint32_t sck_val = (p_config->mode <= NRF_SPIM_MODE_1) ? 0 : 1;
296     pin_init(p_config->sck_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, sck_val);
297 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_SCK_NEEDED)
298     nrfy_gpio_pin_clock_set(p_config->sck_pin, true);
299 #endif
300     // - MOSI (optional) - output with initial value 0
301     pin_init(p_config->mosi_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 0);
302 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_MOSI_NEEDED)
303     nrfy_gpio_pin_clock_set(p_config->mosi_pin, true);
304 #endif
305     // - MISO (optional) - input
306     pin_init(p_config->miso_pin, NRF_GPIO_PIN_DIR_INPUT, p_config->miso_pull, pin_drive, 0);
307     // - Slave Select (optional) - output with initial value 1 (inactive).
308     uint32_t ss_val = !p_config->ss_active_high;
309     pin_init(p_config->ss_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, ss_val);
310 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
311     // - DCX (optional) - output.
312     pin_init(p_config->dcx_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 1);
313 #endif
314 }
315 
316 #if NRF_SPIM_HAS_FREQUENCY
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)317 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
318 {
319     (void)p_instance;
320     switch (frequency)
321     {
322         case NRFX_KHZ_TO_HZ(125):
323             /* FALLTHROUGH */
324         case NRFX_KHZ_TO_HZ(250):
325             /* FALLTHROUGH */
326         case NRFX_KHZ_TO_HZ(500):
327             /* FALLTHROUGH */
328         case NRFX_MHZ_TO_HZ(1):
329             /* FALLTHROUGH */
330         case NRFX_MHZ_TO_HZ(2):
331             /* FALLTHROUGH */
332         case NRFX_MHZ_TO_HZ(4):
333             /* FALLTHROUGH */
334         case NRFX_MHZ_TO_HZ(8):
335             return true;
336 #if NRF_SPIM_HAS_16_MHZ_FREQ
337         case NRFX_MHZ_TO_HZ(16):
338             return true;
339 #endif
340 #if NRF_SPIM_HAS_32_MHZ_FREQ
341         case NRFX_MHZ_TO_HZ(32):
342             return true;
343 #endif
344         default:
345             return false;
346     }
347 }
348 
spim_frequency_bit_decode(uint32_t frequency)349 static nrf_spim_frequency_t spim_frequency_bit_decode(uint32_t frequency)
350 {
351     switch (frequency)
352     {
353         case NRFX_KHZ_TO_HZ(125):
354             return NRF_SPIM_FREQ_125K;
355         case NRFX_KHZ_TO_HZ(250):
356             return NRF_SPIM_FREQ_250K;
357         case NRFX_KHZ_TO_HZ(500):
358             return NRF_SPIM_FREQ_500K;
359         case NRFX_MHZ_TO_HZ(1):
360             return NRF_SPIM_FREQ_1M;
361         case NRFX_MHZ_TO_HZ(2):
362             return NRF_SPIM_FREQ_2M;
363         case NRFX_MHZ_TO_HZ(4):
364             return NRF_SPIM_FREQ_4M;
365         case NRFX_MHZ_TO_HZ(8):
366             return NRF_SPIM_FREQ_8M;
367 #if NRF_SPIM_HAS_16_MHZ_FREQ
368         case NRFX_MHZ_TO_HZ(16):
369             return NRF_SPIM_FREQ_16M;
370 #endif
371 #if NRF_SPIM_HAS_32_MHZ_FREQ
372         case NRFX_MHZ_TO_HZ(32):
373             return NRF_SPIM_FREQ_32M;
374 #endif
375         default:
376             NRFX_ASSERT(false);
377             return NRF_SPIM_FREQ_4M;
378     }
379 }
380 #elif NRF_SPIM_HAS_PRESCALER
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)381 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
382 {
383     uint32_t base_frequency = NRFX_SPIM_BASE_FREQUENCY_GET(p_instance);
384     uint32_t prescaler = NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
385 
386     return ((base_frequency % frequency) < prescaler) &&
387             NRFX_IS_EVEN(prescaler) &&
388             (prescaler <= NRF_SPIM_PRESCALER_MAX_GET(p_instance->p_reg)) &&
389             (prescaler >= NRF_SPIM_PRESCALER_MIN_GET(p_instance->p_reg));
390 }
391 
spim_prescaler_calculate(nrfx_spim_t const * p_instance,uint32_t frequency)392 static uint32_t spim_prescaler_calculate(nrfx_spim_t const * p_instance, uint32_t frequency)
393 {
394     (void)p_instance;
395     return NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
396 }
397 #else
398     #error "Unable to determine frequency division support type."
399 #endif
400 
spim_configuration_verify(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)401 static nrfx_err_t spim_configuration_verify(nrfx_spim_t const *        p_instance,
402                                             nrfx_spim_config_t const * p_config)
403 {
404     nrfx_err_t err_code;
405     if (!spim_frequency_valid_check(p_instance, p_config->frequency))
406     {
407         err_code = NRFX_ERROR_INVALID_PARAM;
408         NRFX_LOG_WARNING("Function: %s, error code: %s.",
409                          __func__,
410                          NRFX_LOG_ERROR_STRING_GET(err_code));
411         return err_code;
412     }
413 
414 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
415     // Check if SPIM instance supports the extended features.
416     if (!SPIM_SUPPORTED_FREQ_VALIDATE(p_instance->drv_inst_idx, p_config->frequency) ||
417          (p_config->use_hw_ss && (p_config->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
418           !SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx)) ||
419          ((p_config->dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
420           !SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx)))
421     {
422         err_code = NRFX_ERROR_NOT_SUPPORTED;
423         NRFX_LOG_WARNING("Function: %s, error code: %s.",
424                          __func__,
425                          NRFX_LOG_ERROR_STRING_GET(err_code));
426         return err_code;
427     }
428 
429 #if NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
430     // Check if dedicated SPIM pins are used, unless both GPIO configuration
431     // and pin selection are to be skipped (pin numbers may be not specified
432     // in such case).
433     if (!(p_config->skip_gpio_cfg && p_config->skip_psel_cfg) &&
434         (p_instance->p_reg == NRF_SPIM4) && (p_config->frequency == NRFX_MHZ_TO_HZ(32)))
435     {
436         enum {
437             SPIM_SCK_DEDICATED  = NRF_GPIO_PIN_MAP(0, 8),
438             SPIM_MOSI_DEDICATED = NRF_GPIO_PIN_MAP(0, 9),
439             SPIM_MISO_DEDICATED = NRF_GPIO_PIN_MAP(0, 10),
440             SPIM_CSN_DEDICATED  = NRF_GPIO_PIN_MAP(0, 11),
441             SPIM_DCX_DEDICATED  = NRF_GPIO_PIN_MAP(0, 12),
442         };
443 
444         if (!SPIM_DEDICATED_PIN_VALIDATE(p_config->sck_pin, SPIM_SCK_DEDICATED) ||
445             !SPIM_DEDICATED_PIN_VALIDATE(p_config->mosi_pin, SPIM_MOSI_DEDICATED) ||
446             !SPIM_DEDICATED_PIN_VALIDATE(p_config->miso_pin, SPIM_MISO_DEDICATED) ||
447             (p_config->use_hw_ss &&
448              !SPIM_DEDICATED_PIN_VALIDATE(p_config->ss_pin, SPIM_CSN_DEDICATED)) ||
449             !SPIM_DEDICATED_PIN_VALIDATE(p_config->dcx_pin, SPIM_DCX_DEDICATED))
450         {
451             err_code = NRFX_ERROR_INVALID_PARAM;
452             NRFX_LOG_WARNING("Function: %s, error code: %s.",
453                              __func__,
454                              NRFX_LOG_ERROR_STRING_GET(err_code));
455             return err_code;
456         }
457     }
458 #endif // NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
459 
460 #else
461     (void)p_instance;
462     (void)p_config;
463 #endif // NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
464     return NRFX_SUCCESS;
465 }
466 
spim_configure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)467 static void spim_configure(nrfx_spim_t const *        p_instance,
468                            nrfx_spim_config_t const * p_config)
469 {
470 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
471     bool hw_csn_supported = SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx);
472     bool use_csn = hw_csn_supported && p_config->use_hw_ss;
473 #endif
474     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
475     uint8_t csn_duration = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
476                                 (use_csn ? p_config->ss_duration : NRF_SPIM_CSNDUR_DEFAULT),
477                                 (0));
478 
479 #if NRF_SPIM_HAS_FREQUENCY
480     nrf_spim_frequency_t frequency = spim_frequency_bit_decode(p_config->frequency);
481 #elif NRF_SPIM_HAS_PRESCALER
482     uint32_t prescaler = spim_prescaler_calculate(p_instance, p_config->frequency);
483 #endif
484 
485 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
486     if (apply_errata_nrf54l_8_nrf54h_212())
487     {
488         /* Workaround must be applied only if PRESCALER is larger than 2 and CPHA=0 */
489         if ((prescaler > 2) &&
490             ((p_config->mode == NRF_SPIM_MODE_0) || (p_config->mode == NRF_SPIM_MODE_2)))
491         {
492             uint8_t min_dur = (uint8_t)((prescaler / 2) + 1);
493             csn_duration = NRFX_MAX(csn_duration, min_dur);
494             p_cb->apply_errata_8_212 = 1;
495         }
496         else
497         {
498             p_cb->apply_errata_8_212 = 0;
499         }
500     }
501 #else
502     (void)csn_duration;
503 #endif
504 
505     p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
506     configure_pins(p_instance, p_config);
507 
508 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
509     if (use_csn)
510     {
511         p_cb->ss_pin = NRF_SPIM_PIN_NOT_CONNECTED;
512     }
513     else
514 #endif
515     {
516         p_cb->ss_pin = p_config->ss_pin;
517         p_cb->ss_active_high = p_config->ss_active_high;
518     }
519 
520     nrfy_spim_config_t nrfy_config =
521     {
522         .pins =
523         {
524             .sck_pin  = p_config->sck_pin,
525             .mosi_pin = p_config->mosi_pin,
526             .miso_pin = p_config->miso_pin
527         },
528         .orc       = p_config->orc,
529 #if NRF_SPIM_HAS_FREQUENCY
530         .frequency = frequency,
531 #elif NRF_SPIM_HAS_PRESCALER
532         .prescaler = prescaler,
533 #endif
534         .mode      = p_config->mode,
535         .bit_order = p_config->bit_order,
536 #if NRFY_SPIM_HAS_EXTENDED
537         /* Extended config is applied even if only single instance supports it.
538            For other instances, and also when NRFX_SPIM_EXTENDED_ENABLED is 0,
539            apply default configuration. */
540         .ext_config =
541         {
542             .pins =
543             {
544 #if NRFY_SPIM_HAS_DCX
545                 .dcx_pin = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
546                                             (p_config->dcx_pin,),
547                                             (NRF_SPIM_DCX_DEFAULT,))
548 #endif
549 #if NRFY_SPIM_HAS_HW_CSN
550                 .csn_pin = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
551                                             (use_csn ? p_config->ss_pin : NRF_SPIM_CSN_DEFAULT,),
552                                             (NRF_SPIM_CSN_DEFAULT,))
553 #endif
554             },
555 #if NRFY_SPIM_HAS_HW_CSN
556             .csn_pol      = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
557                                              (use_csn ?
558                                               (p_config->ss_active_high ?
559                                                NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW) :
560                                                (nrf_spim_csn_pol_t)NRF_SPIM_CSNPOL_DEFAULT,),
561                                               ((nrf_spim_csn_pol_t)NRF_SPIM_CSNPOL_DEFAULT,))
562             .csn_duration = csn_duration,
563 #endif
564 #if NRFY_SPIM_HAS_RXDELAY
565             .rx_delay = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
566                                          (SPIM_RXDELAY_PRESENT_VALIDATE(p_instance->drv_inst_idx) ?
567                                           p_config->rx_delay : NRF_SPIM_RXDELAY_DEFAULT,),
568                                          (NRF_SPIM_RXDELAY_DEFAULT,))
569 #endif
570         },
571 #endif // NRFY_SPIM_HAS_EXTENDED
572         .skip_psel_cfg = p_config->skip_psel_cfg
573     };
574 
575     nrfy_spim_periph_configure(p_instance->p_reg, &nrfy_config);
576     if (m_cb[p_instance->drv_inst_idx].handler)
577     {
578         nrfy_spim_int_init(p_instance->p_reg, 0, p_config->irq_priority, false);
579     }
580 }
581 
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)582 nrfx_err_t nrfx_spim_init(nrfx_spim_t const *        p_instance,
583                           nrfx_spim_config_t const * p_config,
584                           nrfx_spim_evt_handler_t    handler,
585                           void *                     p_context)
586 {
587     NRFX_ASSERT(p_config);
588 
589     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
590     nrfx_err_t err_code;
591 
592     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
593     {
594 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
595         err_code = NRFX_ERROR_ALREADY;
596 #else
597         err_code = NRFX_ERROR_INVALID_STATE;
598 #endif
599         NRFX_LOG_WARNING("Function: %s, error code: %s.",
600                          __func__,
601                          NRFX_LOG_ERROR_STRING_GET(err_code));
602         return err_code;
603     }
604 
605     if (p_config)
606     {
607         err_code = spim_configuration_verify(p_instance, p_config);
608         if (err_code != NRFX_SUCCESS)
609         {
610             return err_code;
611         }
612     }
613 
614 #if NRFX_CHECK(NRFX_PRS_ENABLED)
615     static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
616         NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPIM, spim)
617     };
618     if (nrfx_prs_acquire(p_instance->p_reg, irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
619     {
620         err_code = NRFX_ERROR_BUSY;
621         NRFX_LOG_WARNING("Function: %s, error code: %s.",
622                          __func__,
623                          NRFX_LOG_ERROR_STRING_GET(err_code));
624         return err_code;
625     }
626 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
627 
628     p_cb->handler = handler;
629     p_cb->p_context = p_context;
630 
631     if (p_config)
632     {
633         spim_configure(p_instance, p_config);
634     }
635 
636     p_cb->transfer_in_progress = false;
637     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
638 
639     err_code = NRFX_SUCCESS;
640     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
641     return err_code;
642 }
643 
nrfx_spim_reconfigure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)644 nrfx_err_t nrfx_spim_reconfigure(nrfx_spim_t const *        p_instance,
645                                  nrfx_spim_config_t const * p_config)
646 {
647     NRFX_ASSERT(p_config);
648 
649     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
650 
651     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
652     {
653         return NRFX_ERROR_INVALID_STATE;
654     }
655     if (p_cb->transfer_in_progress)
656     {
657         return NRFX_ERROR_BUSY;
658     }
659     nrfx_err_t err_code = spim_configuration_verify(p_instance, p_config);
660     if (err_code != NRFX_SUCCESS)
661     {
662         return err_code;
663     }
664 
665     spim_configure(p_instance, p_config);
666 
667     return NRFX_SUCCESS;
668 }
669 
spim_pin_uninit(uint32_t pin)670 static void spim_pin_uninit(uint32_t pin)
671 {
672     if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
673     {
674         return;
675     }
676 
677     nrfy_gpio_cfg_default(pin);
678 }
679 
nrfx_spim_uninit(nrfx_spim_t const * p_instance)680 void nrfx_spim_uninit(nrfx_spim_t const * p_instance)
681 {
682     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
683 
684     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
685 
686     nrfy_spim_int_uninit(p_instance->p_reg);
687     if (p_cb->handler)
688     {
689         nrfy_spim_int_disable(p_instance->p_reg, NRF_SPIM_ALL_INTS_MASK);
690         spim_abort(p_instance->p_reg, p_cb);
691     }
692 
693     nrfy_spim_pins_t pins;
694     nrfy_spim_pins_get(p_instance->p_reg, &pins);
695 
696     if (!p_cb->skip_gpio_cfg)
697     {
698         spim_pin_uninit(pins.sck_pin);
699         spim_pin_uninit(pins.miso_pin);
700         spim_pin_uninit(pins.mosi_pin);
701         spim_pin_uninit(p_cb->ss_pin);
702 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
703         if (SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx) &&
704             SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx))
705         {
706             nrfy_spim_ext_pins_t ext_pins;
707             nrfy_spim_ext_pins_get(p_instance->p_reg, &ext_pins);
708 #if NRFY_SPIM_HAS_DCX
709             spim_pin_uninit(ext_pins.dcx_pin);
710 #endif
711 #if NRFY_SPIM_HAS_HW_CSN
712             spim_pin_uninit(ext_pins.csn_pin);
713 #endif
714         }
715 #endif
716     }
717 
718 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_195)
719     if (p_instance->p_reg == NRF_SPIM3)
720     {
721         *(volatile uint32_t *)0x4002F004 = 1;
722     }
723 #endif
724 
725 #if NRFX_CHECK(NRFX_PRS_ENABLED)
726     nrfx_prs_release(p_instance->p_reg);
727 #endif
728 
729     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
730     NRFX_LOG_INFO("Uninitialized.");
731 }
732 
nrfx_spim_init_check(nrfx_spim_t const * p_instance)733 bool nrfx_spim_init_check(nrfx_spim_t const * p_instance)
734 {
735     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
736 
737     return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
738 }
739 
740 #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)741 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const *           p_instance,
742                               nrfx_spim_xfer_desc_t const * p_xfer_desc,
743                               uint32_t                      flags,
744                               uint8_t                       cmd_length)
745 {
746     (void)flags;
747 
748     NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
749 
750     nrfy_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
751     return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
752 }
753 #endif
754 
set_ss_pin_state(spim_control_block_t * p_cb,bool active)755 static void set_ss_pin_state(spim_control_block_t * p_cb, bool active)
756 {
757     if (p_cb->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED)
758     {
759         if (p_cb->ss_active_high)
760         {
761             if (active)
762             {
763                 nrfy_gpio_pin_set(p_cb->ss_pin);
764             }
765             else
766             {
767                 nrfy_gpio_pin_clear(p_cb->ss_pin);
768             }
769         }
770         else
771         {
772             if (active)
773             {
774                 nrfy_gpio_pin_clear(p_cb->ss_pin);
775             }
776             else
777             {
778                 nrfy_gpio_pin_set(p_cb->ss_pin);
779             }
780         }
781     }
782 }
783 
finish_transfer(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)784 static void finish_transfer(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
785 {
786     // If Slave Select signal is used, this is the time to deactivate it.
787     set_ss_pin_state(p_cb, false);
788 
789     // By clearing this flag before calling the handler we allow subsequent
790     // transfers to be started directly from the handler function.
791     if (p_cb->transfer_in_progress)
792     {
793         spim_abort(p_spim, p_cb);
794     }
795 
796     p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
797     p_cb->handler(&p_cb->evt, p_cb->p_context);
798 }
799 
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)800 static nrfx_err_t spim_xfer(NRF_SPIM_Type               * p_spim,
801                             spim_control_block_t        * p_cb,
802                             nrfx_spim_xfer_desc_t const * p_xfer_desc,
803                             uint32_t                      flags)
804 {
805     nrfx_err_t err_code;
806     // EasyDMA requires that transfer buffers are placed in Data RAM region;
807     // signal error if they are not.
808     if ((p_xfer_desc->p_tx_buffer != NULL &&
809          !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_tx_buffer)) ||
810         (p_xfer_desc->p_rx_buffer != NULL &&
811          !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_rx_buffer)))
812     {
813         p_cb->transfer_in_progress = false;
814         err_code = NRFX_ERROR_INVALID_ADDR;
815         NRFX_LOG_WARNING("Function: %s, error code: %s.",
816                          __func__,
817                          NRFX_LOG_ERROR_STRING_GET(err_code));
818         return err_code;
819     }
820 
821 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
822     if (p_spim == NRF_SPIM3)
823     {
824         anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
825     }
826 #endif
827 
828 #if NRFY_SPIM_HAS_ARRAY_LIST
829     nrfy_spim_tx_list_set(p_spim, NRFX_SPIM_FLAG_TX_POSTINC & flags);
830     nrfy_spim_rx_list_set(p_spim, NRFX_SPIM_FLAG_RX_POSTINC & flags);
831 #endif
832 
833     nrfy_spim_xfer_desc_t xfer_desc = *p_xfer_desc;
834 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
835     if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
836     {
837         nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
838         xfer_desc.tx_length = 0;
839         xfer_desc.rx_length = 0;
840         nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
841     }
842 #endif
843     nrfy_spim_buffers_set(p_spim, &xfer_desc);
844 
845     nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
846 #if defined(HALTIUM_XXAA)
847     p_cb->disable_on_xfer_end = (flags & (NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER |
848                                           NRFX_SPIM_FLAG_HOLD_XFER |
849                                           NRFX_SPIM_FLAG_REPEATED_XFER)) ?
850                                 true : !nrfy_spim_enable_check(p_spim);
851 #endif
852     nrfy_spim_enable(p_spim);
853 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
854     if (apply_errata_nrf54l_8_nrf54h_212() && p_cb->apply_errata_8_212)
855     {
856         *(volatile uint32_t *)((uintptr_t)p_spim + 0xc84) = 0x82;
857         if (p_cb->handler)
858         {
859             nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
860             nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
861         }
862     }
863 #endif
864 
865     if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
866     {
867         nrfy_spim_xfer_start(p_spim, p_cb->handler ? NULL : &xfer_desc);
868     }
869 
870     if (!p_cb->handler)
871     {
872 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
873         if (apply_errata_nrf54l_8_nrf54h_212() && p_cb->apply_errata_8_212)
874         {
875             *(volatile uint32_t *)((uintptr_t)p_spim + 0xc84) = 0;
876         }
877 #endif
878 
879 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
880         if (p_spim == NRF_SPIM3)
881         {
882             anomaly_198_disable();
883         }
884 #endif
885         set_ss_pin_state(p_cb, false);
886         if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
887         {
888             spim_abort(p_spim, p_cb);
889         }
890     }
891     else
892     {
893         if (flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)
894         {
895             nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
896         }
897         else
898         {
899             nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
900         }
901     }
902     err_code = NRFX_SUCCESS;
903     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
904     return err_code;
905 }
906 
nrfx_spim_xfer(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)907 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const *           p_instance,
908                           nrfx_spim_xfer_desc_t const * p_xfer_desc,
909                           uint32_t                      flags)
910 {
911     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
912 
913     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
914     NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
915     NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
916     NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
917                                      p_xfer_desc->rx_length,
918                                      p_xfer_desc->tx_length));
919     NRFX_ASSERT(!(flags & NRFX_SPIM_FLAG_HOLD_XFER) ||
920                 (p_cb->ss_pin == NRF_SPIM_PIN_NOT_CONNECTED));
921 
922     nrfx_err_t err_code = NRFX_SUCCESS;
923 
924 #if !NRFY_SPIM_HAS_ARRAY_LIST
925     if ((NRFX_SPIM_FLAG_TX_POSTINC | NRFX_SPIM_FLAG_RX_POSTINC) & flags)
926     {
927         err_code = NRFX_ERROR_NOT_SUPPORTED;
928         NRFX_LOG_WARNING("Function: %s, error code: %s.",
929                          __func__,
930                          NRFX_LOG_ERROR_STRING_GET(err_code));
931         return err_code;
932     }
933 #endif
934 
935     if (p_cb->transfer_in_progress)
936     {
937         err_code = NRFX_ERROR_BUSY;
938         NRFX_LOG_WARNING("Function: %s, error code: %s.",
939                          __func__,
940                          NRFX_LOG_ERROR_STRING_GET(err_code));
941         return err_code;
942     }
943     else
944     {
945         if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
946                                         NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
947         {
948             p_cb->transfer_in_progress = true;
949         }
950     }
951 
952     p_cb->evt.xfer_desc = *p_xfer_desc;
953 
954     set_ss_pin_state(p_cb, true);
955 
956     return spim_xfer(p_instance->p_reg, p_cb,  p_xfer_desc, flags);
957 }
958 
nrfx_spim_abort(nrfx_spim_t const * p_instance)959 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
960 {
961     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
962 
963     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
964 
965     spim_abort(p_instance->p_reg, p_cb);
966 }
967 
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)968 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
969 {
970 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
971     if (apply_errata_nrf54l_8_nrf54h_212() && p_cb->apply_errata_8_212)
972     {
973         if (nrfy_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK) &&
974             nrfy_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED))
975         {
976             nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
977             *(volatile uint32_t *)((uintptr_t)p_spim + 0xc84) = 0;
978             nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
979         }
980     }
981 #endif
982 
983 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
984     if (nrfy_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK) &&
985         nrfy_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED))
986     {
987         /* Handle first, zero-length, auxiliary transmission. */
988         nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
989         nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
990 
991         NRFX_ASSERT(nrfy_spim_tx_maxcnt_get(p_spim) == 0);
992         NRFX_ASSERT(nrfy_spim_rx_maxcnt_get(p_spim) == 0);
993 
994         /* Disable STARTED interrupt, used only in auxiliary transmission. */
995         nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
996 
997         /* Start the actual, glitch-free transmission. */
998         nrfy_spim_buffers_set(p_spim, &p_cb->evt.xfer_desc);
999         nrfy_spim_xfer_start(p_spim, NULL);
1000         return;
1001     }
1002 #endif
1003 
1004     if (nrfy_spim_events_process(p_spim,
1005                                  NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_END),
1006                                  &p_cb->evt.xfer_desc))
1007     {
1008 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
1009         if (p_spim == NRF_SPIM3)
1010         {
1011             anomaly_198_disable();
1012         }
1013 #endif
1014         NRFX_ASSERT(p_cb->handler);
1015         NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
1016         finish_transfer(p_spim, p_cb);
1017     }
1018 }
1019 
1020 NRFX_INSTANCE_IRQ_HANDLERS(SPIM, spim)
1021 
1022 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
1023