drv_sound.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  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-07-31 Zero-Free first implementation
  9. * 2020-07-02 thread-liu Porting for STM32MP1
  10. */
  11. #include "board.h"
  12. #include "drv_cs42l51.h"
  13. #ifdef BSP_USING_AUDIO
  14. //#define DRV_DEBUG
  15. #define LOG_TAG "drv.audio"
  16. #include <drv_log.h>
  17. #define SOUND_BUS_NAME "i2c4"
  18. /* SYSRAM */
  19. #define TX_FIFO_SIZE (4096)
  20. #if defined(__ARMCC_VERSION)
  21. rt_uint8_t AUDIO_TX_FIFO[TX_FIFO_SIZE] __attribute__((at(0x2FFC3000)));
  22. #elif defined(__ICCARM__)
  23. #pragma location = 0x2FFC3000
  24. rt_uint8_t AUDIO_TX_FIFO[TX_FIFO_SIZE];
  25. #elif defined ( __GNUC__ )
  26. rt_uint8_t AUDIO_TX_FIFO[TX_FIFO_SIZE] __attribute__((at(0x2FFC3000)));
  27. #endif
  28. struct sound_device
  29. {
  30. struct rt_audio_device audio;
  31. struct rt_audio_configure replay_config;
  32. rt_uint8_t *tx_fifo;
  33. rt_uint8_t volume;
  34. };
  35. static struct sound_device snd_dev = {0};
  36. SAI_HandleTypeDef hsai_BlockA2 = {0};
  37. DMA_HandleTypeDef hdma_sai2_a = {0};
  38. SAI_HandleTypeDef hsai_BlockB2 = {0};
  39. DMA_HandleTypeDef hdma_sai2_b = {0};
  40. void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai)
  41. {
  42. GPIO_InitTypeDef GPIO_InitStruct = {0};
  43. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  44. /* SAI2 */
  45. if(hsai->Instance==SAI2_Block_A)
  46. {
  47. /* Peripheral clock enable */
  48. if(IS_ENGINEERING_BOOT_MODE())
  49. {
  50. /** Initializes the peripherals clock
  51. */
  52. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
  53. PeriphClkInit.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLL3_Q;
  54. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  55. {
  56. Error_Handler();
  57. }
  58. }
  59. __HAL_RCC_GPIOE_CLK_ENABLE();
  60. __HAL_RCC_GPIOI_CLK_ENABLE();
  61. __HAL_RCC_GPIOF_CLK_ENABLE();
  62. __HAL_RCC_SAI2_CLK_ENABLE();
  63. /**SAI2_A_Block_A GPIO Configuration
  64. PE0 ------> SAI2_MCLK_A
  65. PI7 ------> SAI2_FS_A
  66. PI5 ------> SAI2_SCK_A
  67. PI6 ------> SAI2_SD_A
  68. */
  69. GPIO_InitStruct.Pin = GPIO_PIN_0;
  70. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  71. GPIO_InitStruct.Pull = GPIO_NOPULL;
  72. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  73. GPIO_InitStruct.Alternate = GPIO_AF10_SAI2;
  74. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  75. GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_5|GPIO_PIN_6;
  76. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  77. GPIO_InitStruct.Pull = GPIO_NOPULL;
  78. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  79. GPIO_InitStruct.Alternate = GPIO_AF10_SAI2;
  80. HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
  81. /* Configure DMA used for SAI2 */
  82. __HAL_RCC_DMAMUX_CLK_ENABLE();
  83. __HAL_RCC_DMA2_CLK_ENABLE();
  84. hdma_sai2_a.Instance = DMA2_Stream5;
  85. hdma_sai2_a.Init.Request = DMA_REQUEST_SAI2_A;
  86. hdma_sai2_a.Init.Direction = DMA_MEMORY_TO_PERIPH;
  87. hdma_sai2_a.Init.PeriphInc = DMA_PINC_DISABLE;
  88. hdma_sai2_a.Init.MemInc = DMA_MINC_ENABLE;
  89. hdma_sai2_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  90. hdma_sai2_a.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
  91. hdma_sai2_a.Init.Mode = DMA_CIRCULAR;
  92. hdma_sai2_a.Init.Priority = DMA_PRIORITY_HIGH;
  93. hdma_sai2_a.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  94. HAL_DMA_DeInit(&hdma_sai2_a);
  95. if (HAL_DMA_Init(&hdma_sai2_a) != HAL_OK)
  96. {
  97. Error_Handler();
  98. }
  99. __HAL_LINKDMA(hsai,hdmatx,hdma_sai2_a);
  100. __HAL_DMA_ENABLE(&hdma_sai2_a);
  101. HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 2, 0);
  102. HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
  103. }
  104. if(hsai->Instance==SAI2_Block_B)
  105. {
  106. /* Peripheral clock enable */
  107. if(IS_ENGINEERING_BOOT_MODE())
  108. {
  109. /** Initializes the peripherals clock
  110. */
  111. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
  112. PeriphClkInit.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLL3_Q;
  113. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  114. {
  115. Error_Handler();
  116. }
  117. }
  118. __HAL_RCC_GPIOF_CLK_ENABLE();
  119. __HAL_RCC_SAI2_CLK_ENABLE();
  120. /**SAI2_B_Block_B GPIO Configuration
  121. PF11 ------> SAI2_SD_B
  122. */
  123. GPIO_InitStruct.Pin = GPIO_PIN_11;
  124. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  125. GPIO_InitStruct.Pull = GPIO_NOPULL;
  126. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  127. GPIO_InitStruct.Alternate = GPIO_AF10_SAI2;
  128. HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
  129. __HAL_RCC_DMAMUX_CLK_ENABLE();
  130. __HAL_RCC_DMA2_CLK_ENABLE();
  131. /* Peripheral DMA init*/
  132. hdma_sai2_b.Instance = DMA2_Stream4;
  133. hdma_sai2_b.Init.Request = DMA_REQUEST_SAI2_B;
  134. hdma_sai2_b.Init.Direction = DMA_PERIPH_TO_MEMORY;
  135. hdma_sai2_b.Init.PeriphInc = DMA_PINC_DISABLE;
  136. hdma_sai2_b.Init.MemInc = DMA_MINC_ENABLE;
  137. hdma_sai2_b.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  138. hdma_sai2_b.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
  139. hdma_sai2_b.Init.Mode = DMA_CIRCULAR;
  140. hdma_sai2_b.Init.Priority = DMA_PRIORITY_HIGH;
  141. hdma_sai2_b.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  142. hdma_sai2_b.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
  143. hdma_sai2_b.Init.MemBurst = DMA_MBURST_SINGLE;
  144. hdma_sai2_b.Init.PeriphBurst = DMA_PBURST_SINGLE;
  145. __HAL_LINKDMA(hsai,hdmarx,hdma_sai2_b);
  146. HAL_DMA_DeInit(&hdma_sai2_b);
  147. if (HAL_DMA_Init(&hdma_sai2_b) != HAL_OK)
  148. {
  149. Error_Handler();
  150. }
  151. __HAL_LINKDMA(hsai,hdmarx,hdma_sai2_b);
  152. __HAL_DMA_ENABLE(&hdma_sai2_b);
  153. HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 2, 0);
  154. HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
  155. }
  156. }
  157. void HAL_SAI_MspDeInit(SAI_HandleTypeDef* hsai)
  158. {
  159. /* SAI2 */
  160. if(hsai->Instance==SAI2_Block_A)
  161. {
  162. /* Peripheral clock disable */
  163. __HAL_RCC_SAI2_CLK_DISABLE();
  164. /**SAI2_A_Block_A GPIO Configuration
  165. PE0 ------> SAI2_MCLK_A
  166. PI7 ------> SAI2_FS_A
  167. PI5 ------> SAI2_SCK_A
  168. PI6 ------> SAI2_SD_A
  169. */
  170. HAL_GPIO_DeInit(GPIOE, GPIO_PIN_0);
  171. HAL_GPIO_DeInit(GPIOI, GPIO_PIN_7|GPIO_PIN_5|GPIO_PIN_6);
  172. HAL_DMA_DeInit(hsai->hdmarx);
  173. HAL_DMA_DeInit(hsai->hdmatx);
  174. }
  175. if(hsai->Instance==SAI2_Block_B)
  176. {
  177. /* Peripheral clock disable */
  178. __HAL_RCC_SAI2_CLK_DISABLE();
  179. /**SAI2_B_Block_B GPIO Configuration
  180. PF11 ------> SAI2_SD_B
  181. */
  182. HAL_GPIO_DeInit(GPIOF, GPIO_PIN_11);
  183. HAL_DMA_DeInit(hsai->hdmarx);
  184. HAL_DMA_DeInit(hsai->hdmatx);
  185. }
  186. }
  187. static void rt_hw_sai2a_init(void)
  188. {
  189. HAL_SAI_DeInit(&hsai_BlockA2);
  190. hsai_BlockA2.Instance = SAI2_Block_A;
  191. hsai_BlockA2.Init.Protocol = SAI_FREE_PROTOCOL;
  192. hsai_BlockA2.Init.AudioMode = SAI_MODEMASTER_TX;
  193. hsai_BlockA2.Init.DataSize = SAI_DATASIZE_16;
  194. hsai_BlockA2.Init.FirstBit = SAI_FIRSTBIT_MSB;
  195. hsai_BlockA2.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;
  196. hsai_BlockA2.Init.Synchro = SAI_ASYNCHRONOUS;
  197. hsai_BlockA2.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
  198. hsai_BlockA2.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
  199. hsai_BlockA2.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;
  200. hsai_BlockA2.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;
  201. hsai_BlockA2.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
  202. hsai_BlockA2.Init.MonoStereoMode = SAI_STEREOMODE;
  203. hsai_BlockA2.Init.CompandingMode = SAI_NOCOMPANDING;
  204. hsai_BlockA2.Init.TriState = SAI_OUTPUT_NOTRELEASED;
  205. hsai_BlockA2.Init.PdmInit.Activation = DISABLE;
  206. hsai_BlockA2.Init.PdmInit.MicPairsNbr = 0;
  207. hsai_BlockA2.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;
  208. hsai_BlockA2.FrameInit.FrameLength = 64;
  209. hsai_BlockA2.FrameInit.ActiveFrameLength = 32;
  210. hsai_BlockA2.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
  211. hsai_BlockA2.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
  212. hsai_BlockA2.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
  213. hsai_BlockA2.SlotInit.FirstBitOffset = 0;
  214. hsai_BlockA2.SlotInit.SlotSize = SAI_SLOTSIZE_32B;
  215. hsai_BlockA2.SlotInit.SlotNumber = 2;
  216. hsai_BlockA2.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
  217. if(HAL_OK != HAL_SAI_Init(&hsai_BlockA2))
  218. {
  219. Error_Handler();
  220. }
  221. /* Enable SAI to generate clock used by audio driver */
  222. __HAL_SAI_ENABLE(&hsai_BlockA2);
  223. }
  224. void DMA2_Stream5_IRQHandler(void)
  225. {
  226. HAL_DMA_IRQHandler(&hdma_sai2_a);
  227. }
  228. void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
  229. {
  230. if (hsai == &hsai_BlockA2)
  231. {
  232. rt_audio_tx_complete(&snd_dev.audio);
  233. }
  234. }
  235. void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
  236. {
  237. if (hsai == &hsai_BlockA2)
  238. {
  239. rt_audio_tx_complete(&snd_dev.audio);
  240. }
  241. }
  242. void SAIA_Frequency_Set(uint32_t frequency)
  243. {
  244. return;
  245. }
  246. void SAIA_Channels_Set(uint8_t channels)
  247. {
  248. if (channels == 1)
  249. {
  250. hsai_BlockA2.Init.MonoStereoMode = SAI_MONOMODE;
  251. }
  252. else
  253. {
  254. hsai_BlockA2.Init.MonoStereoMode = SAI_STEREOMODE;
  255. }
  256. __HAL_SAI_DISABLE(&hsai_BlockA2);
  257. HAL_SAI_Init(&hsai_BlockA2);
  258. __HAL_SAI_ENABLE(&hsai_BlockA2);
  259. }
  260. /**
  261. * RT-Thread Audio Device Driver Interface
  262. */
  263. static rt_err_t sound_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  264. {
  265. rt_err_t result = RT_EOK;
  266. struct sound_device *snd_dev;
  267. RT_ASSERT(audio != RT_NULL);
  268. snd_dev = (struct sound_device *)audio->parent.user_data;
  269. switch (caps->main_type)
  270. {
  271. case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */
  272. {
  273. switch (caps->sub_type)
  274. {
  275. case AUDIO_TYPE_QUERY:
  276. caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER;
  277. break;
  278. default:
  279. result = -RT_ERROR;
  280. break;
  281. }
  282. break;
  283. }
  284. case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
  285. {
  286. switch (caps->sub_type)
  287. {
  288. case AUDIO_DSP_PARAM:
  289. caps->udata.config.samplerate = snd_dev->replay_config.samplerate;
  290. caps->udata.config.channels = snd_dev->replay_config.channels;
  291. caps->udata.config.samplebits = snd_dev->replay_config.samplebits;
  292. break;
  293. case AUDIO_DSP_SAMPLERATE:
  294. caps->udata.config.samplerate = snd_dev->replay_config.samplerate;
  295. break;
  296. case AUDIO_DSP_CHANNELS:
  297. caps->udata.config.channels = snd_dev->replay_config.channels;
  298. break;
  299. case AUDIO_DSP_SAMPLEBITS:
  300. caps->udata.config.samplebits = snd_dev->replay_config.samplebits;
  301. break;
  302. default:
  303. result = -RT_ERROR;
  304. break;
  305. }
  306. break;
  307. }
  308. case AUDIO_TYPE_MIXER: /* report the Mixer Units */
  309. {
  310. switch (caps->sub_type)
  311. {
  312. case AUDIO_MIXER_QUERY:
  313. caps->udata.mask = AUDIO_MIXER_VOLUME;
  314. break;
  315. case AUDIO_MIXER_VOLUME:
  316. caps->udata.value = cs42l51_drv.get_volume();
  317. break;
  318. default:
  319. result = -RT_ERROR;
  320. break;
  321. }
  322. break;
  323. }
  324. default:
  325. result = -RT_ERROR;
  326. break;
  327. }
  328. return result;
  329. }
  330. static rt_err_t sound_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  331. {
  332. rt_err_t result = RT_EOK;
  333. struct sound_device *snd_dev;
  334. RT_ASSERT(audio != RT_NULL);
  335. snd_dev = (struct sound_device *)audio->parent.user_data;
  336. switch (caps->main_type)
  337. {
  338. case AUDIO_TYPE_MIXER:
  339. {
  340. switch (caps->sub_type)
  341. {
  342. case AUDIO_MIXER_VOLUME:
  343. {
  344. rt_uint8_t volume = caps->udata.value;
  345. cs42l51_drv.set_volume(volume);
  346. snd_dev->volume = volume;
  347. LOG_D("set volume %d", volume);
  348. break;
  349. }
  350. default:
  351. result = -RT_ERROR;
  352. break;
  353. }
  354. break;
  355. }
  356. case AUDIO_TYPE_OUTPUT:
  357. {
  358. switch (caps->sub_type)
  359. {
  360. case AUDIO_DSP_PARAM:
  361. {
  362. /* set samplerate */
  363. SAIA_Frequency_Set(caps->udata.config.samplerate);
  364. /* set channels */
  365. SAIA_Channels_Set(caps->udata.config.channels);
  366. /* save configs */
  367. snd_dev->replay_config.samplerate = caps->udata.config.samplerate;
  368. snd_dev->replay_config.channels = caps->udata.config.channels;
  369. snd_dev->replay_config.samplebits = caps->udata.config.samplebits;
  370. LOG_D("set samplerate %d", snd_dev->replay_config.samplerate);
  371. break;
  372. }
  373. case AUDIO_DSP_SAMPLERATE:
  374. {
  375. SAIA_Frequency_Set(caps->udata.config.samplerate);
  376. snd_dev->replay_config.samplerate = caps->udata.config.samplerate;
  377. LOG_D("set samplerate %d", snd_dev->replay_config.samplerate);
  378. break;
  379. }
  380. case AUDIO_DSP_CHANNELS:
  381. {
  382. SAIA_Channels_Set(caps->udata.config.channels);
  383. snd_dev->replay_config.channels = caps->udata.config.channels;
  384. LOG_D("set channels %d", snd_dev->replay_config.channels);
  385. break;
  386. }
  387. case AUDIO_DSP_SAMPLEBITS:
  388. {
  389. /* not support */
  390. snd_dev->replay_config.samplebits = caps->udata.config.samplebits;
  391. break;
  392. }
  393. default:
  394. result = -RT_ERROR;
  395. break;
  396. }
  397. break;
  398. }
  399. default:
  400. break;
  401. }
  402. return result;
  403. }
  404. static rt_err_t sound_init(struct rt_audio_device *audio)
  405. {
  406. rt_err_t result = RT_EOK;
  407. struct sound_device *snd_dev;
  408. RT_ASSERT(audio != RT_NULL);
  409. snd_dev = (struct sound_device *)audio->parent.user_data;
  410. cs42l51_drv.init(OUT_HEADPHONE, SOUND_BUS_NAME, 40);
  411. if (cs42l51_drv.read_id() != RT_EOK)
  412. {
  413. LOG_E("can't find low level audio device!");
  414. return -RT_ERROR;
  415. }
  416. rt_hw_sai2a_init();
  417. /* set default params */
  418. SAIA_Frequency_Set(snd_dev->replay_config.samplerate);
  419. SAIA_Channels_Set(snd_dev->replay_config.channels);
  420. return result;
  421. }
  422. static rt_err_t sound_start(struct rt_audio_device *audio, int stream)
  423. {
  424. struct sound_device *snd_dev;
  425. RT_ASSERT(audio != RT_NULL);
  426. snd_dev = (struct sound_device *)audio->parent.user_data;
  427. if (stream == AUDIO_STREAM_REPLAY)
  428. {
  429. LOG_D("open sound device");
  430. cs42l51_drv.init(OUT_HEADPHONE, SOUND_BUS_NAME, 60); /* set work mode */
  431. cs42l51_drv.play();
  432. if (HAL_SAI_Transmit_DMA(&hsai_BlockA2, snd_dev->tx_fifo, TX_FIFO_SIZE / 2) != HAL_OK)
  433. {
  434. return -RT_ERROR;
  435. }
  436. }
  437. return RT_EOK;
  438. }
  439. static rt_err_t sound_stop(struct rt_audio_device *audio, int stream)
  440. {
  441. RT_ASSERT(audio != RT_NULL);
  442. if (stream == AUDIO_STREAM_REPLAY)
  443. {
  444. HAL_SAI_DMAStop(&hsai_BlockA2);
  445. HAL_SAI_Abort(&hsai_BlockA2);
  446. cs42l51_drv.stop();
  447. LOG_D("close sound device");
  448. }
  449. return RT_EOK;
  450. }
  451. static void sound_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
  452. {
  453. struct sound_device *snd_dev;
  454. RT_ASSERT(audio != RT_NULL);
  455. snd_dev = (struct sound_device *)audio->parent.user_data;
  456. /**
  457. * TX_FIFO
  458. * +----------------+----------------+
  459. * | block1 | block2 |
  460. * +----------------+----------------+
  461. * \ block_size /
  462. */
  463. info->buffer = snd_dev->tx_fifo;
  464. info->total_size = TX_FIFO_SIZE;
  465. info->block_size = TX_FIFO_SIZE / 2;
  466. info->block_count = 2;
  467. }
  468. static struct rt_audio_ops snd_ops =
  469. {
  470. .getcaps = sound_getcaps,
  471. .configure = sound_configure,
  472. .init = sound_init,
  473. .start = sound_start,
  474. .stop = sound_stop,
  475. .transmit = RT_NULL,
  476. .buffer_info = sound_buffer_info,
  477. };
  478. int rt_hw_sound_init(void)
  479. {
  480. rt_err_t result = RT_EOK;
  481. struct rt_device *device = RT_NULL;
  482. rt_memset(AUDIO_TX_FIFO, 0, TX_FIFO_SIZE);
  483. snd_dev.tx_fifo = AUDIO_TX_FIFO;
  484. /* init default configuration */
  485. snd_dev.replay_config.samplerate = 44100;
  486. snd_dev.replay_config.channels = 2;
  487. snd_dev.replay_config.samplebits = 16;
  488. snd_dev.volume = 55;
  489. /* register sound device */
  490. snd_dev.audio.ops = &snd_ops;
  491. result = rt_audio_register(&snd_dev.audio, "sound0", RT_DEVICE_FLAG_WRONLY, &snd_dev);
  492. if (result != RT_EOK)
  493. {
  494. device = &(snd_dev.audio.parent);
  495. rt_device_unregister(device);
  496. LOG_E("sound device init error!");
  497. return -RT_ERROR;
  498. }
  499. return RT_EOK;
  500. }
  501. INIT_APP_EXPORT(rt_hw_sound_init);
  502. #endif