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 #ifndef NRFX_I2S_H__
35 #define NRFX_I2S_H__
36 
37 #include <nrfx.h>
38 #include <haly/nrfy_i2s.h>
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /* On devices with single instance (with no id) use instance 0. */
45 #if defined(NRF_I2S) && defined(NRFX_I2S_ENABLED) && !defined(NRFX_I2S0_ENABLED)
46 #define NRFX_I2S0_ENABLED 1
47 #endif
48 
49 /**
50  * @defgroup nrfx_i2s I2S driver
51  * @{
52  * @ingroup nrf_i2s
53  * @brief   Inter-IC Sound (I2S) peripheral driver.
54  */
55 
56 /** @brief I2S driver configuration structure. */
57 typedef struct
58 {
59     uint32_t           sck_pin;       ///< SCK pin number.
60     uint32_t           lrck_pin;      ///< LRCK pin number.
61     uint32_t           mck_pin;       ///< MCK pin number.
62                                       /**< Optional. Use @ref NRF_I2S_PIN_NOT_CONNECTED
63                                        *   if this signal is not needed. */
64     uint32_t           sdout_pin;     ///< SDOUT pin number.
65                                       /**< Optional. Use @ref NRF_I2S_PIN_NOT_CONNECTED
66                                        *   if this signal is not needed. */
67     uint32_t           sdin_pin;      ///< SDIN pin number.
68                                       /**< Optional. Use @ref NRF_I2S_PIN_NOT_CONNECTED
69                                        *   if this signal is not needed. */
70     uint8_t            irq_priority;  ///< Interrupt priority.
71     nrf_i2s_mode_t     mode;          ///< Mode of operation (master or slave).
72     nrf_i2s_format_t   format;        ///< I2S frame format.
73     nrf_i2s_align_t    alignment;     ///< Alignment of sample within a frame.
74     nrf_i2s_swidth_t   sample_width;  ///< Sample width.
75     nrf_i2s_channels_t channels;      ///< Enabled channels.
76     nrf_i2s_mck_t      mck_setup;     ///< Master clock generator setup.
77     nrf_i2s_ratio_t    ratio;         ///< MCK/LRCK ratio.
78 #if NRF_I2S_HAS_CLKCONFIG
79     nrf_i2s_clksrc_t   clksrc;        ///< Clock source selection.
80     bool               enable_bypass; ///< Bypass clock generator. MCK will be equal to source input.
81 #endif
82     bool               skip_gpio_cfg; ///< Skip GPIO configuration of pins.
83                                       /**< When set to true, the driver does not modify
84                                        *   any GPIO parameters of the used pins. Those
85                                        *   parameters are supposed to be configured
86                                        *   externally before the driver is initialized. */
87     bool               skip_psel_cfg; ///< Skip pin selection configuration.
88                                       /**< When set to true, the driver does not modify
89                                        *   pin select registers in the peripheral.
90                                        *   Those registers are supposed to be set up
91                                        *   externally before the driver is initialized.
92                                        *   @note When both GPIO configuration and pin
93                                        *   selection are to be skipped, the structure
94                                        *   fields that specify pins can be omitted,
95                                        *   as they are ignored anyway. */
96 } nrfx_i2s_config_t;
97 
98 #if NRFX_API_VER_AT_LEAST(3, 3, 0) || defined(__NRFX_DOXYGEN__)
99 /** @brief I2S driver buffers structure. */
100 typedef nrfy_i2s_xfer_desc_t nrfx_i2s_buffers_t;
101 #else
102 typedef nrfy_i2s_buffers_t nrfx_i2s_buffers_t;
103 #endif
104 
105 /** @brief I2S driver instance structure. */
106 typedef struct
107 {
108     NRF_I2S_Type  * p_reg;        ///< Pointer to a structure with I2S registers.
109     uint8_t         drv_inst_idx; ///< Index of the driver instance. For internal use only.
110 } nrfx_i2s_t;
111 
112 /** @brief Macro for creating an I2S driver instance. */
113 #define NRFX_I2S_INSTANCE(id)                               \
114 {                                                           \
115     .p_reg        = NRFX_CONCAT(NRF_, I2S, id),             \
116     .drv_inst_idx = NRFX_CONCAT(NRFX_I2S, id, _INST_IDX),   \
117 }
118 
119 #ifndef __NRFX_DOXYGEN__
120 enum {
121     /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */
122     NRFX_INSTANCE_ENUM_LIST(I2S)
123     NRFX_I2S_ENABLED_COUNT
124 };
125 #endif
126 
127 /**
128  * @brief I2S driver default configuration.
129  *
130  * This configuration sets up I2S with the following options:
131  * - master mode
132  * - i2s data format
133  * - left alignment
134  * - sample width 16 bit
135  * - left channel enabled
136  * - MCK frequency 4 MHz
137  * - LRCK frequency 125 kHz
138  *
139  * @param[in] _pin_sck   SCK pin number.
140  * @param[in] _pin_lrck  LRCK pin number.
141  * @param[in] _pin_mck   MCK pin number.
142  * @param[in] _pin_sdout SDOUT pin number.
143  * @param[in] _pin_sdin  SDIN pin number.
144  */
145 #define NRFX_I2S_DEFAULT_CONFIG(_pin_sck, _pin_lrck, _pin_mck, _pin_sdout, _pin_sdin) \
146 {                                                                                     \
147     .sck_pin      = _pin_sck,                                                         \
148     .lrck_pin     = _pin_lrck,                                                        \
149     .mck_pin      = _pin_mck,                                                         \
150     .sdout_pin    = _pin_sdout,                                                       \
151     .sdin_pin     = _pin_sdin,                                                        \
152     .irq_priority = NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY,                             \
153     .mode         = NRF_I2S_MODE_MASTER,                                              \
154     .format       = NRF_I2S_FORMAT_I2S,                                               \
155     .alignment    = NRF_I2S_ALIGN_LEFT,                                               \
156     .sample_width = NRF_I2S_SWIDTH_16BIT,                                             \
157     .channels     = NRF_I2S_CHANNELS_LEFT,                                            \
158     .mck_setup    = NRF_I2S_MCK_32MDIV8,                                              \
159     .ratio        = NRF_I2S_RATIO_32X,                                                \
160     NRFX_COND_CODE_1(NRF_I2S_HAS_CLKCONFIG,                                           \
161                      (.clksrc = NRF_I2S_CLKSRC_PCLK32M,                               \
162                       .enable_bypass = false,),                                       \
163                      ())                                                              \
164 }
165 
166 #define NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED (1UL << 0)
167     /**< The application must provide buffers that are to be used in the next
168      *   part of the transfer. A call to @ref nrfx_i2s_next_buffers_set must
169      *   be done before the currently used buffers are completely processed
170      *   (that is, the time remaining for supplying the next buffers depends on
171      *   the used size of the buffers). */
172 
173 #define NRFX_I2S_STATUS_TRANSFER_STOPPED    (1UL << 1)
174     /**< The I2S peripheral has been stopped and all buffers that were passed
175      *   to the driver have been released. */
176 
177 /**
178  * @brief I2S driver data handler type.
179  *
180  * A data handling function of this type must be specified during the initialization
181  * of the driver. The driver will call this function when it finishes using
182  * buffers passed to it by the application, and when it needs to be provided
183  * with buffers for the next part of the transfer.
184  *
185  * @note The @c p_released pointer passed to this function is temporary and
186  *       will be invalid after the function returns, hence it cannot be stored
187  *       and used later. If needed, the pointed content (that is, buffers pointers)
188  *       must be copied instead.
189  *
190  * @param[in] p_released  Pointer to a structure with pointers to buffers
191  *                        passed previously to the driver that will no longer
192  *                        be accessed by it (they can be now safely released or
193  *                        used for another purpose, in particular for a next
194  *                        part of the transfer).
195  *                        This pointer will be NULL if the application did not
196  *                        supply the buffers for the next part of the transfer
197  *                        (via a call to @ref nrfx_i2s_next_buffers_set) since
198  *                        the previous time the data handler signaled such need.
199  *                        This means that data corruption occurred (the previous
200  *                        buffers are used for the second time) and no buffers
201  *                        can be released at the moment.
202  *                        Both pointers in this structure are NULL when the
203  *                        handler is called for the first time after a transfer
204  *                        is started, because no data has been transferred yet
205  *                        at this point. In all successive calls, the pointers
206  *                        specify what has been sent (TX) and what has been
207  *                        received (RX) in the part of the transfer that has
208  *                        just been completed (provided that a given direction
209  *                        is enabled, see @ref nrfx_i2s_start).
210  *                        @note Since the peripheral is stopped asynchronously,
211  *                              buffers that are released after the call to
212  *                              @ref nrfx_i2s_stop are not used entirely.
213  *                              In this case, only a part (if any) of the TX
214  *                              buffer has been actually transmitted and only
215  *                              a part (if any) of the RX buffer is filled with
216  *                              received data.
217  * @param[in] status  Bit field describing the current status of the transfer.
218  *                    It can be 0 or a combination of the following flags:
219  *                    - @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED
220  *                    - @ref NRFX_I2S_STATUS_TRANSFER_STOPPED
221  */
222 typedef void (* nrfx_i2s_data_handler_t)(nrfx_i2s_buffers_t const * p_released,
223                                          uint32_t                   status);
224 
225 /**
226  * @brief Function for initializing the I2S driver.
227  *
228  * @param[in] p_instance Pointer to the driver instance structure.
229  * @param[in] p_config   Pointer to the structure with the initial configuration.
230  * @param[in] handler    Data handler provided by the user. Must not be NULL.
231  *
232  * @retval NRFX_SUCCESS             Initialization was successful.
233  * @retval NRFX_ERROR_ALREADY       The driver is already initialized.
234  * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
235  *                                  Deprecated - use @ref NRFX_ERROR_ALREADY instead.
236  * @retval NRFX_ERROR_INVALID_PARAM The requested combination of configuration
237  *                                  options is not allowed by the I2S peripheral.
238  */
239 nrfx_err_t nrfx_i2s_init(nrfx_i2s_t const *        p_instance,
240                          nrfx_i2s_config_t const * p_config,
241                          nrfx_i2s_data_handler_t   handler);
242 
243 /**
244  * @brief Function for uninitializing the I2S driver.
245  *
246  * @param[in] p_instance Pointer to the driver instance structure.
247  */
248 void nrfx_i2s_uninit(nrfx_i2s_t const * p_instance);
249 
250 /**
251  * @brief Function for checking if the I2S driver instance is initialized.
252  *
253  * @param[in] p_instance Pointer to the driver instance structure.
254  *
255  * @retval true  Instance is already initialized.
256  * @retval false Instance is not initialized.
257  */
258 bool nrfx_i2s_init_check(nrfx_i2s_t const * p_instance);
259 
260 #if NRFX_API_VER_AT_LEAST(3, 3, 0) || defined(__NRFX_DOXYGEN__)
261 /**
262  * @brief Function for starting the continuous I2S transfer.
263  *
264  * The I2S data transfer can be performed in one of three modes: RX (reception)
265  * only, TX (transmission) only, or in both directions simultaneously.
266  * The mode is selected by specifying a proper buffer for a given direction
267  * in the call to this function or by passing NULL instead if this direction
268  * is to be disabled.
269  *
270  * The length of the buffer (which is a common value for RX and TX if both
271  * directions are enabled) is specified in 32-bit words. One 32-bit memory
272  * word can either contain four 8-bit samples, two 16-bit samples, or one
273  * right-aligned 24-bit sample sign-extended to a 32-bit value.
274  * For a detailed memory mapping for different supported configurations,
275  * see the Product Specification.
276  *
277  * @note Peripherals using EasyDMA (including I2S) require the transfer buffers
278  *       to be placed in the Data RAM region. If this condition is not met,
279  *       this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
280  *
281  * @param[in] p_instance        Pointer to the driver instance structure.
282  * @param[in] p_initial_buffers Pointer to a structure specifying the buffers
283  *                              to be used in the initial part of the transfer
284  *                              (buffers for all consecutive parts are provided
285  *                              through the data handler).
286  * @param[in] flags             Transfer options (0 for default settings).
287  *                              Currently, no additional flags are available.
288  *
289  * @retval NRFX_SUCCESS             The operation was successful.
290  * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or
291  *                                  the driver has not been initialized.
292  * @retval NRFX_ERROR_INVALID_ADDR  The provided buffers are not placed
293  *                                  in the Data RAM region.
294  */
295 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const *         p_instance,
296                           nrfx_i2s_buffers_t const * p_initial_buffers,
297                           uint8_t                    flags);
298 #else
299 /**
300  * @brief Function for starting the continuous I2S transfer.
301  *
302  * The I2S data transfer can be performed in one of three modes: RX (reception)
303  * only, TX (transmission) only, or in both directions simultaneously.
304  * The mode is selected by specifying a proper buffer for a given direction
305  * in the call to this function or by passing NULL instead if this direction
306  * is to be disabled.
307  *
308  * The length of the buffer (which is a common value for RX and TX if both
309  * directions are enabled) is specified in 32-bit words. One 32-bit memory
310  * word can either contain four 8-bit samples, two 16-bit samples, or one
311  * right-aligned 24-bit sample sign-extended to a 32-bit value.
312  * For a detailed memory mapping for different supported configurations,
313  * see the Product Specification.
314  *
315  * @note Peripherals using EasyDMA (including I2S) require the transfer buffers
316  *       to be placed in the Data RAM region. If this condition is not met,
317  *       this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
318  *
319  * @param[in] p_instance        Pointer to the driver instance structure.
320  * @param[in] p_initial_buffers Pointer to a structure specifying the buffers
321  *                              to be used in the initial part of the transfer
322  *                              (buffers for all consecutive parts are provided
323  *                              through the data handler).
324  * @param[in] buffer_size       Size of the buffers (in 32-bit words).
325  *                              Must not be 0.
326  * @param[in] flags             Transfer options (0 for default settings).
327  *                              Currently, no additional flags are available.
328  *
329  * @retval NRFX_SUCCESS             The operation was successful.
330  * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or
331  *                                  the driver has not been initialized.
332  * @retval NRFX_ERROR_INVALID_ADDR  The provided buffers are not placed
333  *                                  in the Data RAM region.
334  */
335 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const *         p_instance,
336                           nrfx_i2s_buffers_t const * p_initial_buffers,
337                           uint16_t                   buffer_size,
338                           uint8_t                    flags);
339 #endif
340 
341 /**
342  * @brief Function for supplying the buffers to be used in the next part of
343  *        the transfer.
344  *
345  * The application must call this function when the data handler receives
346  * @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED in the @c status parameter.
347  * The call can be done immediately from the data handler function or later,
348  * but it has to be done before the I2S peripheral finishes processing the
349  * buffers supplied previously. Otherwise, data corruption will occur.
350  *
351  * @param[in] p_instance Pointer to the driver instance structure.
352  * @param[in] p_buffers  Pointer to a structure specifying the buffers
353  *                       to be used in the upcoming part of the transfer.
354  *
355  * @retval NRFX_SUCCESS             If the operation was successful.
356  * @retval NRFX_ERROR_INVALID_STATE If the buffers were already supplied or
357  *                                  the peripheral is currently being stopped.
358  *
359  * @sa nrfx_i2s_data_handler_t
360  */
361 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_t const *         p_instance,
362                                      nrfx_i2s_buffers_t const * p_buffers);
363 
364 /**
365  * @brief Function for stopping the I2S transfer.
366  *
367  * @param[in] p_instance Pointer to the driver instance structure.
368  */
369 void nrfx_i2s_stop(nrfx_i2s_t const * p_instance);
370 
371 /** @} */
372 
373 /*
374  * Declare interrupt handlers for all enabled driver instances in the following format:
375  * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_i2s_0_irq_handler).
376  *
377  * A specific interrupt handler for the driver instance can be retrieved by using
378  * the NRFX_I2S_INST_HANDLER_GET macro.
379  *
380  * Here is a sample of using the NRFX_I2S_INST_HANDLER_GET macro to map an interrupt handler
381  * in a Zephyr application:
382  *
383  * IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_I2S_INST_GET(\<instance_index\>)), \<priority\>,
384  *             NRFX_I2S_INST_HANDLER_GET(\<instance_index\>), 0, 0);
385  */
386 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(I2S, i2s)
387 
388 #ifdef __cplusplus
389 }
390 #endif
391 
392 #endif // NRFX_I2S_H__
393 
394