drv_i2s.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /*
  2. * Copyright (c) 2022-2025 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. #ifdef HPMSOC_HAS_HPMSDK_DMAV2
  16. #include "hpm_dmav2_drv.h"
  17. #else
  18. #include "hpm_dma_drv.h"
  19. #endif
  20. #include "hpm_dmamux_drv.h"
  21. #include "hpm_l1c_drv.h"
  22. #include "hpm_clock_drv.h"
  23. #include "hpm_dma_mgr.h"
  24. #include "drv_i2s.h"
  25. #include "drivers/dev_audio.h"
  26. extern uint32_t rtt_board_init_i2s_clock(I2S_Type *ptr);
  27. static rt_ssize_t hpm_i2s_transmit(struct rt_audio_device* audio, const void* writeBuf, void* readBuf, rt_size_t size);
  28. /**
  29. * I2S state
  30. */
  31. typedef enum {
  32. hpm_i2s_state_stop,
  33. hpm_i2s_state_read,
  34. hpm_i2s_state_write,
  35. } hpm_i2s_state_t;
  36. struct hpm_i2s
  37. {
  38. struct rt_audio_device audio;
  39. struct rt_audio_configure audio_config;
  40. dma_resource_t rx_dma_resource;
  41. dma_resource_t tx_dma_resource;
  42. char *dev_name;
  43. I2S_Type *base;
  44. clock_name_t clk_name;
  45. i2s_transfer_config_t transfer;
  46. uint8_t rx_dma_req;
  47. uint8_t tx_dma_req;
  48. rt_uint8_t* tx_buff;
  49. rt_uint8_t* rx_buff;
  50. hpm_i2s_state_t i2s_state;
  51. };
  52. #if defined(BSP_USING_I2S0)
  53. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s0_tx_buff[I2S_FIFO_SIZE];
  54. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s0_rx_buff[I2S_FIFO_SIZE];
  55. #endif
  56. #if defined(BSP_USING_I2S1)
  57. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s1_tx_buff[I2S_FIFO_SIZE];
  58. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s1_rx_buff[I2S_FIFO_SIZE];
  59. #endif
  60. #if defined(BSP_USING_I2S2)
  61. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s2_tx_buff[I2S_FIFO_SIZE];
  62. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s2_rx_buff[I2S_FIFO_SIZE];
  63. #endif
  64. #if defined(BSP_USING_I2S3)
  65. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s3_tx_buff[I2S_FIFO_SIZE];
  66. ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s3_rx_buff[I2S_FIFO_SIZE];
  67. #endif
  68. static struct hpm_i2s hpm_i2s_set[] =
  69. {
  70. #if defined(BSP_USING_I2S0) && defined(HPM_I2S0)
  71. {
  72. .dev_name = "i2s0",
  73. .base = HPM_I2S0,
  74. .clk_name = clock_i2s0,
  75. .rx_dma_req = HPM_DMA_SRC_I2S0_RX,
  76. .tx_dma_req = HPM_DMA_SRC_I2S0_TX,
  77. .tx_buff = i2s0_tx_buff,
  78. .rx_buff = i2s0_rx_buff,
  79. },
  80. #endif
  81. #if defined(BSP_USING_I2S1) && defined(HPM_I2S1)
  82. {
  83. .dev_name = "i2s1",
  84. .base = HPM_I2S1,
  85. .clk_name = clock_i2s1,
  86. .rx_dma_req = HPM_DMA_SRC_I2S1_RX,
  87. .tx_dma_req = HPM_DMA_SRC_I2S1_TX,
  88. .tx_buff = i2s1_tx_buff,
  89. .rx_buff = i2s1_rx_buff,
  90. },
  91. #endif
  92. #if defined(BSP_USING_I2S2) && defined(HPM_I2S2)
  93. {
  94. .dev_name = "i2s2",
  95. .base = HPM_I2S2,
  96. .clk_name = clock_i2s2,
  97. .rx_dma_req = HPM_DMA_SRC_I2S2_RX,
  98. .tx_dma_req = HPM_DMA_SRC_I2S2_TX,
  99. .tx_buff = i2s2_tx_buff,
  100. .rx_buff = i2s2_rx_buff,
  101. },
  102. #endif
  103. #if defined(BSP_USING_I2S3) && defined(HPM_I2S3)
  104. {
  105. .dev_name = "i2s3",
  106. .base = HPM_I2S3,
  107. .clk_name = clock_i2s3,
  108. .rx_dma_req = HPM_DMA_SRC_I2S3_RX,
  109. .tx_dma_req = HPM_DMA_SRC_I2S3_TX,
  110. .tx_buff = i2s3_tx_buff,
  111. .rx_buff = i2s3_rx_buff,
  112. },
  113. #endif
  114. };
  115. /* I2S TX DMA callback function: trigger next transfer */
  116. void i2s_tx_dma_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data)
  117. {
  118. struct hpm_i2s* hpm_audio = (struct hpm_i2s*) user_data;
  119. rt_audio_tx_complete(&hpm_audio->audio);
  120. }
  121. /* I2S RX DMA callback function: write data into record->pipe and trigger next transfer */
  122. void i2s_rx_dma_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data)
  123. {
  124. struct hpm_i2s* hpm_audio = (struct hpm_i2s*) user_data;
  125. rt_audio_rx_done(&hpm_audio->audio, hpm_audio->rx_buff, I2S_FIFO_SIZE);
  126. hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE);
  127. }
  128. static rt_err_t hpm_i2s_init(struct rt_audio_device* audio)
  129. {
  130. RT_ASSERT(audio != RT_NULL);
  131. rt_uint32_t mclk_hz;
  132. i2s_config_t i2s_config;
  133. i2s_transfer_config_t transfer;
  134. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  135. init_i2s_pins(hpm_audio->base);
  136. rtt_board_init_i2s_clock(hpm_audio->base);
  137. /* enable dma request */
  138. i2s_enable_rx_dma_request(hpm_audio->base);
  139. i2s_enable_tx_dma_request(hpm_audio->base);
  140. i2s_get_default_config(hpm_audio->base, &i2s_config);
  141. i2s_config.enable_mclk_out = true;
  142. i2s_init(hpm_audio->base, &i2s_config);
  143. mclk_hz = clock_get_frequency(hpm_audio->clk_name);
  144. i2s_get_default_transfer_config(&transfer);
  145. /* init I2S parameter */
  146. transfer.sample_rate = 48000U;
  147. transfer.protocol = I2S_PROTOCOL_LEFT_JUSTIFIED;
  148. transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0); /* one channel */
  149. transfer.audio_depth = i2s_audio_depth_16_bits;
  150. transfer.master_mode = true;
  151. transfer.data_line = BOARD_APP_I2S_RX_DATA_LINE;
  152. hpm_audio->transfer = transfer;
  153. /* record i2s parameter to audio_config */
  154. hpm_audio->audio_config.samplerate = 48000U;
  155. hpm_audio->audio_config.samplebits = 16;
  156. hpm_audio->audio_config.channels = 1;
  157. if (status_success != i2s_config_transfer(hpm_audio->base, mclk_hz, &transfer))
  158. {
  159. LOG_E("i2s configure transfer failed\n");
  160. return -RT_ERROR;
  161. }
  162. hpm_audio->i2s_state = hpm_i2s_state_stop;
  163. return RT_EOK;
  164. }
  165. static rt_err_t hpm_i2s_getcaps(struct rt_audio_device* audio, struct rt_audio_caps* caps)
  166. {
  167. rt_err_t result = RT_EOK;
  168. RT_ASSERT(audio != RT_NULL);
  169. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  170. switch(caps->main_type)
  171. {
  172. case AUDIO_TYPE_INPUT:
  173. {
  174. switch(caps->sub_type)
  175. {
  176. case AUDIO_DSP_PARAM:
  177. {
  178. caps->udata.config.channels = hpm_audio->audio_config.channels;
  179. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  180. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  181. break;
  182. }
  183. case AUDIO_DSP_SAMPLERATE:
  184. {
  185. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  186. break;
  187. }
  188. case AUDIO_DSP_CHANNELS:
  189. {
  190. caps->udata.config.channels = hpm_audio->audio_config.channels;
  191. break;
  192. }
  193. case AUDIO_DSP_SAMPLEBITS:
  194. {
  195. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  196. break;
  197. }
  198. case AUDIO_PARM_I2S_DATA_LINE:
  199. {
  200. caps->udata.value = hpm_audio->transfer.data_line;
  201. break;
  202. }
  203. default:
  204. {
  205. result = -RT_ERROR;
  206. break;
  207. }
  208. }
  209. break;
  210. }
  211. case AUDIO_TYPE_OUTPUT:
  212. {
  213. switch(caps->sub_type)
  214. {
  215. case AUDIO_DSP_PARAM:
  216. {
  217. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  218. caps->udata.config.channels = hpm_audio->audio_config.channels;
  219. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  220. break;
  221. }
  222. case AUDIO_DSP_SAMPLERATE:
  223. {
  224. caps->udata.config.samplerate = hpm_audio->audio_config.samplerate;
  225. break;
  226. }
  227. case AUDIO_DSP_CHANNELS:
  228. {
  229. caps->udata.config.channels = hpm_audio->audio_config.channels;
  230. break;
  231. }
  232. case AUDIO_DSP_SAMPLEBITS:
  233. {
  234. caps->udata.config.samplebits = hpm_audio->audio_config.samplebits;
  235. break;
  236. }
  237. case AUDIO_PARM_I2S_DATA_LINE:
  238. {
  239. caps->udata.value = hpm_audio->transfer.data_line;
  240. break;
  241. }
  242. default:
  243. {
  244. result = -RT_ERROR;
  245. break;
  246. }
  247. }
  248. break;
  249. }
  250. default:
  251. result = -RT_ERROR;
  252. break;
  253. }
  254. return result;
  255. }
  256. static bool i2s_is_enabled(I2S_Type *ptr)
  257. {
  258. return ((ptr->CTRL & I2S_CTRL_I2S_EN_MASK) != 0);
  259. }
  260. static rt_err_t hpm_i2s_configure(struct rt_audio_device* audio, struct rt_audio_caps* caps)
  261. {
  262. rt_err_t result = RT_EOK;
  263. RT_ASSERT(audio != RT_NULL);
  264. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  265. switch(caps->main_type)
  266. {
  267. case AUDIO_TYPE_OUTPUT:
  268. {
  269. switch(caps->sub_type)
  270. {
  271. case AUDIO_DSP_PARAM:
  272. {
  273. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  274. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  275. hpm_audio->audio_config.channels = caps->udata.config.channels;
  276. break;
  277. }
  278. case AUDIO_DSP_SAMPLERATE:
  279. {
  280. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  281. break;
  282. }
  283. case AUDIO_DSP_CHANNELS:
  284. {
  285. hpm_audio->audio_config.channels = caps->udata.config.channels;
  286. break;
  287. }
  288. case AUDIO_DSP_SAMPLEBITS:
  289. {
  290. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  291. break;
  292. }
  293. case AUDIO_PARM_I2S_DATA_LINE:
  294. {
  295. hpm_audio->transfer.data_line = caps->udata.value;
  296. break;
  297. }
  298. default:
  299. result = -RT_ERROR;
  300. break;
  301. }
  302. break;
  303. }
  304. case AUDIO_TYPE_INPUT:
  305. {
  306. switch(caps->sub_type)
  307. {
  308. case AUDIO_DSP_PARAM:
  309. {
  310. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  311. hpm_audio->audio_config.channels = caps->udata.config.channels;
  312. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  313. break;
  314. }
  315. case AUDIO_DSP_SAMPLERATE:
  316. {
  317. hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
  318. break;
  319. }
  320. case AUDIO_DSP_CHANNELS:
  321. {
  322. hpm_audio->audio_config.channels = caps->udata.config.channels;
  323. break;
  324. }
  325. case AUDIO_DSP_SAMPLEBITS:
  326. {
  327. hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
  328. break;
  329. }
  330. case AUDIO_PARM_I2S_DATA_LINE:
  331. {
  332. hpm_audio->transfer.data_line = caps->udata.value;
  333. break;
  334. }
  335. default:
  336. result = -RT_ERROR;
  337. break;
  338. }
  339. break;
  340. }
  341. default:
  342. break;
  343. }
  344. /* configure I2S transfer */
  345. if (hpm_audio->audio_config.channels == i2s_mono_left) {
  346. hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0);
  347. } else if (hpm_audio->audio_config.channels == i2s_mono_right) {
  348. hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(1);
  349. } else if(hpm_audio->audio_config.channels == 2) {
  350. hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0) | I2S_CHANNEL_SLOT_MASK(1);
  351. } else {
  352. LOG_E("I2S not support channels number %d.\n", hpm_audio->audio_config.channels);
  353. return -RT_ERROR;
  354. }
  355. hpm_audio->transfer.sample_rate = hpm_audio->audio_config.samplerate;
  356. /* i2s dma only support sample bit: 16 and 32 bits */
  357. assert(hpm_audio->audio_config.samplebits == 16 || hpm_audio->audio_config.samplebits == 32);
  358. hpm_audio->transfer.audio_depth = hpm_audio->audio_config.samplebits;
  359. /* Stop I2S transfer if the I2S needs to be re-configured */
  360. bool is_enabled = i2s_is_enabled(hpm_audio->base);
  361. i2s_disable(hpm_audio->base);
  362. i2s_reset_tx_rx(hpm_audio->base);
  363. if (is_enabled)
  364. {
  365. if (hpm_audio->i2s_state == hpm_i2s_state_read)
  366. {
  367. dma_abort_channel(hpm_audio->rx_dma_resource.base, 1u << hpm_audio->rx_dma_resource.channel);
  368. }
  369. if (hpm_audio->i2s_state == hpm_i2s_state_write)
  370. {
  371. dma_abort_channel(hpm_audio->tx_dma_resource.base, 1u << hpm_audio->tx_dma_resource.channel);
  372. }
  373. }
  374. if (status_success != i2s_config_transfer(hpm_audio->base, clock_get_frequency(hpm_audio->clk_name), &hpm_audio->transfer))
  375. {
  376. LOG_E("%s configure transfer failed.\n", hpm_audio->dev_name);
  377. return -RT_ERROR;
  378. }
  379. /* Restore I2S to previous state */
  380. if (is_enabled)
  381. {
  382. if (hpm_audio->i2s_state == hpm_i2s_state_read)
  383. {
  384. i2s_disable_rx_dma_request(hpm_audio->base);
  385. if (I2S_FIFO_SIZE != hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE)) {
  386. return -RT_ERROR;
  387. }
  388. i2s_enable_rx_dma_request(hpm_audio->base);
  389. }
  390. i2s_enable(hpm_audio->base);
  391. }
  392. return result;
  393. }
  394. static rt_err_t hpm_i2s_start(struct rt_audio_device* audio, int stream)
  395. {
  396. RT_ASSERT(audio != RT_NULL);
  397. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  398. /* request DMA resource for audio data transfer */
  399. if (stream == AUDIO_STREAM_REPLAY) {
  400. i2s_disable(hpm_audio->base);
  401. i2s_disable_tx_dma_request(hpm_audio->base);
  402. dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
  403. if (dma_mgr_request_resource(dma_resource) == status_success) {
  404. uint8_t dmamux_ch;
  405. dma_mgr_install_chn_tc_callback(dma_resource, i2s_tx_dma_tc_callback, hpm_audio);
  406. dma_mgr_enable_dma_irq_with_priority(dma_resource, 1);
  407. dmamux_ch = DMA_SOC_CHN_TO_DMAMUX_CHN(dma_resource->base, dma_resource->channel);
  408. dmamux_config(HPM_DMAMUX, dmamux_ch, hpm_audio->tx_dma_req, true);
  409. } else {
  410. LOG_E("no dma resource available for I2S TX transfer.\n");
  411. return -RT_ERROR;
  412. }
  413. i2s_reset_tx(hpm_audio->base); /* disable and reset tx */
  414. /* fill 2 dummy data, it is suitable for 1/2 channel of audio */
  415. if (i2s_fill_tx_dummy_data(hpm_audio->base, hpm_audio->transfer.data_line , 2) != status_success) {
  416. return -RT_ERROR;
  417. }
  418. rt_audio_tx_complete(audio);
  419. i2s_enable(hpm_audio->base);
  420. i2s_enable_tx_dma_request(hpm_audio->base);
  421. } else if (stream == AUDIO_STREAM_RECORD) {
  422. i2s_disable(hpm_audio->base);
  423. i2s_disable_rx_dma_request(hpm_audio->base);
  424. dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
  425. if (dma_mgr_request_resource(dma_resource) == status_success) {
  426. uint8_t dmamux_ch;
  427. dma_mgr_install_chn_tc_callback(dma_resource, i2s_rx_dma_tc_callback, hpm_audio);
  428. dma_mgr_enable_dma_irq_with_priority(dma_resource, 1);
  429. dmamux_ch = DMA_SOC_CHN_TO_DMAMUX_CHN(dma_resource->base, dma_resource->channel);
  430. dmamux_config(HPM_DMAMUX, dmamux_ch, hpm_audio->rx_dma_req, true);
  431. } else {
  432. LOG_E("no dma resource available for I2S RX transfer.\n");
  433. return -RT_ERROR;
  434. }
  435. i2s_reset_rx(hpm_audio->base); /* disable and reset rx */
  436. if (I2S_FIFO_SIZE != hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE)) {
  437. return -RT_ERROR;
  438. }
  439. i2s_enable(hpm_audio->base);
  440. i2s_enable_rx_dma_request(hpm_audio->base);
  441. } else {
  442. return -RT_ERROR;
  443. }
  444. return RT_EOK;
  445. }
  446. static rt_err_t hpm_i2s_stop(struct rt_audio_device* audio, int stream)
  447. {
  448. RT_ASSERT(audio != RT_NULL);
  449. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  450. i2s_disable(hpm_audio->base);
  451. if (stream == AUDIO_STREAM_REPLAY) {
  452. dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
  453. dma_abort_channel(dma_resource->base, 1u << dma_resource->channel);
  454. dma_mgr_release_resource(dma_resource);
  455. } else if (stream == AUDIO_STREAM_RECORD)
  456. {
  457. dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
  458. dma_abort_channel(dma_resource->base, 1u << dma_resource->channel);
  459. dma_mgr_release_resource(dma_resource);
  460. } else {
  461. return -RT_ERROR;
  462. }
  463. hpm_audio->i2s_state = hpm_i2s_state_stop;
  464. return RT_EOK;
  465. }
  466. static rt_ssize_t hpm_i2s_transmit(struct rt_audio_device* audio, const void* writeBuf, void* readBuf, rt_size_t size)
  467. {
  468. RT_ASSERT(audio != RT_NULL);
  469. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  470. /* i2s dma only support sample bit: 16 and 32 bits */
  471. uint8_t data_width;
  472. uint8_t data_shift_byte;
  473. if (hpm_audio->transfer.audio_depth == i2s_audio_depth_16_bits) {
  474. data_width = DMA_TRANSFER_WIDTH_HALF_WORD;
  475. data_shift_byte = 2U ; /* put 16bit data on high bit of register */
  476. } else {
  477. data_width = DMA_TRANSFER_WIDTH_WORD;
  478. data_shift_byte = 0U;
  479. }
  480. if(writeBuf != RT_NULL)
  481. {
  482. dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
  483. dma_channel_config_t ch_config = {0};
  484. dma_default_channel_config(dma_resource->base, &ch_config);
  485. ch_config.src_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)writeBuf);
  486. ch_config.dst_addr = (uint32_t)&hpm_audio->base->TXD[hpm_audio->transfer.data_line] + data_shift_byte;
  487. ch_config.src_width = data_width;
  488. ch_config.dst_width = data_width;
  489. ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
  490. ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
  491. ch_config.size_in_byte = size;
  492. ch_config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
  493. ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
  494. if (l1c_dc_is_enabled()) {
  495. /* cache writeback for sent buff */
  496. l1c_dc_writeback((uint32_t)writeBuf, size);
  497. }
  498. hpm_audio->i2s_state = hpm_i2s_state_write;
  499. if (status_success != dma_setup_channel(dma_resource->base, dma_resource->channel, &ch_config, true)) {
  500. LOG_E("dma setup channel failed\n");
  501. return -RT_ERROR;
  502. }
  503. } else if (readBuf != RT_NULL){
  504. dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
  505. dma_channel_config_t ch_config = {0};
  506. dma_default_channel_config(dma_resource->base, &ch_config);
  507. ch_config.src_addr = (uint32_t)&hpm_audio->base->RXD[hpm_audio->transfer.data_line] + data_shift_byte;
  508. ch_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)readBuf);
  509. ch_config.src_width = data_width;
  510. ch_config.dst_width = data_width;
  511. ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
  512. ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
  513. ch_config.size_in_byte = size;
  514. ch_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
  515. ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
  516. hpm_audio->i2s_state = hpm_i2s_state_read;
  517. if (status_success != dma_setup_channel(dma_resource->base, dma_resource->channel, &ch_config, true)) {
  518. LOG_E("dma setup channel failed\n");
  519. return -RT_ERROR;
  520. }
  521. if (l1c_dc_is_enabled()) {
  522. /* cache invalidate for receive buff */
  523. l1c_dc_invalidate((uint32_t)readBuf, size);
  524. }
  525. }
  526. return size;
  527. }
  528. static void hpm_i2s_buffer_info(struct rt_audio_device* audio, struct rt_audio_buf_info* info)
  529. {
  530. RT_ASSERT(audio != RT_NULL);
  531. struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
  532. /**
  533. * AUD_FIFO
  534. * +----------------+----------------+
  535. * | block1 | block2 |
  536. * +----------------+----------------+
  537. * \ block_size /
  538. */
  539. info->buffer = hpm_audio->tx_buff;
  540. info->total_size = I2S_FIFO_SIZE;
  541. info->block_size = I2S_FIFO_SIZE / 2;
  542. info->block_count = 2;
  543. }
  544. static struct rt_audio_ops hpm_i2s_ops =
  545. {
  546. .getcaps = hpm_i2s_getcaps,
  547. .configure = hpm_i2s_configure,
  548. .init = hpm_i2s_init,
  549. .start = hpm_i2s_start,
  550. .stop = hpm_i2s_stop,
  551. .transmit = hpm_i2s_transmit,
  552. .buffer_info = hpm_i2s_buffer_info,
  553. };
  554. int rt_hw_i2s_init(void)
  555. {
  556. rt_err_t ret = RT_EOK;
  557. for (uint32_t i = 0; i < sizeof(hpm_i2s_set) / sizeof(hpm_i2s_set[0]); i++) {
  558. hpm_i2s_set[i].audio.ops = &hpm_i2s_ops;
  559. ret = rt_audio_register(&hpm_i2s_set[i].audio, hpm_i2s_set[i].dev_name, RT_DEVICE_FLAG_RDWR, &hpm_i2s_set[i]);
  560. if (ret != RT_EOK)
  561. {
  562. LOG_E("rt audio %s register failed, status=%d\n", hpm_i2s_set[i].dev_name, ret);
  563. }
  564. }
  565. return RT_EOK;
  566. }
  567. INIT_DEVICE_EXPORT(rt_hw_i2s_init);
  568. #endif /* BSP_USING_I2S */