1 /*
2  * Copyright (c) 2015 - 2020, 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_I2S_ENABLED)
35 
36 #include <nrfx_i2s.h>
37 #include <hal/nrf_gpio.h>
38 
39 #define NRFX_LOG_MODULE I2S
40 #include <nrfx_log.h>
41 
42 #define EVT_TO_STR(event)                                         \
43     (event == NRF_I2S_EVENT_RXPTRUPD ? "NRF_I2S_EVENT_RXPTRUPD" : \
44     (event == NRF_I2S_EVENT_TXPTRUPD ? "NRF_I2S_EVENT_TXPTRUPD" : \
45     (event == NRF_I2S_EVENT_STOPPED  ? "NRF_I2S_EVENT_STOPPED"  : \
46                                        "UNKNOWN EVENT")))
47 
48 #if !defined(USE_WORKAROUND_FOR_I2S_STOP_ANOMALY) && \
49     (defined(NRF52_SERIES) || defined(NRF9160_XXAA))
50 // Enable workaround for nRF52 Series anomaly 194 / nRF9160 anomaly 1
51 // (STOP task does not switch off all resources).
52 #define USE_WORKAROUND_FOR_I2S_STOP_ANOMALY 1
53 #endif
54 
55 #if !defined(USE_WORKAROUND_FOR_ANOMALY_170) && defined(NRF52_SERIES)
56 // Enable workaround for nRF52 Series anomaly 170
57 // (when reading the value of PSEL registers, the CONNECT field might not
58 //  return the same value that has been written to it).
59 #define USE_WORKAROUND_FOR_ANOMALY_170 1
60 #endif
61 
62 #if !defined(USE_WORKAROUND_FOR_ANOMALY_196) && defined(NRF52_SERIES)
63 // Enable workaround for nRF52 Series anomaly 196
64 // (PSEL acquires GPIO regardless of ENABLE).
65 #define USE_WORKAROUND_FOR_ANOMALY_196 1
66 #endif
67 
68 // Control block - driver instance local data.
69 typedef struct
70 {
71     nrfx_i2s_data_handler_t handler;
72     nrfx_drv_state_t        state;
73 
74     bool use_rx         : 1;
75     bool use_tx         : 1;
76     bool rx_ready       : 1;
77     bool tx_ready       : 1;
78     bool buffers_needed : 1;
79     bool buffers_reused : 1;
80 
81     uint16_t            buffer_size;
82     nrfx_i2s_buffers_t  next_buffers;
83     nrfx_i2s_buffers_t  current_buffers;
84 } i2s_control_block_t;
85 static i2s_control_block_t m_cb;
86 
87 
configure_pins(nrfx_i2s_config_t const * p_config)88 static void configure_pins(nrfx_i2s_config_t const * p_config)
89 {
90     uint32_t mck_pin, sdout_pin, sdin_pin;
91 
92     // Configure pins used by the peripheral:
93 
94     // - SCK and LRCK (required) - depending on the mode of operation these
95     //   pins are configured as outputs (in Master mode) or inputs (in Slave
96     //   mode).
97     if (p_config->mode == NRF_I2S_MODE_MASTER)
98     {
99         nrf_gpio_cfg_output(p_config->sck_pin);
100         nrf_gpio_cfg_output(p_config->lrck_pin);
101     }
102     else
103     {
104         nrf_gpio_cfg_input(p_config->sck_pin,  NRF_GPIO_PIN_NOPULL);
105         nrf_gpio_cfg_input(p_config->lrck_pin, NRF_GPIO_PIN_NOPULL);
106     }
107 
108     // - MCK (optional) - always output,
109     if (p_config->mck_pin != NRFX_I2S_PIN_NOT_USED)
110     {
111         mck_pin = p_config->mck_pin;
112         nrf_gpio_cfg_output(mck_pin);
113     }
114     else
115     {
116         mck_pin = NRF_I2S_PIN_NOT_CONNECTED;
117     }
118 
119     // - SDOUT (optional) - always output,
120     if (p_config->sdout_pin != NRFX_I2S_PIN_NOT_USED)
121     {
122         sdout_pin = p_config->sdout_pin;
123         nrf_gpio_cfg_output(sdout_pin);
124     }
125     else
126     {
127         sdout_pin = NRF_I2S_PIN_NOT_CONNECTED;
128     }
129 
130     // - SDIN (optional) - always input.
131     if (p_config->sdin_pin != NRFX_I2S_PIN_NOT_USED)
132     {
133         sdin_pin = p_config->sdin_pin;
134         nrf_gpio_cfg_input(sdin_pin, NRF_GPIO_PIN_NOPULL);
135     }
136     else
137     {
138         sdin_pin = NRF_I2S_PIN_NOT_CONNECTED;
139     }
140 
141     nrf_i2s_pins_set(NRF_I2S0,
142                      p_config->sck_pin,
143                      p_config->lrck_pin,
144                      mck_pin,
145                      sdout_pin,
146                      sdin_pin);
147 }
148 
deconfigure_pins(void)149 static void deconfigure_pins(void)
150 {
151     uint32_t sck_pin   = nrf_i2s_sck_pin_get(NRF_I2S0);
152     uint32_t lrck_pin  = nrf_i2s_lrck_pin_get(NRF_I2S0);
153     uint32_t mck_pin   = nrf_i2s_mck_pin_get(NRF_I2S0);
154     uint32_t sdout_pin = nrf_i2s_sdout_pin_get(NRF_I2S0);
155     uint32_t sdin_pin  = nrf_i2s_sdin_pin_get(NRF_I2S0);
156 
157 #if USE_WORKAROUND_FOR_ANOMALY_170
158     // Create bitmask for extracting pin number from PSEL register.
159     uint32_t pin_mask = I2S_PSEL_SCK_PIN_Msk;
160 #if defined(I2S_PSEL_SCK_PORT_Msk)
161     // If device supports more than one GPIO port, take port number into account as well.
162     pin_mask |= I2S_PSEL_SCK_PORT_Msk;
163 #endif
164 #else
165     uint32_t pin_mask = 0xFFFFFFFF;
166 #endif // USE_WORKAROUND_FOR_ANOMALY_170
167 
168     nrf_gpio_cfg_default(sck_pin & pin_mask);
169     nrf_gpio_cfg_default(lrck_pin & pin_mask);
170 
171     if (mck_pin != NRF_I2S_PIN_NOT_CONNECTED)
172     {
173         nrf_gpio_cfg_default(mck_pin & pin_mask);
174     }
175 
176     if (sdout_pin != NRF_I2S_PIN_NOT_CONNECTED)
177     {
178         nrf_gpio_cfg_default(sdout_pin & pin_mask);
179     }
180 
181     if (sdin_pin != NRF_I2S_PIN_NOT_CONNECTED)
182     {
183         nrf_gpio_cfg_default(sdin_pin & pin_mask);
184     }
185 }
186 
nrfx_i2s_init(nrfx_i2s_config_t const * p_config,nrfx_i2s_data_handler_t handler)187 nrfx_err_t nrfx_i2s_init(nrfx_i2s_config_t const * p_config,
188                          nrfx_i2s_data_handler_t   handler)
189 {
190     NRFX_ASSERT(p_config);
191     NRFX_ASSERT(handler);
192 
193     nrfx_err_t err_code;
194 
195     if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
196     {
197         err_code = NRFX_ERROR_INVALID_STATE;
198         NRFX_LOG_WARNING("Function: %s, error code: %s.",
199                          __func__,
200                          NRFX_LOG_ERROR_STRING_GET(err_code));
201         return err_code;
202     }
203 
204     if (!nrf_i2s_configure(NRF_I2S0,
205                            p_config->mode,
206                            p_config->format,
207                            p_config->alignment,
208                            p_config->sample_width,
209                            p_config->channels,
210                            p_config->mck_setup,
211                            p_config->ratio))
212     {
213         err_code = NRFX_ERROR_INVALID_PARAM;
214         NRFX_LOG_WARNING("Function: %s, error code: %s.",
215                          __func__,
216                          NRFX_LOG_ERROR_STRING_GET(err_code));
217         return err_code;
218     }
219 
220 #if NRF_I2S_HAS_CLKCONFIG
221     nrf_i2s_clk_configure(NRF_I2S0, p_config->clksrc, p_config->enable_bypass);
222 #endif
223     configure_pins(p_config);
224 
225     m_cb.handler = handler;
226 
227     NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(NRF_I2S0), p_config->irq_priority);
228     NRFX_IRQ_ENABLE(nrfx_get_irq_number(NRF_I2S0));
229 
230     m_cb.state = NRFX_DRV_STATE_INITIALIZED;
231 
232     NRFX_LOG_INFO("Initialized.");
233     return NRFX_SUCCESS;
234 }
235 
236 
nrfx_i2s_uninit(void)237 void nrfx_i2s_uninit(void)
238 {
239     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
240 
241     nrfx_i2s_stop();
242 
243     NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_I2S0));
244 
245     nrf_i2s_disable(NRF_I2S0);
246 
247     deconfigure_pins();
248 
249 #if USE_WORKAROUND_FOR_ANOMALY_196
250     // Disabling I2S is insufficient to release pins acquired by the peripheral.
251     // Explicit disconnect is needed.
252     nrf_i2s_pins_set(NRF_I2S0,
253                      NRF_I2S_PIN_NOT_CONNECTED,
254                      NRF_I2S_PIN_NOT_CONNECTED,
255                      NRF_I2S_PIN_NOT_CONNECTED,
256                      NRF_I2S_PIN_NOT_CONNECTED,
257                      NRF_I2S_PIN_NOT_CONNECTED);
258 #endif
259 
260     m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
261     NRFX_LOG_INFO("Uninitialized.");
262 }
263 
264 
nrfx_i2s_start(nrfx_i2s_buffers_t const * p_initial_buffers,uint16_t buffer_size,uint8_t flags)265 nrfx_err_t nrfx_i2s_start(nrfx_i2s_buffers_t const * p_initial_buffers,
266                           uint16_t                   buffer_size,
267                           uint8_t                    flags)
268 {
269     NRFX_ASSERT(p_initial_buffers != NULL);
270     NRFX_ASSERT(p_initial_buffers->p_rx_buffer != NULL ||
271                 p_initial_buffers->p_tx_buffer != NULL);
272     NRFX_ASSERT((p_initial_buffers->p_rx_buffer == NULL) ||
273                 (nrfx_is_in_ram(p_initial_buffers->p_rx_buffer) &&
274                  nrfx_is_word_aligned(p_initial_buffers->p_rx_buffer)));
275     NRFX_ASSERT((p_initial_buffers->p_tx_buffer == NULL) ||
276                 (nrfx_is_in_ram(p_initial_buffers->p_tx_buffer) &&
277                  nrfx_is_word_aligned(p_initial_buffers->p_tx_buffer)));
278     NRFX_ASSERT(buffer_size != 0);
279     (void)(flags);
280 
281     nrfx_err_t err_code;
282 
283     if (m_cb.state != NRFX_DRV_STATE_INITIALIZED)
284     {
285         err_code = NRFX_ERROR_INVALID_STATE;
286         NRFX_LOG_WARNING("Function: %s, error code: %s.",
287                          __func__,
288                          NRFX_LOG_ERROR_STRING_GET(err_code));
289         return err_code;
290     }
291 
292     if (((p_initial_buffers->p_rx_buffer != NULL)
293          && !nrfx_is_in_ram(p_initial_buffers->p_rx_buffer))
294         ||
295         ((p_initial_buffers->p_tx_buffer != NULL)
296          && !nrfx_is_in_ram(p_initial_buffers->p_tx_buffer)))
297     {
298         err_code = NRFX_ERROR_INVALID_ADDR;
299         NRFX_LOG_WARNING("Function: %s, error code: %s.",
300                          __func__,
301                          NRFX_LOG_ERROR_STRING_GET(err_code));
302         return err_code;
303     }
304 
305     m_cb.use_rx         = (p_initial_buffers->p_rx_buffer != NULL);
306     m_cb.use_tx         = (p_initial_buffers->p_tx_buffer != NULL);
307     m_cb.rx_ready       = false;
308     m_cb.tx_ready       = false;
309     m_cb.buffers_needed = false;
310     m_cb.buffer_size    = buffer_size;
311 
312     // Set the provided initial buffers as next, they will become the current
313     // ones after the IRQ handler is called for the first time, what will occur
314     // right after the START task is triggered.
315     m_cb.next_buffers = *p_initial_buffers;
316     m_cb.current_buffers.p_rx_buffer = NULL;
317     m_cb.current_buffers.p_tx_buffer = NULL;
318 
319     nrf_i2s_transfer_set(NRF_I2S0,
320                          m_cb.buffer_size,
321                          m_cb.next_buffers.p_rx_buffer,
322                          m_cb.next_buffers.p_tx_buffer);
323 
324     nrf_i2s_enable(NRF_I2S0);
325 
326     m_cb.state = NRFX_DRV_STATE_POWERED_ON;
327 
328     nrf_i2s_event_clear(NRF_I2S0, NRF_I2S_EVENT_RXPTRUPD);
329     nrf_i2s_event_clear(NRF_I2S0, NRF_I2S_EVENT_TXPTRUPD);
330     nrf_i2s_event_clear(NRF_I2S0, NRF_I2S_EVENT_STOPPED);
331     nrf_i2s_int_enable(NRF_I2S0, (m_cb.use_rx ? NRF_I2S_INT_RXPTRUPD_MASK : 0) |
332                                  (m_cb.use_tx ? NRF_I2S_INT_TXPTRUPD_MASK : 0) |
333                                  NRF_I2S_INT_STOPPED_MASK);
334     nrf_i2s_task_trigger(NRF_I2S0, NRF_I2S_TASK_START);
335 
336     NRFX_LOG_INFO("Started.");
337     return NRFX_SUCCESS;
338 }
339 
340 
nrfx_i2s_next_buffers_set(nrfx_i2s_buffers_t const * p_buffers)341 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_buffers_t const * p_buffers)
342 {
343     NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_POWERED_ON);
344     NRFX_ASSERT(p_buffers);
345     NRFX_ASSERT((p_buffers->p_rx_buffer == NULL) ||
346                 (nrfx_is_in_ram(p_buffers->p_rx_buffer) &&
347                  nrfx_is_word_aligned(p_buffers->p_rx_buffer)));
348     NRFX_ASSERT((p_buffers->p_tx_buffer == NULL) ||
349                 (nrfx_is_in_ram(p_buffers->p_tx_buffer) &&
350                  nrfx_is_word_aligned(p_buffers->p_tx_buffer)));
351 
352     nrfx_err_t err_code;
353 
354     if (!m_cb.buffers_needed)
355     {
356         err_code = NRFX_ERROR_INVALID_STATE;
357         NRFX_LOG_WARNING("Function: %s, error code: %s.",
358                          __func__,
359                          NRFX_LOG_ERROR_STRING_GET(err_code));
360         return err_code;
361     }
362 
363     if (((p_buffers->p_rx_buffer != NULL)
364          && !nrfx_is_in_ram(p_buffers->p_rx_buffer))
365         ||
366         ((p_buffers->p_tx_buffer != NULL)
367          && !nrfx_is_in_ram(p_buffers->p_tx_buffer)))
368     {
369         err_code = NRFX_ERROR_INVALID_ADDR;
370         NRFX_LOG_WARNING("Function: %s, error code: %s.",
371                          __func__,
372                          NRFX_LOG_ERROR_STRING_GET(err_code));
373         return err_code;
374     }
375 
376     if (m_cb.use_tx)
377     {
378         NRFX_ASSERT(p_buffers->p_tx_buffer != NULL);
379         nrf_i2s_tx_buffer_set(NRF_I2S0, p_buffers->p_tx_buffer);
380     }
381     if (m_cb.use_rx)
382     {
383         NRFX_ASSERT(p_buffers->p_rx_buffer != NULL);
384         nrf_i2s_rx_buffer_set(NRF_I2S0, p_buffers->p_rx_buffer);
385     }
386 
387     m_cb.next_buffers   = *p_buffers;
388     m_cb.buffers_needed = false;
389 
390     return NRFX_SUCCESS;
391 }
392 
393 
nrfx_i2s_stop(void)394 void nrfx_i2s_stop(void)
395 {
396     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
397 
398     m_cb.buffers_needed = false;
399 
400     // First disable interrupts, then trigger the STOP task, so no spurious
401     // RXPTRUPD and TXPTRUPD events (see nRF52 anomaly 55) are processed.
402     nrf_i2s_int_disable(NRF_I2S0, NRF_I2S_INT_RXPTRUPD_MASK |
403                                   NRF_I2S_INT_TXPTRUPD_MASK);
404     nrf_i2s_task_trigger(NRF_I2S0, NRF_I2S_TASK_STOP);
405 
406 #if NRFX_CHECK(USE_WORKAROUND_FOR_I2S_STOP_ANOMALY)
407     *((volatile uint32_t *)(((uint32_t)NRF_I2S0) + 0x38)) = 1;
408     *((volatile uint32_t *)(((uint32_t)NRF_I2S0) + 0x3C)) = 1;
409 #endif
410 }
411 
412 
nrfx_i2s_irq_handler(void)413 void nrfx_i2s_irq_handler(void)
414 {
415     if (nrf_i2s_event_check(NRF_I2S0, NRF_I2S_EVENT_TXPTRUPD))
416     {
417         nrf_i2s_event_clear(NRF_I2S0, NRF_I2S_EVENT_TXPTRUPD);
418         m_cb.tx_ready = true;
419         if (m_cb.use_tx && m_cb.buffers_needed)
420         {
421             m_cb.buffers_reused = true;
422         }
423     }
424     if (nrf_i2s_event_check(NRF_I2S0, NRF_I2S_EVENT_RXPTRUPD))
425     {
426         nrf_i2s_event_clear(NRF_I2S0, NRF_I2S_EVENT_RXPTRUPD);
427         m_cb.rx_ready = true;
428         if (m_cb.use_rx && m_cb.buffers_needed)
429         {
430             m_cb.buffers_reused = true;
431         }
432     }
433 
434     if (nrf_i2s_event_check(NRF_I2S0, NRF_I2S_EVENT_STOPPED))
435     {
436         nrf_i2s_event_clear(NRF_I2S0, NRF_I2S_EVENT_STOPPED);
437         nrf_i2s_int_disable(NRF_I2S0, NRF_I2S_INT_STOPPED_MASK);
438         nrf_i2s_disable(NRF_I2S0);
439 
440         // When stopped, release all buffers, including these scheduled for
441         // the next part of the transfer, and signal that the transfer has
442         // finished.
443 
444         m_cb.handler(&m_cb.current_buffers, 0);
445 
446         // Change the state of the driver before calling the handler with
447         // the flag signaling that the transfer has finished, so that it is
448         // possible to start a new transfer directly from the handler function.
449         m_cb.state = NRFX_DRV_STATE_INITIALIZED;
450         NRFX_LOG_INFO("Stopped.");
451 
452         m_cb.handler(&m_cb.next_buffers, NRFX_I2S_STATUS_TRANSFER_STOPPED);
453     }
454     else
455     {
456         // Check if the requested transfer has been completed:
457         // - full-duplex mode
458         if ((m_cb.use_tx && m_cb.use_rx && m_cb.tx_ready && m_cb.rx_ready) ||
459             // - TX only mode
460             (!m_cb.use_rx && m_cb.tx_ready) ||
461             // - RX only mode
462             (!m_cb.use_tx && m_cb.rx_ready))
463         {
464             m_cb.tx_ready = false;
465             m_cb.rx_ready = false;
466 
467             // If the application did not supply the buffers for the next
468             // part of the transfer until this moment, the current buffers
469             // cannot be released, since the I2S peripheral already started
470             // using them. Signal this situation to the application by
471             // passing NULL instead of the structure with released buffers.
472             if (m_cb.buffers_reused)
473             {
474                 m_cb.buffers_reused = false;
475                 // This will most likely be set at this point. However, there is
476                 // a small time window between TXPTRUPD and RXPTRUPD events,
477                 // and it is theoretically possible that next buffers will be
478                 // set in this window, so to be sure this flag is set to true,
479                 // set it explicitly.
480                 m_cb.buffers_needed = true;
481                 m_cb.handler(NULL,
482                              NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED);
483             }
484             else
485             {
486                 // Buffers that have been used by the I2S peripheral (current)
487                 // are now released and will be returned to the application,
488                 // and the ones scheduled to be used as next become the current
489                 // ones.
490                 nrfx_i2s_buffers_t released_buffers = m_cb.current_buffers;
491                 m_cb.current_buffers = m_cb.next_buffers;
492                 m_cb.next_buffers.p_rx_buffer = NULL;
493                 m_cb.next_buffers.p_tx_buffer = NULL;
494                 m_cb.buffers_needed = true;
495                 m_cb.handler(&released_buffers,
496                              NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED);
497             }
498 
499         }
500     }
501 }
502 
503 #endif // NRFX_CHECK(NRFX_I2S_ENABLED)
504