1 /*
2  * Copyright (c) 2015 - 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_TWIM_ENABLED)
35 
36 #if !(NRFX_CHECK(NRFX_TWIM0_ENABLED) || NRFX_CHECK(NRFX_TWIM1_ENABLED))
37 #error "No enabled TWIM instances. Check <nrfx_config.h>."
38 #endif
39 
40 #include <nrfx_twim.h>
41 #include <hal/nrf_gpio.h>
42 #include "prs/nrfx_prs.h"
43 
44 #define NRFX_LOG_MODULE TWIM
45 #include <nrfx_log.h>
46 
47 #define EVT_TO_STR(event)                                       \
48     (event == NRFX_TWIM_EVT_DONE         ? "EVT_DONE"         : \
49     (event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
50     (event == NRFX_TWIM_EVT_DATA_NACK    ? "EVT_DATA_NACK"    : \
51                                            "UNKNOWN ERROR")))
52 
53 #define EVT_TO_STR_TWIM(event)                                        \
54     (event == NRF_TWIM_EVENT_STOPPED   ? "NRF_TWIM_EVENT_STOPPED"   : \
55     (event == NRF_TWIM_EVENT_ERROR     ? "NRF_TWIM_EVENT_ERROR"     : \
56     (event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \
57     (event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \
58     (event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \
59     (event == NRF_TWIM_EVENT_LASTRX    ? "NRF_TWIM_EVENT_LASTRX"    : \
60     (event == NRF_TWIM_EVENT_LASTTX    ? "NRF_TWIM_EVENT_LASTTX"    : \
61                                          "UNKNOWN ERROR")))))))
62 
63 #define TRANSFER_TO_STR(type)                    \
64     (type == NRFX_TWIM_XFER_TX   ? "XFER_TX"   : \
65     (type == NRFX_TWIM_XFER_RX   ? "XFER_RX"   : \
66     (type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \
67     (type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \
68                                    "UNKNOWN TRANSFER TYPE"))))
69 
70 #define TWIM_PIN_INIT(_pin) nrf_gpio_cfg((_pin),                     \
71                                          NRF_GPIO_PIN_DIR_INPUT,     \
72                                          NRF_GPIO_PIN_INPUT_CONNECT, \
73                                          NRF_GPIO_PIN_PULLUP,        \
74                                          NRF_GPIO_PIN_S0D1,          \
75                                          NRF_GPIO_PIN_NOSENSE)
76 
77 #define TWIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2)     \
78     (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
79      NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2))
80 
81 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
82 #define TWIM0_LENGTH_VALIDATE(...)  TWIMX_LENGTH_VALIDATE(TWIM0, __VA_ARGS__)
83 #else
84 #define TWIM0_LENGTH_VALIDATE(...)  0
85 #endif
86 
87 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
88 #define TWIM1_LENGTH_VALIDATE(...)  TWIMX_LENGTH_VALIDATE(TWIM1, __VA_ARGS__)
89 #else
90 #define TWIM1_LENGTH_VALIDATE(...)  0
91 #endif
92 
93 #define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2)  \
94     (TWIM0_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
95      TWIM1_LENGTH_VALIDATE(drv_inst_idx, len1, len2))
96 
97 // Control block - driver instance local data.
98 typedef struct
99 {
100     nrfx_twim_evt_handler_t handler;
101     void *                  p_context;
102     volatile uint32_t       int_mask;
103     nrfx_twim_xfer_desc_t   xfer_desc;
104     uint32_t                flags;
105     uint8_t *               p_curr_buf;
106     size_t                  curr_length;
107     bool                    curr_no_stop;
108     nrfx_drv_state_t        state;
109     bool                    error;
110     volatile bool           busy;
111     bool                    repeated;
112     uint8_t                 bytes_transferred;
113     bool                    hold_bus_uninit;
114 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
115     nrf_twim_frequency_t    bus_frequency;
116 #endif
117 } twim_control_block_t;
118 
119 static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT];
120 
twi_process_error(uint32_t errorsrc)121 static nrfx_err_t twi_process_error(uint32_t errorsrc)
122 {
123     nrfx_err_t ret = NRFX_ERROR_INTERNAL;
124 
125     if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
126     {
127         ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
128     }
129 
130     if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
131     {
132         ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
133     }
134 
135     return ret;
136 }
137 
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)138 nrfx_err_t nrfx_twim_init(nrfx_twim_t const *        p_instance,
139                           nrfx_twim_config_t const * p_config,
140                           nrfx_twim_evt_handler_t    event_handler,
141                           void *                     p_context)
142 {
143     NRFX_ASSERT(p_config);
144     NRFX_ASSERT(p_config->scl != p_config->sda);
145     twim_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
146     nrfx_err_t err_code;
147 
148     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
149     {
150         err_code = NRFX_ERROR_INVALID_STATE;
151         NRFX_LOG_WARNING("Function: %s, error code: %s.",
152                          __func__,
153                          NRFX_LOG_ERROR_STRING_GET(err_code));
154         return err_code;
155     }
156 
157 #if NRFX_CHECK(NRFX_PRS_ENABLED)
158     static nrfx_irq_handler_t const irq_handlers[NRFX_TWIM_ENABLED_COUNT] = {
159         #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
160         nrfx_twim_0_irq_handler,
161         #endif
162         #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
163         nrfx_twim_1_irq_handler,
164         #endif
165     };
166     if (nrfx_prs_acquire(p_instance->p_twim,
167             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
168     {
169         err_code = NRFX_ERROR_BUSY;
170         NRFX_LOG_WARNING("Function: %s, error code: %s.",
171                          __func__,
172                          NRFX_LOG_ERROR_STRING_GET(err_code));
173         return err_code;
174     }
175 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
176 
177     p_cb->handler         = event_handler;
178     p_cb->p_context       = p_context;
179     p_cb->int_mask        = 0;
180     p_cb->repeated        = false;
181     p_cb->busy            = false;
182     p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
183 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
184     p_cb->bus_frequency   = (nrf_twim_frequency_t)p_config->frequency;
185 #endif
186 
187     /* To secure correct signal levels on the pins used by the TWI
188        master when the system is in OFF mode, and when the TWI master is
189        disabled, these pins must be configured in the GPIO peripheral.
190     */
191     TWIM_PIN_INIT(p_config->scl);
192     TWIM_PIN_INIT(p_config->sda);
193 
194     NRF_TWIM_Type * p_twim = p_instance->p_twim;
195     nrf_twim_pins_set(p_twim, p_config->scl, p_config->sda);
196     nrf_twim_frequency_set(p_twim,
197         (nrf_twim_frequency_t)p_config->frequency);
198 
199     if (p_cb->handler)
200     {
201         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twim),
202             p_config->interrupt_priority);
203         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twim));
204     }
205 
206     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
207 
208     err_code = NRFX_SUCCESS;
209     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
210     return err_code;
211 }
212 
nrfx_twim_uninit(nrfx_twim_t const * p_instance)213 void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
214 {
215     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
216     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
217 
218     if (p_cb->handler)
219     {
220         NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twim));
221     }
222     nrfx_twim_disable(p_instance);
223 
224 #if NRFX_CHECK(NRFX_PRS_ENABLED)
225     nrfx_prs_release(p_instance->p_twim);
226 #endif
227 
228     if (!p_cb->hold_bus_uninit)
229     {
230         nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SCL);
231         nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SDA);
232     }
233 
234     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
235     NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
236 }
237 
nrfx_twim_enable(nrfx_twim_t const * p_instance)238 void nrfx_twim_enable(nrfx_twim_t const * p_instance)
239 {
240     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
241     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
242 
243     nrf_twim_enable(p_instance->p_twim);
244 
245     p_cb->state = NRFX_DRV_STATE_POWERED_ON;
246     NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
247 }
248 
nrfx_twim_disable(nrfx_twim_t const * p_instance)249 void nrfx_twim_disable(nrfx_twim_t const * p_instance)
250 {
251     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
252     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
253 
254     NRF_TWIM_Type * p_twim = p_instance->p_twim;
255     p_cb->int_mask = 0;
256     nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
257     nrf_twim_shorts_disable(p_twim, NRF_TWIM_ALL_SHORTS_MASK);
258     nrf_twim_disable(p_twim);
259 
260     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
261     NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
262 }
263 
264 
nrfx_twim_is_busy(nrfx_twim_t const * p_instance)265 bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance)
266 {
267     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
268     return p_cb->busy;
269 }
270 
271 
twim_list_enable_handle(NRF_TWIM_Type * p_twim,uint32_t flags)272 __STATIC_INLINE void twim_list_enable_handle(NRF_TWIM_Type * p_twim, uint32_t flags)
273 {
274     if (NRFX_TWIM_FLAG_TX_POSTINC & flags)
275     {
276         nrf_twim_tx_list_enable(p_twim);
277     }
278     else
279     {
280         nrf_twim_tx_list_disable(p_twim);
281     }
282 
283     if (NRFX_TWIM_FLAG_RX_POSTINC & flags)
284     {
285         nrf_twim_rx_list_enable(p_twim);
286     }
287     else
288     {
289         nrf_twim_rx_list_disable(p_twim);
290     }
291 }
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)292 __STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t        * p_cb,
293                                      NRF_TWIM_Type               * p_twim,
294                                      nrfx_twim_xfer_desc_t const * p_xfer_desc,
295                                      uint32_t                      flags)
296 {
297     nrfx_err_t err_code = NRFX_SUCCESS;
298     nrf_twim_task_t  start_task = NRF_TWIM_TASK_STARTTX;
299     nrf_twim_event_t evt_to_wait = NRF_TWIM_EVENT_STOPPED;
300 
301     if (!nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
302     {
303         err_code = NRFX_ERROR_INVALID_ADDR;
304         NRFX_LOG_WARNING("Function: %s, error code: %s.",
305                          __func__,
306                          NRFX_LOG_ERROR_STRING_GET(err_code));
307         return err_code;
308     }
309     /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
310     nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
311     if (p_cb->busy)
312     {
313         nrf_twim_int_enable(p_twim, p_cb->int_mask);
314         err_code = NRFX_ERROR_BUSY;
315         NRFX_LOG_WARNING("Function: %s, error code: %s.",
316                          __func__,
317                          NRFX_LOG_ERROR_STRING_GET(err_code));
318         return err_code;
319     }
320     else
321     {
322         p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
323                       (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true;
324     }
325 
326     p_cb->xfer_desc = *p_xfer_desc;
327     p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
328     nrf_twim_address_set(p_twim, p_xfer_desc->address);
329 
330     nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
331     nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
332 
333     twim_list_enable_handle(p_twim, flags);
334     switch (p_xfer_desc->type)
335     {
336     case NRFX_TWIM_XFER_TXTX:
337         NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
338         NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
339         NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
340         if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
341         {
342             err_code = NRFX_ERROR_INVALID_ADDR;
343             NRFX_LOG_WARNING("Function: %s, error code: %s.",
344                              __func__,
345                              NRFX_LOG_ERROR_STRING_GET(err_code));
346             return err_code;
347         }
348         nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
349         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
350         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
351         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
352         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
353         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
354         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
355         while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
356         {}
357         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
358         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
359         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
360         p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
361         break;
362     case NRFX_TWIM_XFER_TXRX:
363         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
364         if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
365         {
366             err_code = NRFX_ERROR_INVALID_ADDR;
367             NRFX_LOG_WARNING("Function: %s, error code: %s.",
368                              __func__,
369                              NRFX_LOG_ERROR_STRING_GET(err_code));
370             return err_code;
371         }
372         nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
373         nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
374                                     NRF_TWIM_SHORT_LASTRX_STOP_MASK);
375         p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
376         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
377         break;
378     case NRFX_TWIM_XFER_TX:
379         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
380         if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
381         {
382             nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
383             p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
384             nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
385             evt_to_wait = NRF_TWIM_EVENT_SUSPENDED;
386         }
387         else
388         {
389             nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
390             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
391         }
392         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
393         break;
394     case NRFX_TWIM_XFER_RX:
395         nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
396         nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
397         p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
398         start_task = NRF_TWIM_TASK_STARTRX;
399         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
400         break;
401     default:
402         err_code = NRFX_ERROR_INVALID_PARAM;
403         break;
404     }
405 
406     if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
407     {
408         nrf_twim_task_trigger(p_twim, start_task);
409     }
410 
411     if (p_cb->handler)
412     {
413         if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
414         {
415             p_cb->int_mask = NRF_TWIM_INT_ERROR_MASK;
416         }
417         nrf_twim_int_enable(p_twim, p_cb->int_mask);
418 
419 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
420         if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && ((p_xfer_desc->type == NRFX_TWIM_XFER_TX) ||
421                                                    (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)))
422         {
423             p_cb->flags = flags;
424             twim_list_enable_handle(p_twim, 0);
425             p_twim->FREQUENCY = 0;
426             nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
427             nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
428         }
429 #endif
430     }
431     else
432     {
433         while (!nrf_twim_event_check(p_twim, evt_to_wait))
434         {
435             if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
436             {
437                 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
438                 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
439                 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
440                 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
441                 evt_to_wait = NRF_TWIM_EVENT_STOPPED;
442             }
443         }
444 
445         uint32_t errorsrc =  nrf_twim_errorsrc_get_and_clear(p_twim);
446 
447         p_cb->busy = false;
448 
449         if (errorsrc)
450         {
451             err_code = twi_process_error(errorsrc);
452         }
453     }
454     return err_code;
455 }
456 
457 
nrfx_twim_xfer(nrfx_twim_t const * p_instance,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)458 nrfx_err_t nrfx_twim_xfer(nrfx_twim_t           const * p_instance,
459                           nrfx_twim_xfer_desc_t const * p_xfer_desc,
460                           uint32_t                      flags)
461 {
462     NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
463                                      p_xfer_desc->primary_length,
464                                      p_xfer_desc->secondary_length));
465 
466     nrfx_err_t err_code = NRFX_SUCCESS;
467     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
468 
469     // TXRX and TXTX transfers are supported only in non-blocking mode.
470     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)));
471     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX)));
472 
473     NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
474     NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
475                   p_xfer_desc->primary_length,
476                   p_xfer_desc->secondary_length);
477     NRFX_LOG_DEBUG("Primary buffer data:");
478     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
479                            p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0]));
480     NRFX_LOG_DEBUG("Secondary buffer data:");
481     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
482                            p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0]));
483 
484     err_code = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->p_twim, p_xfer_desc, flags);
485     NRFX_LOG_WARNING("Function: %s, error code: %s.",
486                      __func__,
487                      NRFX_LOG_ERROR_STRING_GET(err_code));
488     return err_code;
489 }
490 
nrfx_twim_tx(nrfx_twim_t const * p_instance,uint8_t address,uint8_t const * p_data,size_t length,bool no_stop)491 nrfx_err_t nrfx_twim_tx(nrfx_twim_t const * p_instance,
492                         uint8_t             address,
493                         uint8_t     const * p_data,
494                         size_t              length,
495                         bool                no_stop)
496 {
497     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TX(address, (uint8_t*)p_data, length);
498 
499     return nrfx_twim_xfer(p_instance, &xfer, no_stop ? NRFX_TWIM_FLAG_TX_NO_STOP : 0);
500 }
501 
nrfx_twim_rx(nrfx_twim_t const * p_instance,uint8_t address,uint8_t * p_data,size_t length)502 nrfx_err_t nrfx_twim_rx(nrfx_twim_t const * p_instance,
503                         uint8_t             address,
504                         uint8_t *           p_data,
505                         size_t              length)
506 {
507     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_RX(address, p_data, length);
508     return nrfx_twim_xfer(p_instance, &xfer, 0);
509 }
510 
nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,nrfx_twim_xfer_type_t xfer_type)511 uint32_t nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,
512                                   nrfx_twim_xfer_type_t xfer_type)
513 {
514     return (uint32_t)nrf_twim_task_address_get(p_instance->p_twim,
515         (xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX);
516 }
517 
nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)518 uint32_t nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)
519 {
520     return (uint32_t)nrf_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED);
521 }
522 
twim_irq_handler(NRF_TWIM_Type * p_twim,twim_control_block_t * p_cb)523 static void twim_irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb)
524 {
525 
526 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
527     /* Handle only workaround case. Can be used without TWIM handler in IRQs. */
528     if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
529     {
530         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
531         nrf_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
532         if (p_twim->FREQUENCY == 0)
533         {
534             // Set enable to zero to reset TWIM internal state.
535             nrf_twim_disable(p_twim);
536             nrf_twim_enable(p_twim);
537 
538             // Set proper frequency.
539             nrf_twim_frequency_set(p_twim, p_cb->bus_frequency);
540             twim_list_enable_handle(p_twim, p_cb->flags);
541 
542             // Start proper transmission.
543             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
544             return;
545         }
546     }
547 #endif
548 
549     NRFX_ASSERT(p_cb->handler);
550 
551     if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
552     {
553         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
554         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
555         if (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
556         {
557             nrf_twim_int_disable(p_twim, p_cb->int_mask);
558             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
559             nrf_twim_int_enable(p_twim, p_cb->int_mask);
560 
561             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
562             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
563             return;
564         }
565     }
566 
567     nrfx_twim_evt_t event;
568 
569     if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
570     {
571         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
572         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
573         event.xfer_desc = p_cb->xfer_desc;
574         if (p_cb->error)
575         {
576 
577             event.xfer_desc.primary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_RX) ?
578                 nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim);
579             event.xfer_desc.secondary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TXRX) ?
580                 nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim);
581 
582         }
583         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
584         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX);
585         if (!p_cb->repeated || p_cb->error)
586         {
587             nrf_twim_shorts_set(p_twim, 0);
588             p_cb->int_mask = 0;
589             nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
590         }
591     }
592     else
593     {
594         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
595         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
596         if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX)
597         {
598             event.xfer_desc = p_cb->xfer_desc;
599             if (!p_cb->repeated)
600             {
601                 nrf_twim_shorts_set(p_twim, 0);
602                 p_cb->int_mask = 0;
603                 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
604             }
605         }
606         else
607         {
608             nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
609             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
610             nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
611             nrf_twim_int_enable(p_twim, p_cb->int_mask);
612             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
613             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
614             return;
615         }
616     }
617 
618     uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim);
619     if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
620     {
621         event.type = NRFX_TWIM_EVT_ADDRESS_NACK;
622         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK));
623     }
624     else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
625     {
626         event.type = NRFX_TWIM_EVT_DATA_NACK;
627         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK));
628     }
629     else
630     {
631         event.type = NRFX_TWIM_EVT_DONE;
632         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE));
633     }
634 
635     if (!p_cb->repeated)
636     {
637         p_cb->busy = false;
638     }
639     p_cb->handler(&event, p_cb->p_context);
640 }
641 
642 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
nrfx_twim_0_irq_handler(void)643 void nrfx_twim_0_irq_handler(void)
644 {
645     twim_irq_handler(NRF_TWIM0, &m_cb[NRFX_TWIM0_INST_IDX]);
646 }
647 #endif
648 
649 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
nrfx_twim_1_irq_handler(void)650 void nrfx_twim_1_irq_handler(void)
651 {
652     twim_irq_handler(NRF_TWIM1, &m_cb[NRFX_TWIM1_INST_IDX]);
653 }
654 #endif
655 
656 #endif // NRFX_CHECK(NRFX_TWIM_ENABLED)
657