i2s.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /**
  2. * @file i2s.c
  3. * @brief Inter-Integrated Sound (I2S) driver implementation.
  4. */
  5. /* ****************************************************************************
  6. * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a
  9. * copy of this software and associated documentation files (the "Software"),
  10. * to deal in the Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. * and/or sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included
  16. * in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  21. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
  22. * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  23. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24. * OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. * Except as contained in this notice, the name of Maxim Integrated
  27. * Products, Inc. shall not be used except as stated in the Maxim Integrated
  28. * Products, Inc. Branding Policy.
  29. *
  30. * The mere transfer of this software does not imply any licenses
  31. * of trade secrets, proprietary technology, copyrights, patents,
  32. * trademarks, maskwork rights, or any other form of intellectual
  33. * property whatsoever. Maxim Integrated Products, Inc. retains all
  34. * ownership rights.
  35. *
  36. * $Date: 2018-12-18 15:37:22 -0600 (Tue, 18 Dec 2018) $
  37. * $Revision: 40072 $
  38. *
  39. *************************************************************************** */
  40. #include <stddef.h>
  41. #include <stdint.h>
  42. #include "mxc_config.h"
  43. #include "mxc_assert.h"
  44. #include "mxc_lock.h"
  45. #include "mxc_sys.h"
  46. #include "dma.h"
  47. #include "i2s.h"
  48. #define I2S_CHANNELS 2
  49. #define I2S_WIDTH 16
  50. int dma_channel = -1;
  51. int I2S_Init(const i2s_cfg_t *cfg, void (*dma_ctz_cb)(int, int), const sys_cfg_i2s_t* sys_cfg_i2s)
  52. {
  53. unsigned int i2s_clk, baud;
  54. uint16_t clocks;
  55. uint8_t ctz_en;
  56. int err;
  57. SYS_I2S_Init(sys_cfg_i2s);
  58. /* Setup SPI_MSS as master, mode 0, 16 bit transfers as I2S Requires */
  59. MXC_SPIMSS->ctrl = MXC_F_SPIMSS_CTRL_MMEN;
  60. MXC_SPIMSS->mod = MXC_V_SPIMSS_MOD_NUMBITS_BITS16 | MXC_F_SPIMSS_MOD_SSIO;
  61. MXC_SPIMSS->dma = MXC_S_SPIMSS_DMA_TX_FIFO_LEVEL_ENTRIES8;
  62. /* Setup I2S register from i2s_cfg_t */
  63. MXC_SPIMSS->i2s_ctrl = cfg->left_justify << MXC_F_SPIMSS_I2S_CTRL_I2S_LJ_POS |
  64. cfg->mono_audio << MXC_F_SPIMSS_I2S_CTRL_I2S_MONO_POS;
  65. /* Determine divisor for baud rate generator */
  66. baud = cfg->sample_rate*I2S_CHANNELS*I2S_WIDTH;
  67. i2s_clk = SYS_I2S_GetFreq(MXC_SPIMSS);
  68. if (i2s_clk/4 < baud) {
  69. return E_BAD_PARAM;
  70. }
  71. clocks = i2s_clk / (2*baud);
  72. MXC_SPIMSS->brg = clocks;
  73. /* Prepare SPIMSS DMA register for DMA setup */
  74. if (dma_ctz_cb == NULL) {
  75. ctz_en = 0;
  76. } else {
  77. ctz_en = 1;
  78. }
  79. /* Initialize DMA */
  80. if (cfg->audio_direction % 2) {
  81. MXC_SPIMSS->dma |= MXC_F_SPIMSS_DMA_TX_DMA_EN | MXC_F_SPIMSS_DMA_TX_FIFO_CLEAR;
  82. if ((err = DMA_Init()) != E_NO_ERROR) {
  83. if (err != E_BAD_STATE) {
  84. return err;
  85. }
  86. }
  87. if ((err = DMA_AcquireChannel()) < 0) {
  88. return err;
  89. }
  90. dma_channel = err;
  91. DMA_ConfigChannel(dma_channel, DMA_PRIO_MEDHIGH,
  92. sys_cfg_i2s->dma_reqsel_tx, 1, DMA_TIMEOUT_512_CLK,
  93. DMA_PRESCALE_DIV64K, DMA_WIDTH_HALFWORD, 1,
  94. DMA_WIDTH_HALFWORD, 0, 16, 0, ctz_en);
  95. if (ctz_en) {
  96. DMA_SetCallback(dma_channel, dma_ctz_cb);
  97. DMA_EnableInterrupt(dma_channel);
  98. }
  99. }
  100. if (cfg->audio_direction / 2) {
  101. MXC_SPIMSS->dma = MXC_F_SPIMSS_DMA_RX_DMA_EN | MXC_F_SPIMSS_DMA_RX_FIFO_CLEAR;
  102. if ((err = DMA_Init()) != E_NO_ERROR) {
  103. if (err != E_BAD_STATE) { //DMA already initialized
  104. return err;
  105. }
  106. }
  107. if ((err = DMA_AcquireChannel()) < 0) {
  108. return err;
  109. }
  110. dma_channel = err;
  111. DMA_ConfigChannel(dma_channel, DMA_PRIO_MEDHIGH,
  112. sys_cfg_i2s->dma_reqsel_rx, 1, DMA_TIMEOUT_512_CLK,
  113. DMA_PRESCALE_DIV64K, DMA_WIDTH_HALFWORD, 0,
  114. DMA_WIDTH_HALFWORD, 1, 8, 0, ctz_en);
  115. if (ctz_en) {
  116. DMA_SetCallback(dma_channel, dma_ctz_cb);
  117. DMA_EnableInterrupt(dma_channel);
  118. }
  119. }
  120. I2S_DMA_SetAddrCnt(cfg->dma_src_addr, cfg->dma_dst_addr, cfg->dma_cnt);
  121. if (cfg->dma_reload_en) {
  122. I2S_DMA_SetReload(cfg->dma_src_addr, cfg->dma_dst_addr, cfg->dma_cnt);
  123. }
  124. if (cfg->start_immediately) {
  125. return I2S_Start();
  126. }
  127. return E_NO_ERROR;
  128. }
  129. int I2S_Shutdown(void)
  130. {
  131. MXC_SPIMSS->ctrl = 0;
  132. MXC_SPIMSS->i2s_ctrl = 0;
  133. MXC_SPIMSS->brg = 0;
  134. MXC_SPIMSS->mod = 0;
  135. MXC_SPIMSS->dma = 0;
  136. SYS_I2S_Shutdown();
  137. return DMA_ReleaseChannel(dma_channel);
  138. }
  139. int I2S_Mute(void)
  140. {
  141. MXC_SPIMSS->i2s_ctrl |= MXC_F_SPIMSS_I2S_CTRL_I2S_MUTE;
  142. return E_NO_ERROR;
  143. }
  144. int I2S_Unmute(void)
  145. {
  146. MXC_SPIMSS->i2s_ctrl &= ~MXC_F_SPIMSS_I2S_CTRL_I2S_MUTE;
  147. return E_NO_ERROR;
  148. }
  149. int I2S_Pause(void)
  150. {
  151. MXC_SPIMSS->i2s_ctrl |= MXC_F_SPIMSS_I2S_CTRL_I2S_PAUSE;
  152. return E_NO_ERROR;
  153. }
  154. int I2S_Unpause(void)
  155. {
  156. MXC_SPIMSS->i2s_ctrl &= ~MXC_F_SPIMSS_I2S_CTRL_I2S_PAUSE;
  157. return E_NO_ERROR;
  158. }
  159. int I2S_Stop(void)
  160. {
  161. MXC_SPIMSS->ctrl &= ~MXC_F_SPIMSS_CTRL_SPIEN;
  162. MXC_SPIMSS->i2s_ctrl &= ~MXC_F_SPIMSS_I2S_CTRL_I2S_EN;
  163. return DMA_Stop(dma_channel);
  164. }
  165. int I2S_Start(void)
  166. {
  167. MXC_SPIMSS->ctrl |= MXC_F_SPIMSS_CTRL_SPIEN;
  168. MXC_SPIMSS->i2s_ctrl |= MXC_F_SPIMSS_I2S_CTRL_I2S_EN;
  169. return DMA_Start(dma_channel);
  170. }
  171. int I2S_DMA_ClearFlags(void)
  172. {
  173. return DMA_ClearFlags(dma_channel);
  174. }
  175. int I2S_DMA_SetAddrCnt(void *src_addr, void *dst_addr, unsigned int count)
  176. {
  177. return DMA_SetSrcDstCnt(dma_channel, src_addr, dst_addr, count);
  178. }
  179. int I2S_DMA_SetReload(void *src_addr, void *dst_addr, unsigned int count)
  180. {
  181. return DMA_SetReload(dma_channel, src_addr, dst_addr, count);
  182. }