drv_sound.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-11-17 LiWeiHao First implementation
  9. */
  10. #include "drv_sound.h"
  11. #include "fsl_common.h"
  12. #include "fsl_iocon.h"
  13. #include "fsl_dma.h"
  14. #include "fsl_i2s.h"
  15. #include "fsl_i2s_dma.h"
  16. #include "fsl_wm8904.h"
  17. #include "fsl_i2c.h"
  18. #define TX_FIFO_SIZE (4096)
  19. #define I2S_TX I2S1
  20. #define I2S_RX I2S0
  21. #define I2S_DMA_TX 15
  22. #define I2S_DMA_RX 12
  23. #ifndef CODEC_I2C_NAME
  24. #define CODEC_I2C_NAME "i2c4"
  25. #endif
  26. struct sound_device
  27. {
  28. wm8904_handle_t wm8904_handle;
  29. dma_handle_t tx_dma_handle;
  30. i2s_dma_handle_t tx_i2s_dma_handle;
  31. struct rt_audio_device audio;
  32. struct rt_audio_configure replay_config;
  33. rt_uint8_t volume;
  34. rt_uint8_t *tx_fifo;
  35. };
  36. const pll_setup_t pll_setup =
  37. {
  38. .syspllctrl = SYSCON_SYSPLLCTRL_BANDSEL_MASK | SYSCON_SYSPLLCTRL_SELP(0x1FU) | SYSCON_SYSPLLCTRL_SELI(0x8U),
  39. .syspllndec = SYSCON_SYSPLLNDEC_NDEC(0x2DU),
  40. .syspllpdec = SYSCON_SYSPLLPDEC_PDEC(0x42U),
  41. .syspllssctrl = {SYSCON_SYSPLLSSCTRL0_MDEC(0x34D3U) | SYSCON_SYSPLLSSCTRL0_SEL_EXT_MASK, 0x00000000U},
  42. .pllRate = 24576000U, /* 16 bits * 2 channels * 44.1 kHz * 16 */
  43. .flags = PLL_SETUPFLAG_WAITLOCK
  44. };
  45. static struct sound_device snd_dev;
  46. void i2s_tx_transfer_callback(I2S_Type *base,
  47. i2s_dma_handle_t *handle,
  48. status_t completionStatus,
  49. void *userData)
  50. {
  51. struct sound_device *snd_dev = (struct sound_device *)userData;
  52. rt_audio_tx_complete(&snd_dev->audio);
  53. }
  54. static rt_err_t lpc_audio_init(struct rt_audio_device *audio)
  55. {
  56. i2s_config_t tx_i2s_config;
  57. wm8904_config_t wm8904_config;
  58. CLOCK_EnableClock(kCLOCK_Iocon);
  59. CLOCK_EnableClock(kCLOCK_InputMux);
  60. CLOCK_EnableClock(kCLOCK_Gpio0);
  61. CLOCK_EnableClock(kCLOCK_Gpio1);
  62. CLOCK_AttachClk(kFRO12M_to_SYS_PLL);
  63. CLOCK_AttachClk(kSYS_PLL_to_FLEXCOMM7);
  64. RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
  65. CLOCK_SetPLLFreq(&pll_setup);
  66. CLOCK_AttachClk(kSYS_PLL_to_MCLK);
  67. SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U);
  68. // Flexcomm 7 I2S Tx
  69. IOCON_PinMuxSet(IOCON, 1, 12, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / SCK */
  70. IOCON_PinMuxSet(IOCON, 1, 13, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / SDA */
  71. IOCON_PinMuxSet(IOCON, 1, 14, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / WS */
  72. /* MCLK output for I2S */
  73. IOCON_PinMuxSet(IOCON, 1, 17, IOCON_FUNC4 | IOCON_MODE_INACT | IOCON_DIGITAL_EN);
  74. SYSCON->MCLKIO = 1U;
  75. WM8904_GetDefaultConfig(&wm8904_config);
  76. snd_dev.wm8904_handle.i2c = (struct rt_i2c_bus_device *)rt_device_find(CODEC_I2C_NAME);
  77. if (WM8904_Init(&snd_dev.wm8904_handle, &wm8904_config) != kStatus_Success)
  78. {
  79. rt_kprintf("wm8904 init failed\n");
  80. return -RT_ERROR;
  81. }
  82. WM8904_SetMute(&snd_dev.wm8904_handle, RT_TRUE, RT_TRUE);
  83. I2S_TxGetDefaultConfig(&tx_i2s_config);
  84. tx_i2s_config.divider = CLOCK_GetPllOutFreq() / 48000U / 16 / 2;
  85. I2S_TxInit(I2S_TX, &tx_i2s_config);
  86. DMA_Init(DMA0);
  87. DMA_EnableChannel(DMA0, I2S_DMA_TX);
  88. DMA_SetChannelPriority(DMA0, I2S_DMA_TX, kDMA_ChannelPriority3);
  89. DMA_CreateHandle(&snd_dev.tx_dma_handle, DMA0, I2S_DMA_TX);
  90. I2S_TxTransferCreateHandleDMA(I2S_TX,
  91. &snd_dev.tx_i2s_dma_handle,
  92. &snd_dev.tx_dma_handle,
  93. i2s_tx_transfer_callback,
  94. (void *)&snd_dev);
  95. return RT_EOK;
  96. }
  97. static rt_err_t lpc_audio_start(struct rt_audio_device *audio, int stream)
  98. {
  99. RT_ASSERT(audio != RT_NULL);
  100. if (stream == AUDIO_STREAM_REPLAY)
  101. {
  102. struct rt_audio_caps caps;
  103. caps.main_type = AUDIO_TYPE_MIXER;
  104. caps.sub_type = AUDIO_MIXER_VOLUME;
  105. audio->ops->getcaps(audio, &caps);
  106. audio->ops->configure(audio, &caps);
  107. rt_audio_tx_complete(audio);
  108. }
  109. return RT_EOK;
  110. }
  111. static rt_err_t lpc_audio_stop(struct rt_audio_device *audio, int stream)
  112. {
  113. if (stream == AUDIO_STREAM_REPLAY)
  114. {
  115. WM8904_SetMute(&snd_dev.wm8904_handle, RT_TRUE, RT_TRUE);
  116. I2S_TransferAbortDMA(I2S_TX, &snd_dev.tx_i2s_dma_handle);
  117. }
  118. return RT_EOK;
  119. }
  120. static rt_err_t lpc_audio_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  121. {
  122. rt_err_t result = RT_EOK;
  123. struct sound_device *snd_dev;
  124. RT_ASSERT(audio != RT_NULL);
  125. snd_dev = (struct sound_device *)audio->parent.user_data;
  126. switch (caps->main_type)
  127. {
  128. case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */
  129. {
  130. switch (caps->sub_type)
  131. {
  132. case AUDIO_TYPE_QUERY:
  133. caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER;
  134. break;
  135. default:
  136. result = -RT_ERROR;
  137. break;
  138. }
  139. break;
  140. }
  141. case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
  142. {
  143. switch (caps->sub_type)
  144. {
  145. case AUDIO_DSP_PARAM:
  146. caps->udata.config.samplerate = snd_dev->replay_config.samplerate;
  147. caps->udata.config.channels = snd_dev->replay_config.channels;
  148. caps->udata.config.samplebits = snd_dev->replay_config.samplebits;
  149. break;
  150. case AUDIO_DSP_SAMPLERATE:
  151. caps->udata.config.samplerate = snd_dev->replay_config.samplerate;
  152. break;
  153. case AUDIO_DSP_CHANNELS:
  154. caps->udata.config.channels = snd_dev->replay_config.channels;
  155. break;
  156. case AUDIO_DSP_SAMPLEBITS:
  157. caps->udata.config.samplebits = snd_dev->replay_config.samplebits;
  158. break;
  159. default:
  160. result = -RT_ERROR;
  161. break;
  162. }
  163. break;
  164. }
  165. case AUDIO_TYPE_MIXER: /* report the Mixer Units */
  166. {
  167. switch (caps->sub_type)
  168. {
  169. case AUDIO_MIXER_QUERY:
  170. caps->udata.mask = AUDIO_MIXER_VOLUME;
  171. break;
  172. case AUDIO_MIXER_VOLUME:
  173. caps->udata.value = snd_dev->volume;
  174. break;
  175. default:
  176. result = -RT_ERROR;
  177. break;
  178. }
  179. break;
  180. }
  181. default:
  182. result = -RT_ERROR;
  183. break;
  184. }
  185. return result;
  186. }
  187. static rt_err_t lpc_audio_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  188. {
  189. rt_err_t result = RT_EOK;
  190. struct sound_device *snd_dev = audio->parent.user_data;
  191. switch (caps->main_type)
  192. {
  193. case AUDIO_TYPE_MIXER:
  194. {
  195. switch (caps->sub_type)
  196. {
  197. case AUDIO_MIXER_MUTE:
  198. {
  199. WM8904_SetMute(&snd_dev->wm8904_handle, RT_TRUE, RT_TRUE);
  200. snd_dev->volume = 0;
  201. break;
  202. }
  203. case AUDIO_MIXER_VOLUME:
  204. {
  205. int volume = caps->udata.value / 2;
  206. WM8904_SetMute(&snd_dev->wm8904_handle, RT_FALSE, RT_FALSE);
  207. WM8904_SetVolume(&snd_dev->wm8904_handle, volume, volume);
  208. snd_dev->volume = volume;
  209. break;
  210. }
  211. }
  212. break;
  213. }
  214. case AUDIO_TYPE_OUTPUT:
  215. {
  216. switch (caps->sub_type)
  217. {
  218. case AUDIO_DSP_PARAM:
  219. {
  220. struct rt_audio_configure config = caps->udata.config;
  221. i2s_config_t tx_i2s_config;
  222. snd_dev->replay_config.channels = config.channels;
  223. snd_dev->replay_config.samplebits = config.samplebits;
  224. snd_dev->replay_config.samplerate = config.samplerate;
  225. I2S_TxGetDefaultConfig(&tx_i2s_config);
  226. tx_i2s_config.divider = CLOCK_GetPllOutFreq() / config.samplerate / 16 / 2;
  227. I2S_TxInit(I2S_TX, &tx_i2s_config);
  228. break;
  229. }
  230. case AUDIO_DSP_SAMPLERATE:
  231. {
  232. struct rt_audio_configure config = caps->udata.config;
  233. i2s_config_t tx_i2s_config;
  234. snd_dev->replay_config.samplerate = config.samplerate;
  235. I2S_TxGetDefaultConfig(&tx_i2s_config);
  236. tx_i2s_config.divider = CLOCK_GetPllOutFreq() / config.samplerate / 16 / 2;
  237. I2S_TxInit(I2S_TX, &tx_i2s_config);
  238. break;
  239. }
  240. default:
  241. result = -RT_ERROR;
  242. break;
  243. }
  244. break;
  245. }
  246. }
  247. return result;
  248. }
  249. static rt_size_t lpc_audio_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size)
  250. {
  251. RT_ASSERT(audio != RT_NULL);
  252. i2s_transfer_t transfer;
  253. transfer.data = (uint8_t *)writeBuf;
  254. transfer.dataSize = size;
  255. I2S_TxTransferSendDMA(I2S_TX, &snd_dev.tx_i2s_dma_handle, transfer);
  256. return RT_EOK;
  257. }
  258. static void lpc_audio_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
  259. {
  260. RT_ASSERT(audio != RT_NULL);
  261. /**
  262. * TX_FIFO
  263. * +----------------+----------------+
  264. * | block1 | block2 |
  265. * +----------------+----------------+
  266. * \ block_size /
  267. */
  268. info->buffer = snd_dev.tx_fifo;
  269. info->total_size = TX_FIFO_SIZE;
  270. info->block_size = TX_FIFO_SIZE / 2;
  271. info->block_count = 2;
  272. }
  273. static struct rt_audio_ops audio_ops =
  274. {
  275. .getcaps = lpc_audio_getcaps,
  276. .configure = lpc_audio_configure,
  277. .init = lpc_audio_init,
  278. .start = lpc_audio_start,
  279. .stop = lpc_audio_stop,
  280. .transmit = lpc_audio_transmit,
  281. .buffer_info = lpc_audio_buffer_info,
  282. };
  283. int rt_hw_sound_init(void)
  284. {
  285. rt_uint8_t *tx_fifo = RT_NULL;
  286. tx_fifo = rt_malloc(TX_FIFO_SIZE);
  287. if (tx_fifo == NULL)
  288. {
  289. return -RT_ENOMEM;
  290. }
  291. snd_dev.tx_fifo = tx_fifo;
  292. /* init default configuration */
  293. {
  294. snd_dev.replay_config.samplerate = 44100;
  295. snd_dev.replay_config.channels = 2;
  296. snd_dev.replay_config.samplebits = 16;
  297. snd_dev.volume = 30;
  298. }
  299. snd_dev.audio.ops = &audio_ops;
  300. rt_audio_register(&snd_dev.audio, "sound0", RT_DEVICE_FLAG_WRONLY, &snd_dev);
  301. return RT_EOK;
  302. }
  303. INIT_DEVICE_EXPORT(rt_hw_sound_init);