1 /*
2 * Copyright (c) 2013 - 2018, 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_SPIS_ENABLED)
35
36 #if !(NRFX_CHECK(NRFX_SPIS0_ENABLED) || \
37 NRFX_CHECK(NRFX_SPIS1_ENABLED) || \
38 NRFX_CHECK(NRFX_SPIS2_ENABLED) || \
39 NRFX_CHECK(NRFX_SPIS3_ENABLED))
40 #error "No enabled SPIS instances. Check <nrfx_config.h>."
41 #endif
42
43 #include <nrfx_spis.h>
44 #include "prs/nrfx_prs.h"
45
46 #define NRFX_LOG_MODULE SPIS
47 #include <nrfx_log.h>
48
49 #define EVT_TO_STR(event) \
50 (event == NRF_SPIS_EVENT_ACQUIRED ? "NRF_SPIS_EVENT_ACQUIRED" : \
51 (event == NRF_SPIS_EVENT_END ? "NRF_SPIS_EVENT_END" : \
52 "UNKNOWN ERROR"))
53
54 #define SPISX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \
55 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
56 NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len))
57
58 #if NRFX_CHECK(NRFX_SPIS0_ENABLED)
59 #define SPIS0_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS0, __VA_ARGS__)
60 #else
61 #define SPIS0_LENGTH_VALIDATE(...) 0
62 #endif
63
64 #if NRFX_CHECK(NRFX_SPIS1_ENABLED)
65 #define SPIS1_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS1, __VA_ARGS__)
66 #else
67 #define SPIS1_LENGTH_VALIDATE(...) 0
68 #endif
69
70 #if NRFX_CHECK(NRFX_SPIS2_ENABLED)
71 #define SPIS2_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS2, __VA_ARGS__)
72 #else
73 #define SPIS2_LENGTH_VALIDATE(...) 0
74 #endif
75
76 #if NRFX_CHECK(NRFX_SPIS3_ENABLED)
77 #define SPIS3_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS3, __VA_ARGS__)
78 #else
79 #define SPIS3_LENGTH_VALIDATE(...) 0
80 #endif
81
82 #define SPIS_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \
83 (SPIS0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
84 SPIS1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
85 SPIS2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
86 SPIS3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len))
87
88
89 #if NRFX_CHECK(NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
90 #include <nrfx_gpiote.h>
91 #define USE_DMA_ISSUE_WORKAROUND
92 // This handler is called by the GPIOTE driver when a falling edge is detected
93 // on the CSN line. There is no need to do anything here. The handling of the
94 // interrupt itself provides a protection for DMA transfers.
csn_event_handler(nrfx_gpiote_pin_t pin,nrf_gpiote_polarity_t action)95 static void csn_event_handler(nrfx_gpiote_pin_t pin,
96 nrf_gpiote_polarity_t action)
97 {
98 }
99 #endif
100
101
102 /**@brief States of the SPI transaction state machine. */
103 typedef enum
104 {
105 SPIS_STATE_INIT, /**< Initialization state. In this state the module waits for a call to @ref spi_slave_buffers_set. */
106 SPIS_BUFFER_RESOURCE_REQUESTED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has started. */
107 SPIS_BUFFER_RESOURCE_CONFIGURED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has completed. */
108 SPIS_XFER_COMPLETED /**< State where SPI transaction has been completed. */
109 } nrfx_spis_state_t;
110
111 /**@brief SPIS control block - driver instance local data. */
112 typedef struct
113 {
114 volatile uint32_t tx_buffer_size; //!< SPI slave TX buffer size in bytes.
115 volatile uint32_t rx_buffer_size; //!< SPI slave RX buffer size in bytes.
116 nrfx_spis_event_handler_t handler; //!< SPI event handler.
117 volatile const uint8_t * tx_buffer; //!< SPI slave TX buffer.
118 volatile uint8_t * rx_buffer; //!< SPI slave RX buffer.
119 nrfx_drv_state_t state; //!< driver initialization state.
120 volatile nrfx_spis_state_t spi_state; //!< SPI slave state.
121 void * p_context; //!< Context set on initialization.
122 } spis_cb_t;
123
124 static spis_cb_t m_cb[NRFX_SPIS_ENABLED_COUNT];
125
nrfx_spis_init(nrfx_spis_t const * const p_instance,nrfx_spis_config_t const * p_config,nrfx_spis_event_handler_t event_handler,void * p_context)126 nrfx_err_t nrfx_spis_init(nrfx_spis_t const * const p_instance,
127 nrfx_spis_config_t const * p_config,
128 nrfx_spis_event_handler_t event_handler,
129 void * p_context)
130 {
131 NRFX_ASSERT(p_config);
132 NRFX_ASSERT(event_handler);
133 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
134 nrfx_err_t err_code;
135
136 NRF_SPIS_Type * p_spis = p_instance->p_reg;
137
138 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
139 {
140 err_code = NRFX_ERROR_INVALID_STATE;
141 NRFX_LOG_WARNING("Function: %s, error code: %s.",
142 __func__,
143 NRFX_LOG_ERROR_STRING_GET(err_code));
144 return err_code;
145 }
146
147 if ((uint32_t)p_config->mode > (uint32_t)NRF_SPIS_MODE_3)
148 {
149 err_code = NRFX_ERROR_INVALID_PARAM;
150 NRFX_LOG_WARNING("Function: %s, error code: %s.",
151 __func__,
152 NRFX_LOG_ERROR_STRING_GET(err_code));
153 return err_code;
154 }
155 #if NRFX_CHECK(NRFX_PRS_ENABLED)
156 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIS_ENABLED_COUNT] = {
157 #if NRFX_CHECK(NRFX_SPIS0_ENABLED)
158 nrfx_spis_0_irq_handler,
159 #endif
160 #if NRFX_CHECK(NRFX_SPIS1_ENABLED)
161 nrfx_spis_1_irq_handler,
162 #endif
163 #if NRFX_CHECK(NRFX_SPIS2_ENABLED)
164 nrfx_spis_2_irq_handler,
165 #endif
166 #if NRFX_CHECK(NRFX_SPIS3_ENABLED)
167 nrfx_spis_3_irq_handler,
168 #endif
169 };
170 if (nrfx_prs_acquire(p_spis,
171 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
172 {
173 err_code = NRFX_ERROR_BUSY;
174 NRFX_LOG_WARNING("Function: %s, error code: %s.",
175 __func__,
176 NRFX_LOG_ERROR_STRING_GET(err_code));
177 return err_code;
178 }
179 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
180
181 // Configure the SPI pins for input.
182 uint32_t mosi_pin;
183 uint32_t miso_pin;
184
185 if (p_config->miso_pin != NRFX_SPIS_PIN_NOT_USED)
186 {
187 nrf_gpio_cfg(p_config->miso_pin,
188 NRF_GPIO_PIN_DIR_INPUT,
189 NRF_GPIO_PIN_INPUT_CONNECT,
190 NRF_GPIO_PIN_NOPULL,
191 p_config->miso_drive,
192 NRF_GPIO_PIN_NOSENSE);
193 miso_pin = p_config->miso_pin;
194 }
195 else
196 {
197 miso_pin = NRF_SPIS_PIN_NOT_CONNECTED;
198 }
199
200 if (p_config->mosi_pin != NRFX_SPIS_PIN_NOT_USED)
201 {
202 nrf_gpio_cfg(p_config->mosi_pin,
203 NRF_GPIO_PIN_DIR_INPUT,
204 NRF_GPIO_PIN_INPUT_CONNECT,
205 NRF_GPIO_PIN_NOPULL,
206 NRF_GPIO_PIN_S0S1,
207 NRF_GPIO_PIN_NOSENSE);
208 mosi_pin = p_config->mosi_pin;
209 }
210 else
211 {
212 mosi_pin = NRF_SPIS_PIN_NOT_CONNECTED;
213 }
214
215 nrf_gpio_cfg(p_config->csn_pin,
216 NRF_GPIO_PIN_DIR_INPUT,
217 NRF_GPIO_PIN_INPUT_CONNECT,
218 p_config->csn_pullup,
219 NRF_GPIO_PIN_S0S1,
220 NRF_GPIO_PIN_NOSENSE);
221
222 nrf_gpio_cfg(p_config->sck_pin,
223 NRF_GPIO_PIN_DIR_INPUT,
224 NRF_GPIO_PIN_INPUT_CONNECT,
225 NRF_GPIO_PIN_NOPULL,
226 NRF_GPIO_PIN_S0S1,
227 NRF_GPIO_PIN_NOSENSE);
228
229 nrf_spis_pins_set(p_spis, p_config->sck_pin, mosi_pin, miso_pin, p_config->csn_pin);
230
231 nrf_spis_rx_buffer_set(p_spis, NULL, 0);
232 nrf_spis_tx_buffer_set(p_spis, NULL, 0);
233
234 // Configure SPI mode.
235 nrf_spis_configure(p_spis, p_config->mode, p_config->bit_order);
236
237 // Configure DEF and ORC characters.
238 nrf_spis_def_set(p_spis, p_config->def);
239 nrf_spis_orc_set(p_spis, p_config->orc);
240
241 // Clear possible pending events.
242 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
243 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
244
245 // Enable END_ACQUIRE shortcut.
246 nrf_spis_shorts_enable(p_spis, NRF_SPIS_SHORT_END_ACQUIRE);
247
248 p_cb->spi_state = SPIS_STATE_INIT;
249 p_cb->handler = event_handler;
250 p_cb->p_context = p_context;
251
252 #if defined(USE_DMA_ISSUE_WORKAROUND)
253 // Configure a GPIOTE channel to generate interrupts on each falling edge
254 // on the CSN line. Handling of these interrupts will make the CPU active,
255 // and thus will protect the DMA transfers started by SPIS right after it
256 // is selected for communication.
257 // [the GPIOTE driver may be already initialized at this point (by this
258 // driver when another SPIS instance is used, or by an application code),
259 // so just ignore the returned value]
260 (void)nrfx_gpiote_init();
261 static nrfx_gpiote_in_config_t const csn_gpiote_config =
262 NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
263 nrfx_err_t gpiote_err_code = nrfx_gpiote_in_init(p_config->csn_pin,
264 &csn_gpiote_config, csn_event_handler);
265 if (gpiote_err_code != NRFX_SUCCESS)
266 {
267 err_code = NRFX_ERROR_INTERNAL;
268 NRFX_LOG_INFO("Function: %s, error code: %s.",
269 __func__,
270 NRFX_LOG_ERROR_STRING_GET(err_code));
271 return err_code;
272 }
273 nrfx_gpiote_in_event_enable(p_config->csn_pin, true);
274 #endif
275
276 // Enable IRQ.
277 nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK |
278 NRF_SPIS_INT_END_MASK);
279 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
280 p_config->irq_priority);
281 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
282
283 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
284
285 // Enable SPI slave device.
286 nrf_spis_enable(p_spis);
287
288 NRFX_LOG_INFO("Initialized.");
289 return NRFX_SUCCESS;
290 }
291
292
nrfx_spis_uninit(nrfx_spis_t const * const p_instance)293 void nrfx_spis_uninit(nrfx_spis_t const * const p_instance)
294 {
295 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
296 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
297
298 NRF_SPIS_Type * p_spis = p_instance->p_reg;
299
300 #define DISABLE_ALL 0xFFFFFFFF
301 nrf_spis_disable(p_spis);
302 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
303 nrf_spis_int_disable(p_spis, DISABLE_ALL);
304 #undef DISABLE_ALL
305
306 #if NRFX_CHECK(NRFX_PRS_ENABLED)
307 nrfx_prs_release(p_spis);
308 #endif
309
310 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
311 NRFX_LOG_INFO("Uninitialized.");
312 }
313
314
315 /**@brief Function for executing the state entry action. */
spis_state_entry_action_execute(NRF_SPIS_Type * p_spis,spis_cb_t * p_cb)316 static void spis_state_entry_action_execute(NRF_SPIS_Type * p_spis,
317 spis_cb_t * p_cb)
318 {
319 nrfx_spis_evt_t event;
320
321 switch (p_cb->spi_state)
322 {
323 case SPIS_BUFFER_RESOURCE_REQUESTED:
324 nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_ACQUIRE);
325 break;
326
327 case SPIS_BUFFER_RESOURCE_CONFIGURED:
328 event.evt_type = NRFX_SPIS_BUFFERS_SET_DONE;
329 event.rx_amount = 0;
330 event.tx_amount = 0;
331
332 NRFX_ASSERT(p_cb->handler != NULL);
333 p_cb->handler(&event, p_cb->p_context);
334 break;
335
336 case SPIS_XFER_COMPLETED:
337 event.evt_type = NRFX_SPIS_XFER_DONE;
338 event.rx_amount = nrf_spis_rx_amount_get(p_spis);
339 event.tx_amount = nrf_spis_tx_amount_get(p_spis);
340 NRFX_LOG_INFO("Transfer rx_len:%d.", event.rx_amount);
341 NRFX_LOG_DEBUG("Rx data:");
342 NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_cb->rx_buffer,
343 event.rx_amount * sizeof(p_cb->rx_buffer[0]));
344 NRFX_ASSERT(p_cb->handler != NULL);
345 p_cb->handler(&event, p_cb->p_context);
346 break;
347
348 default:
349 // No implementation required.
350 break;
351 }
352 }
353
354 /**@brief Function for changing the state of the SPI state machine.
355 *
356 * @param[in] p_spis SPIS instance register.
357 * @param[in] p_cb SPIS instance control block.
358 * @param[in] new_state State where the state machine transits to.
359 */
spis_state_change(NRF_SPIS_Type * p_spis,spis_cb_t * p_cb,nrfx_spis_state_t new_state)360 static void spis_state_change(NRF_SPIS_Type * p_spis,
361 spis_cb_t * p_cb,
362 nrfx_spis_state_t new_state)
363 {
364 p_cb->spi_state = new_state;
365 spis_state_entry_action_execute(p_spis, p_cb);
366 }
367
nrfx_spis_buffers_set(nrfx_spis_t const * const p_instance,uint8_t const * p_tx_buffer,size_t tx_buffer_length,uint8_t * p_rx_buffer,size_t rx_buffer_length)368 nrfx_err_t nrfx_spis_buffers_set(nrfx_spis_t const * const p_instance,
369 uint8_t const * p_tx_buffer,
370 size_t tx_buffer_length,
371 uint8_t * p_rx_buffer,
372 size_t rx_buffer_length)
373 {
374 NRFX_ASSERT(p_tx_buffer != NULL || tx_buffer_length == 0);
375 NRFX_ASSERT(p_rx_buffer != NULL || rx_buffer_length == 0);
376
377 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
378 nrfx_err_t err_code;
379
380 if (!SPIS_LENGTH_VALIDATE(p_instance->drv_inst_idx,
381 rx_buffer_length,
382 tx_buffer_length))
383 {
384 return NRFX_ERROR_INVALID_LENGTH;
385 }
386
387 // EasyDMA requires that transfer buffers are placed in Data RAM region;
388 // signal error if they are not.
389 if ((p_tx_buffer != NULL && !nrfx_is_in_ram(p_tx_buffer)) ||
390 (p_rx_buffer != NULL && !nrfx_is_in_ram(p_rx_buffer)))
391 {
392 err_code = NRFX_ERROR_INVALID_ADDR;
393 NRFX_LOG_WARNING("Function: %s, error code: %s.",
394 __func__,
395 NRFX_LOG_ERROR_STRING_GET(err_code));
396 return err_code;
397 }
398
399 switch (p_cb->spi_state)
400 {
401 case SPIS_STATE_INIT:
402 case SPIS_XFER_COMPLETED:
403 case SPIS_BUFFER_RESOURCE_CONFIGURED:
404 p_cb->tx_buffer = p_tx_buffer;
405 p_cb->rx_buffer = p_rx_buffer;
406 p_cb->tx_buffer_size = tx_buffer_length;
407 p_cb->rx_buffer_size = rx_buffer_length;
408 err_code = NRFX_SUCCESS;
409
410 spis_state_change(p_instance->p_reg, p_cb, SPIS_BUFFER_RESOURCE_REQUESTED);
411 break;
412
413 case SPIS_BUFFER_RESOURCE_REQUESTED:
414 err_code = NRFX_ERROR_INVALID_STATE;
415 break;
416
417 default:
418 // @note: execution of this code path would imply internal error in the design.
419 err_code = NRFX_ERROR_INTERNAL;
420 break;
421 }
422
423 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
424 return err_code;
425 }
426
spis_irq_handler(NRF_SPIS_Type * p_spis,spis_cb_t * p_cb)427 static void spis_irq_handler(NRF_SPIS_Type * p_spis, spis_cb_t * p_cb)
428 {
429 // @note: as multiple events can be pending for processing, the correct event processing order
430 // is as follows:
431 // - SPI semaphore acquired event.
432 // - SPI transaction complete event.
433
434 // Check for SPI semaphore acquired event.
435 if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_ACQUIRED))
436 {
437 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
438 NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_ACQUIRED));
439
440 switch (p_cb->spi_state)
441 {
442 case SPIS_BUFFER_RESOURCE_REQUESTED:
443 nrf_spis_tx_buffer_set(p_spis, (uint8_t *)p_cb->tx_buffer, p_cb->tx_buffer_size);
444 nrf_spis_rx_buffer_set(p_spis, (uint8_t *)p_cb->rx_buffer, p_cb->rx_buffer_size);
445
446 nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_RELEASE);
447
448 spis_state_change(p_spis, p_cb, SPIS_BUFFER_RESOURCE_CONFIGURED);
449 break;
450
451 default:
452 // No implementation required.
453 break;
454 }
455 }
456
457 // Check for SPI transaction complete event.
458 if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_END))
459 {
460 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
461 NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_END));
462
463 switch (p_cb->spi_state)
464 {
465 case SPIS_BUFFER_RESOURCE_CONFIGURED:
466 spis_state_change(p_spis, p_cb, SPIS_XFER_COMPLETED);
467 break;
468
469 default:
470 // No implementation required.
471 break;
472 }
473 }
474 }
475
476 #if NRFX_CHECK(NRFX_SPIS0_ENABLED)
nrfx_spis_0_irq_handler(void)477 void nrfx_spis_0_irq_handler(void)
478 {
479 spis_irq_handler(NRF_SPIS0, &m_cb[NRFX_SPIS0_INST_IDX]);
480 }
481 #endif
482
483 #if NRFX_CHECK(NRFX_SPIS1_ENABLED)
nrfx_spis_1_irq_handler(void)484 void nrfx_spis_1_irq_handler(void)
485 {
486 spis_irq_handler(NRF_SPIS1, &m_cb[NRFX_SPIS1_INST_IDX]);
487 }
488 #endif
489
490 #if NRFX_CHECK(NRFX_SPIS2_ENABLED)
nrfx_spis_2_irq_handler(void)491 void nrfx_spis_2_irq_handler(void)
492 {
493 spis_irq_handler(NRF_SPIS2, &m_cb[NRFX_SPIS2_INST_IDX]);
494 }
495 #endif
496
497 #if NRFX_CHECK(NRFX_SPIS3_ENABLED)
nrfx_spis_3_irq_handler(void)498 void nrfx_spis_3_irq_handler(void)
499 {
500 spis_irq_handler(NRF_SPIS3, &m_cb[NRFX_SPIS3_INST_IDX]);
501 }
502 #endif
503
504 #endif // NRFX_CHECK(NRFX_SPIS_ENABLED)
505