1
0

drv_i2s.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. * Copyright (c) 2022 hpmicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include <rtthread.h>
  8. #include <rtdevice.h>
  9. #define DBG_TAG "i2s"
  10. #define DBG_LVL DBG_INFO
  11. #include <rtdbg.h>
  12. #ifdef BSP_USING_I2S
  13. #include "hpm_i2s_drv.h"
  14. #include "board.h"
  15. #include "hpm_dma_drv.h"
  16. #include "hpm_dmamux_drv.h"
  17. #include "hpm_l1c_drv.h"
  18. #include "hpm_clock_drv.h"
  19. #include "hpm_dma_manager.h"
  20. #include "drv_i2s.h"
  21. #include "drivers/audio.h"
  22. static rt_ssize_t hpm_i2s_transmit(struct rt_audio_device* audio, const void* writeBuf, void* readBuf, rt_size_t size);
  23. struct hpm_i2s
  24. {
  25. struct rt_audio_device audio;
  26. struct rt_audio_configure audio_config;
  27. hpm_dma_resource_t rx_dma_resource;
  28. hpm_dma_resource_t tx_dma_resource;
  29. char *dev_name;
  30. I2S_Type *base;
  31. clock_name_t clk_name;
  32. i2s_transfer_config_t transfer;
  33. uint8_t rx_dma_req;
  34. uint8_t tx_dma_req;
  35. rt_uint8_t* tx_buff;
  36. rt_uint8_t* rx_buff;
  37. };
  38. #if defined(BSP_USING_I2S0)
  39. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s0_tx_buff[I2S_FIFO_SIZE];
  40. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s0_rx_buff[I2S_FIFO_SIZE];
  41. #endif
  42. #if defined(BSP_USING_I2S1)
  43. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s1_tx_buff[I2S_FIFO_SIZE];
  44. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s1_rx_buff[I2S_FIFO_SIZE];
  45. #endif
  46. #if defined(BSP_USING_I2S2)
  47. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s2_tx_buff[I2S_FIFO_SIZE];
  48. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s2_rx_buff[I2S_FIFO_SIZE];
  49. #endif
  50. #if defined(BSP_USING_I2S3)
  51. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s3_tx_buff[I2S_FIFO_SIZE];
  52. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s3_rx_buff[I2S_FIFO_SIZE];
  53. #endif
  54. static struct hpm_i2s hpm_i2s_set[] =
  55. {
  56. #if defined(BSP_USING_I2S0)
  57. {
  58. .dev_name = "i2s0",
  59. .base = HPM_I2S0,
  60. .clk_name = clock_i2s0,
  61. .rx_dma_req = HPM_DMA_SRC_I2S0_RX,
  62. .tx_dma_req = HPM_DMA_SRC_I2S0_TX,
  63. .tx_buff = i2s0_tx_buff,
  64. .rx_buff = i2s0_rx_buff,
  65. },
  66. #endif
  67. #if defined(BSP_USING_I2S1)
  68. {
  69. .dev_name = "i2s1",
  70. .base = HPM_I2S1;
  71. .clk_name = clock_i2s1,
  72. .rx_dma_req = HPM_DMA_SRC_I2S1_RX,
  73. .tx_dma_req = HPM_DMA_SRC_I2S1_TX,
  74. .tx_buff = i2s1_tx_buff,
  75. .rx_buff = i2s1_rx_buff,
  76. },
  77. #endif
  78. #if defined(BSP_USING_I2S2)
  79. {
  80. .dev_name = "i2s2",
  81. .base = HPM_I2S2,
  82. .clk_name = clock_i2s2,
  83. .rx_dma_req = HPM_DMA_SRC_I2S2_RX,
  84. .tx_dma_req = HPM_DMA_SRC_I2S2_TX,
  85. .tx_buff = i2s2_tx_buff,
  86. .rx_buff = i2s2_rx_buff,
  87. },
  88. #endif
  89. #if defined(BSP_USING_I2S3)
  90. {
  91. .dev_name = "i2s3",
  92. .base = HPM_I2S3,
  93. .clk_name = clock_i2s3,
  94. .rx_dma_req = HPM_DMA_SRC_I2S3_RX,
  95. .tx_dma_req = HPM_DMA_SRC_I2S3_TX,
  96. .tx_buff = i2s3_tx_buff,
  97. .rx_buff = i2s3_rx_buff,
  98. },
  99. #endif
  100. };
  101. /* I2S TX DMA callback function: trigger next transfer */
  102. void i2s_tx_dma_callback(DMA_Type *ptr, uint32_t channel, void *user_data, uint32_t int_stat)
  103. {
  104. if (int_stat == DMA_CHANNEL_STATUS_TC) {
  105. struct hpm_i2s* hpm_audio = (struct hpm_i2s*) user_data;
  106. rt_audio_tx_complete(&hpm_audio->audio);
  107. }
  108. }
  109. /* I2S RX DMA callback function: write data into record->pipe and trigger next transfer */
  110. void i2s_rx_dma_callback(DMA_Type *ptr, uint32_t channel, void *user_data, uint32_t int_stat)
  111. {
  112. if (int_stat == DMA_CHANNEL_STATUS_TC) {
  113. struct hpm_i2s* hpm_audio = (struct hpm_i2s*) user_data;
  114. rt_audio_rx_done(&hpm_audio->audio, hpm_audio->rx_buff, I2S_FIFO_SIZE);
  115. hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE);
  116. }
  117. }
  118. static rt_err_t hpm_i2s_init(struct rt_audio_device* audio)
  119. {
  120. RT_ASSERT(audio != RT_NULL);
  121. rt_uint32_t mclk_hz;
  122. i2s_config_t i2s_config;
  123. i2s_transfer_config_t transfer;
  124. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  125. init_i2s_pins(hpm_audio->base);
  126. board_init_i2s_clock(hpm_audio->base);
  127. //使用DMA传输
  128. i2s_enable_rx_dma_request(hpm_audio->base);
  129. i2s_enable_tx_dma_request(hpm_audio->base);
  130. i2s_get_default_config(hpm_audio->base, &i2s_config);
  131. i2s_config.enable_mclk_out = true;
  132. i2s_config.frame_start_at_rising_edge = true; //左对齐与右对齐方式, 对应上升沿
  133. i2s_init(hpm_audio->base, &i2s_config);
  134. mclk_hz = clock_get_frequency(hpm_audio->clk_name);
  135. i2s_get_default_transfer_config(&transfer);
  136. /* 初始化I2S配置, 应用使用configure ops修改属性 */
  137. transfer.sample_rate = 24000U;
  138. transfer.protocol = I2S_PROTOCOL_LEFT_JUSTIFIED;
  139. transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0); /* 1个通道 */
  140. transfer.audio_depth = I2S_AUDIO_DEPTH_16_BITS;
  141. transfer.master_mode = true;
  142. hpm_audio->transfer = transfer;
  143. //将初始参数记录到audio_config
  144. hpm_audio->audio_config.samplerate = 24000U;
  145. hpm_audio->audio_config.samplebits = 16;
  146. hpm_audio->audio_config.channels = 1;
  147. if (status_success != i2s_config_transfer(hpm_audio->base, mclk_hz, &transfer))
  148. {
  149. LOG_E("dao_i2s configure transfer failed\n");
  150. return -RT_ERROR;
  151. }
  152. return RT_EOK;
  153. }
  154. static rt_err_t hpm_i2s_getcaps(struct rt_audio_device* audio, struct rt_audio_caps* caps)
  155. {
  156. rt_err_t result = RT_EOK;
  157. RT_ASSERT(audio != RT_NULL);
  158. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  159. switch(caps->main_type)
  160. {
  161. case AUDIO_TYPE_INPUT:
  162. {
  163. switch(caps->sub_type)
  164. {
  165. case AUDIO_DSP_PARAM:
  166. {
  167. caps->udata.config.channels = hpm_audio->audio_config.channels;
  168. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  169. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  170. break;
  171. }
  172. case AUDIO_DSP_SAMPLERATE:
  173. {
  174. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  175. break;
  176. }
  177. case AUDIO_DSP_CHANNELS:
  178. {
  179. caps->udata.config.channels = hpm_audio->audio_config.channels;
  180. break;
  181. }
  182. case AUDIO_DSP_SAMPLEBITS:
  183. {
  184. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  185. break;
  186. }
  187. case AUDIO_PARM_I2S_DATA_LINE:
  188. {
  189. caps->udata.value = hpm_audio->transfer.data_line;
  190. break;
  191. }
  192. default:
  193. {
  194. result = -RT_ERROR;
  195. break;
  196. }
  197. }
  198. break;
  199. }
  200. case AUDIO_TYPE_OUTPUT:
  201. {
  202. switch(caps->sub_type)
  203. {
  204. case AUDIO_DSP_PARAM:
  205. {
  206. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  207. caps->udata.config.channels = hpm_audio->audio_config.channels;
  208. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  209. break;
  210. }
  211. case AUDIO_DSP_SAMPLERATE:
  212. {
  213. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  214. break;
  215. }
  216. case AUDIO_DSP_CHANNELS:
  217. {
  218. caps->udata.config.channels = hpm_audio->audio_config.channels;
  219. break;
  220. }
  221. case AUDIO_DSP_SAMPLEBITS:
  222. {
  223. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  224. break;
  225. }
  226. case AUDIO_PARM_I2S_DATA_LINE:
  227. {
  228. caps->udata.value = hpm_audio->transfer.data_line;
  229. break;
  230. }
  231. default:
  232. {
  233. result = -RT_ERROR;
  234. break;
  235. }
  236. }
  237. break;
  238. }
  239. default:
  240. result = -RT_ERROR;
  241. break;
  242. }
  243. return result;
  244. }
  245. static rt_err_t hpm_i2s_configure(struct rt_audio_device* audio, struct rt_audio_caps* caps)
  246. {
  247. rt_err_t result = RT_EOK;
  248. RT_ASSERT(audio != RT_NULL);
  249. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  250. switch(caps->main_type)
  251. {
  252. case AUDIO_TYPE_OUTPUT:
  253. {
  254. switch(caps->sub_type)
  255. {
  256. case AUDIO_DSP_PARAM:
  257. {
  258. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  259. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  260. hpm_audio->audio_config.channels = caps->udata.config.channels;
  261. break;
  262. }
  263. case AUDIO_DSP_SAMPLERATE:
  264. {
  265. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  266. break;
  267. }
  268. case AUDIO_DSP_CHANNELS:
  269. {
  270. hpm_audio->audio_config.channels = caps->udata.config.channels;
  271. break;
  272. }
  273. case AUDIO_DSP_SAMPLEBITS:
  274. {
  275. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  276. break;
  277. }
  278. case AUDIO_PARM_I2S_DATA_LINE:
  279. {
  280. hpm_audio->transfer.data_line = caps->udata.value;
  281. break;
  282. }
  283. default:
  284. result = -RT_ERROR;
  285. break;
  286. }
  287. break;
  288. }
  289. case AUDIO_TYPE_INPUT:
  290. {
  291. switch(caps->sub_type)
  292. {
  293. case AUDIO_DSP_PARAM:
  294. {
  295. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  296. hpm_audio->audio_config.channels = caps->udata.config.channels;
  297. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  298. break;
  299. }
  300. case AUDIO_DSP_SAMPLERATE:
  301. {
  302. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  303. break;
  304. }
  305. case AUDIO_DSP_CHANNELS:
  306. {
  307. hpm_audio->audio_config.channels = caps->udata.config.channels;
  308. break;
  309. }
  310. case AUDIO_DSP_SAMPLEBITS:
  311. {
  312. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  313. break;
  314. }
  315. case AUDIO_PARM_I2S_DATA_LINE:
  316. {
  317. hpm_audio->transfer.data_line = caps->udata.value;
  318. break;
  319. }
  320. default:
  321. result = -RT_ERROR;
  322. break;
  323. }
  324. break;
  325. }
  326. default:
  327. break;
  328. }
  329. /* 设置 I2S transfer */
  330. if (hpm_audio->audio_config.channels == i2s_mono_left) {
  331. hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0);
  332. } else if (hpm_audio->audio_config.channels == i2s_mono_right) {
  333. hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(1);
  334. } else if(hpm_audio->audio_config.channels == 2) {
  335. hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0) | I2S_CHANNEL_SLOT_MASK(1);
  336. } else {
  337. LOG_E("I2S not support channels number %d.\n", hpm_audio->audio_config.channels);
  338. return -RT_ERROR;
  339. }
  340. hpm_audio->transfer.sample_rate = hpm_audio->audio_config.samplerate;
  341. //i2s dma方式仅支持采样位宽为:16bit, 32bit
  342. assert(hpm_audio->audio_config.samplebits == 16 || hpm_audio->audio_config.samplebits == 32);
  343. hpm_audio->transfer.audio_depth = (hpm_audio->audio_config.samplebits - 16) >> 3;
  344. if (status_success != i2s_config_transfer(hpm_audio->base, clock_get_frequency(hpm_audio->clk_name), &hpm_audio->transfer))
  345. {
  346. LOG_E("%s configure transfer failed.\n", hpm_audio->dev_name);
  347. }
  348. return result;
  349. }
  350. static rt_err_t hpm_i2s_start(struct rt_audio_device* audio, int stream)
  351. {
  352. RT_ASSERT(audio != RT_NULL);
  353. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  354. /* 申请DMA resource用于I2S transfer */
  355. if (stream == AUDIO_STREAM_REPLAY) {
  356. hpm_dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
  357. if (dma_manager_request_resource(dma_resource) == status_success) {
  358. uint8_t dmamux_ch;
  359. dma_manager_install_interrupt_callback(dma_resource, i2s_tx_dma_callback, hpm_audio);
  360. dma_manager_enable_dma_interrupt(dma_resource, 1);
  361. dmamux_ch = DMA_SOC_CHN_TO_DMAMUX_CHN(dma_resource->base, dma_resource->channel);
  362. dmamux_config(HPM_DMAMUX, dmamux_ch, hpm_audio->tx_dma_req, true);
  363. } else {
  364. LOG_E("no dma resource available for I2S TX transfer.\n");
  365. return -RT_ERROR;
  366. }
  367. rt_audio_tx_complete(audio);
  368. } else if (stream == AUDIO_STREAM_RECORD) {
  369. hpm_dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
  370. if (dma_manager_request_resource(dma_resource) == status_success) {
  371. uint8_t dmamux_ch;
  372. dma_manager_install_interrupt_callback(dma_resource, i2s_rx_dma_callback, hpm_audio);
  373. dma_manager_enable_dma_interrupt(dma_resource, 1);
  374. dmamux_ch = DMA_SOC_CHN_TO_DMAMUX_CHN(dma_resource->base, dma_resource->channel);
  375. dmamux_config(HPM_DMAMUX, dmamux_ch, hpm_audio->rx_dma_req, true);
  376. } else {
  377. LOG_E("no dma resource available for I2S RX transfer.\n");
  378. return -RT_ERROR;
  379. }
  380. if (RT_EOK != hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE)) {
  381. return -RT_ERROR;
  382. }
  383. } else {
  384. return -RT_ERROR;
  385. }
  386. return RT_EOK;
  387. }
  388. static rt_err_t hpm_i2s_stop(struct rt_audio_device* audio, int stream)
  389. {
  390. RT_ASSERT(audio != RT_NULL);
  391. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  392. if (stream == AUDIO_STREAM_REPLAY) {
  393. hpm_dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
  394. dma_manager_release_resource(dma_resource);
  395. } else if (stream == AUDIO_STREAM_RECORD)
  396. {
  397. hpm_dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
  398. dma_manager_release_resource(dma_resource);
  399. } else {
  400. return -RT_ERROR;
  401. }
  402. return RT_EOK;
  403. }
  404. static rt_ssize_t hpm_i2s_transmit(struct rt_audio_device* audio, const void* writeBuf, void* readBuf, rt_size_t size)
  405. {
  406. RT_ASSERT(audio != RT_NULL);
  407. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  408. //支持采样位宽16bit, 32bit
  409. uint8_t data_width;
  410. uint8_t data_shift_byte;
  411. if (hpm_audio->transfer.audio_depth == I2S_AUDIO_DEPTH_16_BITS) {
  412. data_width = DMA_TRANSFER_WIDTH_HALF_WORD;
  413. data_shift_byte = 2U ; //16位音频数据位于寄存器的高位
  414. } else {
  415. data_width = DMA_TRANSFER_WIDTH_WORD;
  416. data_shift_byte = 0U;
  417. }
  418. if(writeBuf != RT_NULL)
  419. {
  420. hpm_dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
  421. dma_channel_config_t ch_config = {0};
  422. dma_default_channel_config(dma_resource->base, &ch_config);
  423. ch_config.src_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)writeBuf);
  424. ch_config.dst_addr = (uint32_t)&hpm_audio->base->TXD[hpm_audio->transfer.data_line] + data_shift_byte;
  425. ch_config.src_width = data_width;
  426. ch_config.dst_width = data_width;
  427. ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
  428. ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
  429. ch_config.size_in_byte = size;
  430. ch_config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
  431. ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
  432. if (l1c_dc_is_enabled()) {
  433. /* cache writeback for sent buff */
  434. l1c_dc_writeback((uint32_t)writeBuf, size);
  435. }
  436. if (status_success != dma_setup_channel(dma_resource->base, dma_resource->channel, &ch_config)) {
  437. LOG_E("dma setup channel failed\n");
  438. return -RT_ERROR;
  439. }
  440. } else if (readBuf != RT_NULL){
  441. hpm_dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
  442. dma_channel_config_t ch_config = {0};
  443. dma_default_channel_config(dma_resource->base, &ch_config);
  444. ch_config.src_addr = (uint32_t)&hpm_audio->base->RXD[hpm_audio->transfer.data_line] + data_shift_byte;
  445. ch_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)readBuf);
  446. ch_config.src_width = data_width;
  447. ch_config.dst_width = data_width;
  448. ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
  449. ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
  450. ch_config.size_in_byte = size;
  451. ch_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
  452. ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
  453. if (status_success != dma_setup_channel(dma_resource->base, dma_resource->channel, &ch_config)) {
  454. LOG_E("dma setup channel failed\n");
  455. return -RT_ERROR;
  456. }
  457. if (l1c_dc_is_enabled()) {
  458. /* cache invalidate for receive buff */
  459. l1c_dc_invalidate((uint32_t)readBuf, size);
  460. }
  461. }
  462. return size;
  463. }
  464. static void hpm_i2s_buffer_info(struct rt_audio_device* audio, struct rt_audio_buf_info* info)
  465. {
  466. RT_ASSERT(audio != RT_NULL);
  467. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  468. /**
  469. * AUD_FIFO
  470. * +----------------+----------------+
  471. * | block1 | block2 |
  472. * +----------------+----------------+
  473. * \ block_size /
  474. */
  475. info->buffer = hpm_audio->tx_buff;
  476. info->total_size = I2S_FIFO_SIZE;
  477. info->block_size = I2S_FIFO_SIZE / 2;
  478. info->block_count = 2;
  479. }
  480. static struct rt_audio_ops hpm_i2s_ops =
  481. {
  482. .getcaps = hpm_i2s_getcaps,
  483. .configure = hpm_i2s_configure,
  484. .init = hpm_i2s_init,
  485. .start = hpm_i2s_start,
  486. .stop = hpm_i2s_stop,
  487. .transmit = hpm_i2s_transmit,
  488. .buffer_info = hpm_i2s_buffer_info,
  489. };
  490. int rt_hw_i2s_init(void)
  491. {
  492. rt_err_t ret = RT_EOK;
  493. for (uint32_t i = 0; i < sizeof(hpm_i2s_set) / sizeof(hpm_i2s_set[0]); i++) {
  494. hpm_i2s_set[i].audio.ops = &hpm_i2s_ops;
  495. ret = rt_audio_register(&hpm_i2s_set[i].audio, hpm_i2s_set[i].dev_name, RT_DEVICE_FLAG_RDWR, &hpm_i2s_set[i]);
  496. if (ret != RT_EOK)
  497. {
  498. LOG_E("rt audio %s register failed, status=%d\n", hpm_i2s_set[i].dev_name, ret);
  499. }
  500. }
  501. return RT_EOK;
  502. }
  503. INIT_DEVICE_EXPORT(rt_hw_i2s_init);
  504. #endif /* BSP_USING_I2S */