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_TWIM_ENABLED)
37 
38 #if !NRFX_FEATURE_PRESENT(NRFX_TWIM, _ENABLED)
39 #error "No enabled TWIM instances. Check <nrfx_config.h>."
40 #endif
41 
42 #include <nrfx_twim.h>
43 #include <haly/nrfy_gpio.h>
44 #include "prs/nrfx_prs.h"
45 
46 #define NRFX_LOG_MODULE TWIM
47 #include <nrfx_log.h>
48 
49 #define EVT_TO_STR(event)                                       \
50     (event == NRFX_TWIM_EVT_DONE         ? "EVT_DONE"         : \
51     (event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
52     (event == NRFX_TWIM_EVT_DATA_NACK    ? "EVT_DATA_NACK"    : \
53     (event == NRFX_TWIM_EVT_OVERRUN      ? "EVT_OVERRUN"      : \
54     (event == NRFX_TWIM_EVT_BUS_ERROR    ? "EVT_BUS_ERROR"    : \
55                                            "UNKNOWN ERROR")))))
56 
57 #define EVT_TO_STR_TWIM(event)                                        \
58     (event == NRF_TWIM_EVENT_STOPPED   ? "NRF_TWIM_EVENT_STOPPED"   : \
59     (event == NRF_TWIM_EVENT_ERROR     ? "NRF_TWIM_EVENT_ERROR"     : \
60     (event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \
61     (event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \
62     (event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \
63     (event == NRF_TWIM_EVENT_LASTRX    ? "NRF_TWIM_EVENT_LASTRX"    : \
64     (event == NRF_TWIM_EVENT_LASTTX    ? "NRF_TWIM_EVENT_LASTTX"    : \
65                                          "UNKNOWN ERROR")))))))
66 
67 #define TRANSFER_TO_STR(type)                    \
68     (type == NRFX_TWIM_XFER_TX   ? "XFER_TX"   : \
69     (type == NRFX_TWIM_XFER_RX   ? "XFER_RX"   : \
70     (type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \
71     (type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \
72                                    "UNKNOWN TRANSFER TYPE"))))
73 
74 #define TWIM_PIN_INIT(_pin, _drive) nrfy_gpio_cfg((_pin),                     \
75                                                   NRF_GPIO_PIN_DIR_INPUT,     \
76                                                   NRF_GPIO_PIN_INPUT_CONNECT, \
77                                                   NRF_GPIO_PIN_PULLUP,        \
78                                                   (_drive),                   \
79                                                   NRF_GPIO_PIN_NOSENSE)
80 
81 #define TWIMX_LENGTH_VALIDATE(periph_name, prefix, i, drv_inst_idx, len1, len2) \
82     (((drv_inst_idx) == NRFX_CONCAT(NRFX_, periph_name, prefix, i, _INST_IDX)) && \
83      NRFX_EASYDMA_LENGTH_VALIDATE(NRFX_CONCAT(periph_name, prefix, i), len1, len2))
84 
85 #define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2)    \
86         (NRFX_FOREACH_ENABLED(TWIM, TWIMX_LENGTH_VALIDATE, (||), (0), drv_inst_idx, len1, len2))
87 
88 // Control block - driver instance local data.
89 typedef struct
90 {
91     nrfx_twim_evt_handler_t handler;
92     void *                  p_context;
93     volatile uint32_t       int_mask;
94     nrfy_twim_xfer_desc_t   xfer_desc_primary;
95     nrfy_twim_xfer_desc_t   xfer_desc_secondary;
96     uint32_t                flags;
97     nrfx_twim_xfer_type_t   xfer_type;
98     uint8_t                 address;
99     nrfx_drv_state_t        state;
100     bool                    error;
101     volatile bool           busy;
102     bool                    repeated;
103     bool                    hold_bus_uninit;
104     bool                    skip_gpio_cfg;
105 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
106     nrf_twim_frequency_t    bus_frequency;
107 #endif
108 } twim_control_block_t;
109 
110 static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT];
111 
twi_process_error(uint32_t errorsrc)112 static nrfx_err_t twi_process_error(uint32_t errorsrc)
113 {
114     nrfx_err_t ret = NRFX_ERROR_INTERNAL;
115 
116     if (errorsrc & NRF_TWIM_ERROR_OVERRUN)
117     {
118         ret = NRFX_ERROR_DRV_TWI_ERR_OVERRUN;
119     }
120 
121     if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
122     {
123         ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
124     }
125 
126     if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
127     {
128         ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
129     }
130 
131     return ret;
132 }
133 
xfer_completeness_check(NRF_TWIM_Type * p_twim,twim_control_block_t const * p_cb)134 static bool xfer_completeness_check(NRF_TWIM_Type * p_twim, twim_control_block_t const * p_cb)
135 {
136     // If the actual number of transferred bytes is not equal to what was requested,
137     // but there was no error signaled by the peripheral, this means that something
138     // unexpected, like a premature STOP condition, was received on the bus.
139     // In such case the peripheral has to be disabled and re-enabled, so that its
140     // internal state machine is reinitialized.
141 
142     bool transfer_complete = true;
143     switch (p_cb->xfer_type)
144     {
145         case NRFX_TWIM_XFER_TXTX:
146             // int_mask variable is used to determine which length should be checked
147             // against number of bytes latched in EasyDMA.
148             // NRF_TWIM_INT_SUSPENDED_MASK is configured only in first TX of TXTX transfer.
149             if (((p_cb->int_mask & NRF_TWIM_INT_SUSPENDED_MASK) &&
150                  (nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_primary.length)) ||
151                 (!(p_cb->int_mask & NRF_TWIM_INT_SUSPENDED_MASK) &&
152                  (nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_secondary.length)))
153             {
154                 transfer_complete = false;
155             }
156             break;
157         case NRFX_TWIM_XFER_TXRX:
158             if ((nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_primary.length) ||
159                 (nrfy_twim_rxd_amount_get(p_twim) != p_cb->xfer_desc_secondary.length))
160             {
161                 transfer_complete = false;
162             }
163             break;
164         case NRFX_TWIM_XFER_TX:
165             if (nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_primary.length)
166             {
167                 transfer_complete = false;
168             }
169             break;
170         case NRFX_TWIM_XFER_RX:
171             if (nrfy_twim_rxd_amount_get(p_twim) != p_cb->xfer_desc_primary.length)
172             {
173                 transfer_complete = false;
174             }
175             break;
176         default:
177             break;
178     }
179 
180     if (!transfer_complete)
181     {
182         nrfy_twim_disable(p_twim);
183         nrfy_twim_enable(p_twim);
184     }
185 
186     return transfer_complete;
187 }
188 
twim_configure(nrfx_twim_t const * p_instance,nrfx_twim_config_t const * p_config)189 static void twim_configure(nrfx_twim_t const *        p_instance,
190                            nrfx_twim_config_t const * p_config)
191 {
192     nrfy_twim_config_t nrfy_config =
193     {
194         .pins = {
195             .scl_pin = p_config->scl_pin,
196             .sda_pin = p_config->sda_pin
197         },
198         .frequency     = p_config->frequency,
199         .skip_psel_cfg = p_config->skip_psel_cfg
200     };
201 
202     nrfy_twim_periph_configure(p_instance->p_twim, &nrfy_config);
203     if (m_cb[p_instance->drv_inst_idx].handler)
204     {
205         nrfy_twim_int_init(p_instance->p_twim, 0, p_config->interrupt_priority, false);
206     }
207 }
208 
pins_configure(nrfx_twim_config_t const * p_config)209 static bool pins_configure(nrfx_twim_config_t const * p_config)
210 {
211     nrf_gpio_pin_drive_t pin_drive;
212 
213     if (p_config->skip_psel_cfg && p_config->skip_gpio_cfg)
214     {
215         return true;
216     }
217 
218 #if NRF_TWIM_HAS_1000_KHZ_FREQ && defined(NRF5340_XXAA)
219     if (p_config->frequency >= NRF_TWIM_FREQ_1000K)
220     {
221         /* When using 1 Mbps mode, two high-speed pins have to be used with extra high drive. */
222         pin_drive = NRF_GPIO_PIN_E0E1;
223 
224         uint32_t e0e1_pin_1 = NRF_GPIO_PIN_MAP(1, 2);
225         uint32_t e0e1_pin_2 = NRF_GPIO_PIN_MAP(1, 3);
226 
227         /* Check whether provided pins have the extra high drive capabilities. */
228         if (((p_config->scl_pin != e0e1_pin_1) ||
229              (p_config->sda_pin != e0e1_pin_2)) &&
230             ((p_config->scl_pin != e0e1_pin_2) ||
231              (p_config->sda_pin != e0e1_pin_1)))
232         {
233             return false;
234         }
235     }
236     else
237 #endif
238     {
239         pin_drive = NRF_GPIO_PIN_S0D1;
240     }
241 
242     /* To secure correct signal levels on the pins used by the TWI
243        master when the system is in OFF mode, and when the TWI master is
244        disabled, these pins must be configured in the GPIO peripheral.
245     */
246    if (!p_config->skip_gpio_cfg)
247    {
248         NRFX_ASSERT(p_config->scl_pin != p_config->sda_pin);
249         TWIM_PIN_INIT(p_config->scl_pin, pin_drive);
250         TWIM_PIN_INIT(p_config->sda_pin, pin_drive);
251 #if NRF_GPIO_HAS_CLOCKPIN
252 #if defined(NRF_TWIM_CLOCKPIN_SCL_NEEDED)
253         nrfy_gpio_pin_clock_set(p_config->scl_pin, true);
254 #endif
255 #if defined(NRF_TWIM_CLOCKPIN_SDA_NEEDED)
256         nrfy_gpio_pin_clock_set(p_config->sda_pin, true);
257 #endif
258 #endif
259    }
260     return true;
261 }
262 
nrfx_twim_init(nrfx_twim_t const * p_instance,nrfx_twim_config_t const * p_config,nrfx_twim_evt_handler_t event_handler,void * p_context)263 nrfx_err_t nrfx_twim_init(nrfx_twim_t const *        p_instance,
264                           nrfx_twim_config_t const * p_config,
265                           nrfx_twim_evt_handler_t    event_handler,
266                           void *                     p_context)
267 {
268     NRFX_ASSERT(p_config);
269 
270     twim_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
271     nrfx_err_t err_code;
272 
273     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
274     {
275 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
276         err_code = NRFX_ERROR_ALREADY;
277 #else
278         err_code = NRFX_ERROR_INVALID_STATE;
279 #endif
280         NRFX_LOG_WARNING("Function: %s, error code: %s.",
281                          __func__,
282                          NRFX_LOG_ERROR_STRING_GET(err_code));
283         return err_code;
284     }
285 
286 #if NRFX_CHECK(NRFX_PRS_ENABLED)
287     static nrfx_irq_handler_t const irq_handlers[NRFX_TWIM_ENABLED_COUNT] = {
288         NRFX_INSTANCE_IRQ_HANDLERS_LIST(TWIM, twim)
289     };
290     if (nrfx_prs_acquire(p_instance->p_twim,
291             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
292     {
293         err_code = NRFX_ERROR_BUSY;
294         NRFX_LOG_WARNING("Function: %s, error code: %s.",
295                          __func__,
296                          NRFX_LOG_ERROR_STRING_GET(err_code));
297         return err_code;
298     }
299 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
300 
301     p_cb->handler         = event_handler;
302     p_cb->p_context       = p_context;
303     p_cb->int_mask        = 0;
304     p_cb->repeated        = false;
305     p_cb->busy            = false;
306 
307     if (p_config)
308     {
309         p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
310         if (!pins_configure(p_config))
311         {
312 #if NRFX_CHECK(NRFX_PRS_ENABLED)
313             nrfx_prs_release(p_instance->p_twim);
314 #endif
315             return NRFX_ERROR_INVALID_PARAM;
316         }
317 
318         p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
319         #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
320         p_cb->bus_frequency   = (nrf_twim_frequency_t)p_config->frequency;
321         #endif
322 
323         twim_configure(p_instance, p_config);
324     }
325 
326     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
327 
328     err_code = NRFX_SUCCESS;
329     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
330     return err_code;
331 }
332 
nrfx_twim_reconfigure(nrfx_twim_t const * p_instance,nrfx_twim_config_t const * p_config)333 nrfx_err_t nrfx_twim_reconfigure(nrfx_twim_t const *        p_instance,
334                                  nrfx_twim_config_t const * p_config)
335 {
336     NRFX_ASSERT(p_config);
337 
338     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
339 
340     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
341     {
342         return NRFX_ERROR_INVALID_STATE;
343     }
344     if (p_cb->busy)
345     {
346         return NRFX_ERROR_BUSY;
347     }
348 
349     nrfx_err_t err_code = NRFX_SUCCESS;
350     nrfy_twim_disable(p_instance->p_twim);
351     if (pins_configure(p_config))
352     {
353         twim_configure(p_instance, p_config);
354     }
355     else
356     {
357         err_code = NRFX_ERROR_INVALID_PARAM;
358     }
359     nrfy_twim_enable(p_instance->p_twim);
360     return err_code;
361 }
362 
nrfx_twim_uninit(nrfx_twim_t const * p_instance)363 void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
364 {
365     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
366 
367     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
368 
369     nrfy_twim_int_uninit(p_instance->p_twim);
370     nrfx_twim_disable(p_instance);
371 
372 #if NRFX_CHECK(NRFX_PRS_ENABLED)
373     nrfx_prs_release(p_instance->p_twim);
374 #endif
375 
376     if (!p_cb->skip_gpio_cfg && !p_cb->hold_bus_uninit)
377     {
378         nrfy_twim_pins_t pins;
379 
380         nrfy_twim_pins_get(p_instance->p_twim, &pins);
381         nrfy_gpio_cfg_default(pins.scl_pin);
382         nrfy_gpio_cfg_default(pins.sda_pin);
383     }
384 
385     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
386     NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
387 }
388 
nrfx_twim_init_check(nrfx_twim_t const * p_instance)389 bool nrfx_twim_init_check(nrfx_twim_t const * p_instance)
390 {
391     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
392 
393     return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
394 }
395 
nrfx_twim_enable(nrfx_twim_t const * p_instance)396 void nrfx_twim_enable(nrfx_twim_t const * p_instance)
397 {
398     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
399     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
400 
401     nrfy_twim_enable(p_instance->p_twim);
402 
403     p_cb->state = NRFX_DRV_STATE_POWERED_ON;
404     NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
405 }
406 
nrfx_twim_disable(nrfx_twim_t const * p_instance)407 void nrfx_twim_disable(nrfx_twim_t const * p_instance)
408 {
409     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
410 
411     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
412 
413     p_cb->int_mask = 0;
414     nrfy_twim_stop(p_instance->p_twim);
415     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
416     p_cb->busy = false;
417     NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
418 }
419 
nrfx_twim_is_busy(nrfx_twim_t const * p_instance)420 bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance)
421 {
422     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
423     return p_cb->busy;
424 }
425 
twim_xfer(twim_control_block_t * p_cb,NRF_TWIM_Type * p_twim,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)426 static nrfx_err_t twim_xfer(twim_control_block_t        * p_cb,
427                             NRF_TWIM_Type               * p_twim,
428                             nrfx_twim_xfer_desc_t const * p_xfer_desc,
429                             uint32_t                      flags)
430 {
431     nrfx_err_t err_code = NRFX_SUCCESS;
432     p_cb->error = false;
433 
434     if (p_xfer_desc->primary_length != 0 &&
435         !nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
436     {
437         err_code = NRFX_ERROR_INVALID_ADDR;
438         NRFX_LOG_WARNING("Function: %s, error code: %s.",
439                          __func__,
440                          NRFX_LOG_ERROR_STRING_GET(err_code));
441         return err_code;
442     }
443 
444     if ((p_xfer_desc->type == NRFX_TWIM_XFER_TXTX ||
445          p_xfer_desc->type == NRFX_TWIM_XFER_TXRX) &&
446          !nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
447     {
448             err_code = NRFX_ERROR_INVALID_ADDR;
449             NRFX_LOG_WARNING("Function: %s, error code: %s.",
450                              __func__,
451                              NRFX_LOG_ERROR_STRING_GET(err_code));
452             return err_code;
453     }
454 
455 #if !NRFY_TWIM_HAS_ARRAY_LIST
456     if ((NRFX_TWIM_FLAG_TX_POSTINC | NRFX_TWIM_FLAG_RX_POSTINC) & flags)
457     {
458         err_code = NRFX_ERROR_NOT_SUPPORTED;
459         NRFX_LOG_WARNING("Function: %s, error code: %s.",
460                          __func__,
461                          NRFX_LOG_ERROR_STRING_GET(err_code));
462         return err_code;
463     }
464 #endif
465 
466     /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
467     nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
468     if (p_cb->busy)
469     {
470         nrfy_twim_int_enable(p_twim, p_cb->int_mask);
471         err_code = NRFX_ERROR_BUSY;
472         NRFX_LOG_WARNING("Function: %s, error code: %s.",
473                          __func__,
474                          NRFX_LOG_ERROR_STRING_GET(err_code));
475         return err_code;
476     }
477     else
478     {
479         p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
480                       (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false : true;
481     }
482 
483     p_cb->xfer_type = p_xfer_desc->type;
484     p_cb->address   = p_xfer_desc->address;
485     p_cb->xfer_desc_primary.p_buffer   = p_xfer_desc->p_primary_buf;
486     p_cb->xfer_desc_primary.length     = p_xfer_desc->primary_length;
487     p_cb->xfer_desc_secondary.p_buffer = p_xfer_desc->p_secondary_buf;
488     p_cb->xfer_desc_secondary.length   = p_xfer_desc->secondary_length;
489     p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
490     p_cb->flags = flags;
491     nrfy_twim_address_set(p_twim, p_xfer_desc->address);
492 
493     nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
494     nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
495     nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
496     nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
497 
498 #if NRFY_TWIM_HAS_ARRAY_LIST
499     nrfy_twim_tx_list_set(p_twim, NRFX_TWIM_FLAG_TX_POSTINC & flags);
500     nrfy_twim_rx_list_set(p_twim, NRFX_TWIM_FLAG_RX_POSTINC & flags);
501 #endif
502     switch (p_xfer_desc->type)
503     {
504         case NRFX_TWIM_XFER_TXTX:
505             NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
506             NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
507             NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
508             nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
509             nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
510             nrfy_twim_tx_start(p_twim, NULL);
511             while (nrfy_twim_events_process(p_twim,
512                                             NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_TXSTARTED),
513                                             NULL))
514             {}
515             nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_secondary);
516             NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
517             p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK;
518             break;
519         case NRFX_TWIM_XFER_TXRX:
520             nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
521             nrfy_twim_rx_buffer_set(p_twim, &p_cb->xfer_desc_secondary);
522             nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
523                                     NRF_TWIM_SHORT_LASTRX_STOP_MASK);
524             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
525             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
526             break;
527         case NRFX_TWIM_XFER_TX:
528             nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
529             if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
530             {
531                 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
532                 p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK;
533             }
534             else
535             {
536                 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
537                 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
538             }
539             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
540             break;
541         case NRFX_TWIM_XFER_RX:
542             nrfy_twim_rx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
543             nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
544             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
545             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
546             break;
547         default:
548             err_code = NRFX_ERROR_INVALID_PARAM;
549             break;
550     }
551 
552     if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
553     {
554         if (p_xfer_desc->type == NRFX_TWIM_XFER_RX)
555         {
556             nrfy_twim_rx_start(p_twim, p_cb->handler ? NULL : &p_cb->xfer_desc_primary);
557         }
558         else
559         {
560             nrfy_twim_tx_start(p_twim, p_cb->handler ? NULL : &p_cb->xfer_desc_primary);
561         }
562         /* Handling zero length transfers in non-blocking mode.
563            In blocking mode zero length transfer is handled in
564            @ref{nrfy_twim_tx_start} and @ref{nrfy_twim_rx_start}
565         */
566         if (p_xfer_desc->primary_length == 0 && p_cb->handler)
567         {
568             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
569         }
570     }
571 
572     if (p_cb->handler)
573     {
574         if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
575         {
576             p_cb->int_mask = 0;
577         }
578 
579         if (!(flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK))
580         {
581             p_cb->int_mask |= NRF_TWIM_INT_STOPPED_MASK;
582         }
583 
584         // Interrupts for ERROR are implicitly enabled, regardless of driver configuration.
585         p_cb->int_mask |= NRF_TWIM_INT_ERROR_MASK;
586         nrfy_twim_int_enable(p_twim, p_cb->int_mask);
587 
588 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
589         if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_RX))
590         {
591             nrfy_twim_tx_list_set(p_twim, false);
592             nrfy_twim_rx_list_set(p_twim, false);
593             p_twim->FREQUENCY = 0;
594             nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
595             nrfy_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
596         }
597         else
598         {
599             nrfy_twim_frequency_set(p_twim, p_cb->bus_frequency);
600         }
601 #endif
602     }
603     else
604     {
605         uint32_t errorsrc = nrfy_twim_errorsrc_get_and_clear(p_twim);
606 
607         p_cb->busy = false;
608 
609         if (errorsrc)
610         {
611             err_code = twi_process_error(errorsrc);
612         }
613         else
614         {
615             if (!(flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK) &&
616                 !xfer_completeness_check(p_twim, p_cb))
617             {
618                 err_code = NRFX_ERROR_INTERNAL;
619             }
620         }
621     }
622 
623     NRFX_LOG_INFO("Function: %s, error code: %s.",
624                   __func__,
625                   NRFX_LOG_ERROR_STRING_GET(err_code));
626     return err_code;
627 }
628 
629 
nrfx_twim_xfer(nrfx_twim_t const * p_instance,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)630 nrfx_err_t nrfx_twim_xfer(nrfx_twim_t           const * p_instance,
631                           nrfx_twim_xfer_desc_t const * p_xfer_desc,
632                           uint32_t                      flags)
633 {
634     NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
635                                      p_xfer_desc->primary_length,
636                                      p_xfer_desc->secondary_length));
637 
638     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
639 
640     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
641 
642     // TXRX and TXTX transfers are supported only in non-blocking mode.
643     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)));
644     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX)));
645 
646     NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
647     NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
648                   p_xfer_desc->primary_length,
649                   p_xfer_desc->secondary_length);
650     NRFX_LOG_DEBUG("Primary buffer data:");
651     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
652                            p_xfer_desc->primary_length *
653                            sizeof(p_xfer_desc->p_primary_buf[0]));
654     NRFX_LOG_DEBUG("Secondary buffer data:");
655     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
656                            p_xfer_desc->secondary_length *
657                            sizeof(p_xfer_desc->p_secondary_buf[0]));
658 
659     return twim_xfer(p_cb, p_instance->p_twim, p_xfer_desc, flags);
660 }
661 
nrfx_twim_start_task_address_get(nrfx_twim_t const * p_instance,nrfx_twim_xfer_type_t xfer_type)662 uint32_t nrfx_twim_start_task_address_get(nrfx_twim_t const *   p_instance,
663                                           nrfx_twim_xfer_type_t xfer_type)
664 {
665     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
666 
667     return nrfy_twim_task_address_get(p_instance->p_twim,
668         (xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX);
669 }
670 
nrfx_twim_stopped_event_address_get(nrfx_twim_t const * p_instance)671 uint32_t nrfx_twim_stopped_event_address_get(nrfx_twim_t const * p_instance)
672 {
673     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
674 
675     return nrfy_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED);
676 }
677 
irq_handler(NRF_TWIM_Type * p_twim,twim_control_block_t * p_cb)678 static void irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb)
679 {
680     nrfy_twim_xfer_desc_t * p_xfer = p_cb->xfer_type == NRFX_TWIM_XFER_RX ?
681                                                         &p_cb->xfer_desc_primary :
682                                                         &p_cb->xfer_desc_secondary;
683 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
684     if (nrfy_twim_events_process(p_twim,
685                                  NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_TXSTARTED),
686                                  NULL))
687     {
688         nrfy_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
689         if (p_twim->FREQUENCY == 0)
690         {
691             // Set enable to zero to reset TWIM internal state.
692             nrfy_twim_disable(p_twim);
693             nrfy_twim_enable(p_twim);
694 
695             // Set proper frequency.
696             nrfy_twim_frequency_set(p_twim, p_cb->bus_frequency);
697             nrfy_twim_tx_list_set(p_twim, NRFX_TWIM_FLAG_TX_POSTINC & p_cb->flags);
698             nrfy_twim_rx_list_set(p_twim, NRFX_TWIM_FLAG_RX_POSTINC & p_cb->flags);
699             // Start proper transmission.
700             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
701             return;
702         }
703     }
704 #endif
705     NRFX_ASSERT(p_cb->handler);
706 
707     bool stopped = nrfy_twim_events_process(p_twim,
708                                             NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_STOPPED),
709                                             p_xfer);
710 
711     if (nrfy_twim_events_process(p_twim,
712                                  NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_ERROR),
713                                  p_xfer))
714     {
715         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
716         if (!stopped)
717         {
718             nrfy_twim_int_disable(p_twim, p_cb->int_mask);
719             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
720             nrfy_twim_int_enable(p_twim, p_cb->int_mask);
721 
722             if (!(nrfy_twim_events_process(p_twim,
723                                            NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_LASTTX),
724                                            NULL) &&
725                  (nrfy_twim_shorts_get(p_twim) & NRF_TWIM_SHORT_LASTTX_STOP_MASK)))
726             {
727                 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
728                 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
729             }
730 
731             p_cb->error = true;
732             return;
733         }
734     }
735 
736     nrfx_twim_evt_t event;
737 
738     if (stopped)
739     {
740         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
741 
742         if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK) && !p_cb->error)
743         {
744             p_cb->error = !xfer_completeness_check(p_twim, p_cb);
745         }
746 
747         // Further processing of STOPPED event is valid only if NO_XFER_EVT_HANDLER
748         // setting is not used.
749         if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER))
750         {
751             nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
752             nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX);
753             if (!p_cb->repeated || p_cb->error)
754             {
755                 nrfy_twim_shorts_set(p_twim, 0);
756                 p_cb->int_mask = 0;
757                 nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
758 
759                 // At this point interrupt handler should not be invoked again for current transfer.
760                 // If STOPPED arrived during ERROR processing,
761                 // its pending interrupt should be ignored.
762                 // Otherwise spurious NRFX_TWIM_EVT_DONE or NRFX_TWIM_EVT_BUS_ERROR
763                 // would be passed to user's handler.
764                 NRFY_IRQ_PENDING_CLEAR(nrfx_get_irq_number(p_twim));
765             }
766 
767             event.xfer_desc.type    = p_cb->xfer_type;
768             event.xfer_desc.address = p_cb->address;
769             event.xfer_desc.p_primary_buf    = p_cb->xfer_desc_primary.p_buffer;
770             event.xfer_desc.primary_length   = p_cb->xfer_desc_primary.length;
771             event.xfer_desc.p_secondary_buf  = p_cb->xfer_desc_secondary.p_buffer;
772             event.xfer_desc.secondary_length = p_cb->xfer_desc_secondary.length;
773         }
774 
775 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
776         else if (p_cb->xfer_type != NRFX_TWIM_XFER_RX)
777         {
778             /* Add Anomaly 109 workaround for each potential repeated transfer starting from TX. */
779             nrfy_twim_tx_list_set(p_twim, false);
780             nrfy_twim_rx_list_set(p_twim, false);
781             nrfy_twim_frequency_set(p_twim, (nrf_twim_frequency_t)0);
782             nrfy_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
783         }
784 #endif
785     }
786     else
787     {
788         (void)nrfy_twim_events_process(p_twim,
789                                        NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_SUSPENDED),
790                                        p_xfer);
791         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
792         if (p_cb->xfer_type == NRFX_TWIM_XFER_TX)
793         {
794             if (!p_cb->repeated)
795             {
796                 nrfy_twim_shorts_set(p_twim, 0);
797                 p_cb->int_mask = 0;
798                 nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
799 
800                 // At this point interrupt handler should not be invoked again for current transfer.
801                 // If STOPPED arrived during SUSPENDED processing,
802                 // its pending interrupt should be ignored.
803                 // Otherwise spurious NRFX_TWIM_EVT_DONE or NRFX_TWIM_EVT_BUS_ERROR
804                 // would be passed to user's handler.
805                 NRFY_IRQ_PENDING_CLEAR(nrfx_get_irq_number(p_twim));
806             }
807 
808             event.xfer_desc.type    = p_cb->xfer_type;
809             event.xfer_desc.address = p_cb->address;
810             event.xfer_desc.p_primary_buf    = p_cb->xfer_desc_primary.p_buffer;
811             event.xfer_desc.primary_length   = p_cb->xfer_desc_primary.length;
812             event.xfer_desc.p_secondary_buf  = p_cb->xfer_desc_secondary.p_buffer;
813             event.xfer_desc.secondary_length = p_cb->xfer_desc_secondary.length;
814         }
815         else
816         {
817             nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
818             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
819             nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
820             nrfy_twim_int_enable(p_twim, p_cb->int_mask);
821             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
822             nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
823             return;
824         }
825     }
826 
827     uint32_t errorsrc = nrfy_twim_errorsrc_get_and_clear(p_twim);
828     if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
829     {
830         event.type = NRFX_TWIM_EVT_ADDRESS_NACK;
831         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK));
832     }
833     else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
834     {
835         event.type = NRFX_TWIM_EVT_DATA_NACK;
836         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK));
837     }
838     else if (errorsrc & NRF_TWIM_ERROR_OVERRUN)
839     {
840         event.type = NRFX_TWIM_EVT_OVERRUN;
841         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_OVERRUN));
842     }
843     else if (p_cb->error)
844     {
845         event.type = NRFX_TWIM_EVT_BUS_ERROR;
846         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_BUS_ERROR));
847     }
848     else
849     {
850         event.type = NRFX_TWIM_EVT_DONE;
851         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE));
852     }
853 
854     if (!p_cb->repeated)
855     {
856         p_cb->busy = false;
857     }
858 
859     if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER) || p_cb->error)
860     {
861         p_cb->handler(&event, p_cb->p_context);
862     }
863 }
864 
865 NRFX_INSTANCE_IRQ_HANDLERS(TWIM, twim)
866 
867 #endif // NRFX_CHECK(NRFX_TWIM_ENABLED)
868