1 /*
2  * Copyright (c) 2015 - 2023, 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 /** @brief I2S driver buffers structure. */
99 typedef nrfy_i2s_buffers_t nrfx_i2s_buffers_t;
100 
101 /** @brief I2S driver instance structure. */
102 typedef struct
103 {
104     NRF_I2S_Type  * p_reg;        ///< Pointer to a structure with I2S registers.
105     uint8_t         drv_inst_idx; ///< Index of the driver instance. For internal use only.
106 } nrfx_i2s_t;
107 
108 /** @brief Macro for creating an I2S driver instance. */
109 #define NRFX_I2S_INSTANCE(id)                               \
110 {                                                           \
111     .p_reg        = NRF_I2S##id ,                           \
112     .drv_inst_idx = NRFX_CONCAT_3(NRFX_I2S, id, _INST_IDX), \
113 }
114 
115 #ifndef __NRFX_DOXYGEN__
116 enum {
117     /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */
118     NRFX_INSTANCE_ENUM_LIST(I2S)
119     NRFX_I2S_ENABLED_COUNT
120 };
121 #endif
122 
123 /**
124  * @brief I2S driver default configuration.
125  *
126  * This configuration sets up I2S with the following options:
127  * - master mode
128  * - i2s data format
129  * - left alignment
130  * - sample width 16 bit
131  * - left channel enabled
132  * - MCK frequency 4 MHz
133  * - LRCK frequency 125 kHz
134  *
135  * @param[in] _pin_sck   SCK pin number.
136  * @param[in] _pin_lrck  LRCK pin number.
137  * @param[in] _pin_mck   MCK pin number.
138  * @param[in] _pin_sdout SDOUT pin number.
139  * @param[in] _pin_sdin  SDIN pin number.
140  */
141 #define NRFX_I2S_DEFAULT_CONFIG(_pin_sck, _pin_lrck, _pin_mck, _pin_sdout, _pin_sdin) \
142 {                                                                                     \
143     .sck_pin      = _pin_sck,                                                         \
144     .lrck_pin     = _pin_lrck,                                                        \
145     .mck_pin      = _pin_mck,                                                         \
146     .sdout_pin    = _pin_sdout,                                                       \
147     .sdin_pin     = _pin_sdin,                                                        \
148     .irq_priority = NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY,                             \
149     .mode         = NRF_I2S_MODE_MASTER,                                              \
150     .format       = NRF_I2S_FORMAT_I2S,                                               \
151     .alignment    = NRF_I2S_ALIGN_LEFT,                                               \
152     .sample_width = NRF_I2S_SWIDTH_16BIT,                                             \
153     .channels     = NRF_I2S_CHANNELS_LEFT,                                            \
154     .mck_setup    = NRF_I2S_MCK_32MDIV8,                                              \
155     .ratio        = NRF_I2S_RATIO_32X,                                                \
156     NRFX_COND_CODE_1(NRF_I2S_HAS_CLKCONFIG,                                           \
157                      (.clksrc = NRF_I2S_CLKSRC_PCLK32M,                               \
158                       .enable_bypass = false,),                                       \
159                      ())                                                              \
160 }
161 
162 #define NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED (1UL << 0)
163     /**< The application must provide buffers that are to be used in the next
164      *   part of the transfer. A call to @ref nrfx_i2s_next_buffers_set must
165      *   be done before the currently used buffers are completely processed
166      *   (that is, the time remaining for supplying the next buffers depends on
167      *   the used size of the buffers). */
168 
169 #define NRFX_I2S_STATUS_TRANSFER_STOPPED    (1UL << 1)
170     /**< The I2S peripheral has been stopped and all buffers that were passed
171      *   to the driver have been released. */
172 
173 /**
174  * @brief I2S driver data handler type.
175  *
176  * A data handling function of this type must be specified during the initialization
177  * of the driver. The driver will call this function when it finishes using
178  * buffers passed to it by the application, and when it needs to be provided
179  * with buffers for the next part of the transfer.
180  *
181  * @note The @c p_released pointer passed to this function is temporary and
182  *       will be invalid after the function returns, hence it cannot be stored
183  *       and used later. If needed, the pointed content (that is, buffers pointers)
184  *       must be copied instead.
185  *
186  * @param[in] p_released  Pointer to a structure with pointers to buffers
187  *                        passed previously to the driver that will no longer
188  *                        be accessed by it (they can be now safely released or
189  *                        used for another purpose, in particular for a next
190  *                        part of the transfer).
191  *                        This pointer will be NULL if the application did not
192  *                        supply the buffers for the next part of the transfer
193  *                        (via a call to @ref nrfx_i2s_next_buffers_set) since
194  *                        the previous time the data handler signaled such need.
195  *                        This means that data corruption occurred (the previous
196  *                        buffers are used for the second time) and no buffers
197  *                        can be released at the moment.
198  *                        Both pointers in this structure are NULL when the
199  *                        handler is called for the first time after a transfer
200  *                        is started, because no data has been transferred yet
201  *                        at this point. In all successive calls, the pointers
202  *                        specify what has been sent (TX) and what has been
203  *                        received (RX) in the part of the transfer that has
204  *                        just been completed (provided that a given direction
205  *                        is enabled, see @ref nrfx_i2s_start).
206  *                        @note Since the peripheral is stopped asynchronously,
207  *                              buffers that are released after the call to
208  *                              @ref nrfx_i2s_stop are not used entirely.
209  *                              In this case, only a part (if any) of the TX
210  *                              buffer has been actually transmitted and only
211  *                              a part (if any) of the RX buffer is filled with
212  *                              received data.
213  * @param[in] status  Bit field describing the current status of the transfer.
214  *                    It can be 0 or a combination of the following flags:
215  *                    - @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED
216  *                    - @ref NRFX_I2S_STATUS_TRANSFER_STOPPED
217  */
218 typedef void (* nrfx_i2s_data_handler_t)(nrfx_i2s_buffers_t const * p_released,
219                                          uint32_t                   status);
220 
221 /**
222  * @brief Function for initializing the I2S driver.
223  *
224  * @param[in] p_instance Pointer to the driver instance structure.
225  * @param[in] p_config   Pointer to the structure with the initial configuration.
226  * @param[in] handler    Data handler provided by the user. Must not be NULL.
227  *
228  * @retval NRFX_SUCCESS             Initialization was successful.
229  * @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
230  * @retval NRFX_ERROR_INVALID_PARAM The requested combination of configuration
231  *                                  options is not allowed by the I2S peripheral.
232  */
233 nrfx_err_t nrfx_i2s_init(nrfx_i2s_t const *        p_instance,
234                          nrfx_i2s_config_t const * p_config,
235                          nrfx_i2s_data_handler_t   handler);
236 
237 /**
238  * @brief Function for uninitializing the I2S driver.
239  *
240  * @param[in] p_instance Pointer to the driver instance structure.
241  */
242 void nrfx_i2s_uninit(nrfx_i2s_t const * p_instance);
243 
244 /**
245  * @brief Function for starting the continuous I2S transfer.
246  *
247  * The I2S data transfer can be performed in one of three modes: RX (reception)
248  * only, TX (transmission) only, or in both directions simultaneously.
249  * The mode is selected by specifying a proper buffer for a given direction
250  * in the call to this function or by passing NULL instead if this direction
251  * is to be disabled.
252  *
253  * The length of the buffer (which is a common value for RX and TX if both
254  * directions are enabled) is specified in 32-bit words. One 32-bit memory
255  * word can either contain four 8-bit samples, two 16-bit samples, or one
256  * right-aligned 24-bit sample sign-extended to a 32-bit value.
257  * For a detailed memory mapping for different supported configurations,
258  * see the Product Specification.
259  *
260  * @note Peripherals using EasyDMA (including I2S) require the transfer buffers
261  *       to be placed in the Data RAM region. If this condition is not met,
262  *       this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
263  *
264  * @param[in] p_instance        Pointer to the driver instance structure.
265  * @param[in] p_initial_buffers Pointer to a structure specifying the buffers
266  *                              to be used in the initial part of the transfer
267  *                              (buffers for all consecutive parts are provided
268  *                              through the data handler).
269  * @param[in] buffer_size       Size of the buffers (in 32-bit words).
270  *                              Must not be 0.
271  * @param[in] flags             Transfer options (0 for default settings).
272  *                              Currently, no additional flags are available.
273  *
274  * @retval NRFX_SUCCESS             The operation was successful.
275  * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or
276  *                                  the driver has not been initialized.
277  * @retval NRFX_ERROR_INVALID_ADDR  The provided buffers are not placed
278  *                                  in the Data RAM region.
279  */
280 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const *         p_instance,
281                           nrfx_i2s_buffers_t const * p_initial_buffers,
282                           uint16_t                   buffer_size,
283                           uint8_t                    flags);
284 
285 /**
286  * @brief Function for supplying the buffers to be used in the next part of
287  *        the transfer.
288  *
289  * The application must call this function when the data handler receives
290  * @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED in the @c status parameter.
291  * The call can be done immediately from the data handler function or later,
292  * but it has to be done before the I2S peripheral finishes processing the
293  * buffers supplied previously. Otherwise, data corruption will occur.
294  *
295  * @param[in] p_instance Pointer to the driver instance structure.
296  * @param[in] p_buffers  Pointer to a structure specifying the buffers
297  *                       to be used in the upcoming part of the transfer.
298  *
299  * @retval NRFX_SUCCESS             If the operation was successful.
300  * @retval NRFX_ERROR_INVALID_STATE If the buffers were already supplied or
301  *                                  the peripheral is currently being stopped.
302  *
303  * @sa nrfx_i2s_data_handler_t
304  */
305 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_t const *         p_instance,
306                                      nrfx_i2s_buffers_t const * p_buffers);
307 
308 /**
309  * @brief Function for stopping the I2S transfer.
310  *
311  * @param[in] p_instance Pointer to the driver instance structure.
312  */
313 void nrfx_i2s_stop(nrfx_i2s_t const * p_instance);
314 
315 /** @} */
316 
317 /*
318  * Declare interrupt handlers for all enabled driver instances in the following format:
319  * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_i2s_0_irq_handler).
320  *
321  * A specific interrupt handler for the driver instance can be retrieved by using
322  * the NRFX_I2S_INST_HANDLER_GET macro.
323  *
324  * Here is a sample of using the NRFX_I2S_INST_HANDLER_GET macro to directly map
325  * an interrupt handler in a Zephyr application:
326  *
327  * IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_I2S_INST_GET(\<instance_index\>)), \<priority\>,
328  *                    NRFX_I2S_INST_HANDLER_GET(\<instance_index\>), 0);
329  */
330 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(I2S, i2s)
331 
332 #ifdef __cplusplus
333 }
334 #endif
335 
336 #endif // NRFX_I2S_H__
337 
338