drv_i2s.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /*
  2. * Copyright (c) 2006-2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Email: opensource_embedded@phytium.com.cn
  7. *
  8. * Change Logs:
  9. * Date Author Notes
  10. * 2025-01-21 zhangyan first version
  11. *
  12. */
  13. #include <rtthread.h>
  14. #include <rtdevice.h>
  15. #include <drv_i2s.h>
  16. #include "fi2s.h"
  17. #include "fi2s_hw.h"
  18. #include "fddma.h"
  19. #include "fddma_hw.h"
  20. #include "fddma_bdl.h"
  21. #include "fdevice.h"
  22. #include "fes8336.h"
  23. #define DBG_TAG "drv.i2s"
  24. #define DBG_LVL DBG_INFO
  25. #include <rtdbg.h>
  26. #define PER_BUFFER_SIZE 2048
  27. #define TX_RX_BUF_LEN 2048
  28. static struct phytium_i2s_device i2s_dev0;
  29. extern FI2c master_device;
  30. static FEs8336Controller fes8336 =
  31. {
  32. .fes8336_device.name = "es8336",
  33. .dev_type = DEV_TYPE_MIO,
  34. .controller_id = FMIO14_ID,
  35. };
  36. static const u32 ddma_ctrl_id = FDDMA2_I2S_ID;
  37. static const u32 i2s_ctrl_id = FI2S0_ID;
  38. struct phytium_i2s_device
  39. {
  40. const char *name;
  41. struct rt_audio_device audio;
  42. struct rt_audio_configure config;
  43. FI2s i2s_ctrl;
  44. FI2sConfig i2s_config;
  45. FDdma ddmac;
  46. FDdmaConfig ddmac_config;
  47. rt_uint8_t *rx_fifo;
  48. FDdmaChanConfig rx_config;
  49. rt_uint8_t rx_channel; /* 接收通道为DDMA通道1 */
  50. rt_uint8_t volume;
  51. };
  52. static void FDdmaSetupInterrupt(FDdma *const instance)
  53. {
  54. FASSERT(instance);
  55. FDdmaConfig *config = &instance->config;
  56. rt_uint32_t cpu_id = rt_hw_cpu_id();
  57. rt_hw_interrupt_set_target_cpus(config->irq_num, cpu_id);
  58. rt_hw_interrupt_set_priority(config->irq_num, 16);
  59. /* register intr callback */
  60. rt_hw_interrupt_install(config->irq_num,
  61. FDdmaIrqHandler,
  62. instance,
  63. NULL);
  64. /* enable ddma0 irq */
  65. rt_hw_interrupt_umask(config->irq_num);
  66. return;
  67. }
  68. static FError FI2sEs8336Init(u32 word_length)
  69. {
  70. FError ret = FT_SUCCESS;
  71. u32 volumel = 0x1;
  72. FIOMuxInit();
  73. FIOPadSetI2sMux();
  74. ret = FEs8336DevRegister(&fes8336.fes8336_device);
  75. if (FT_SUCCESS != ret)
  76. {
  77. printf("ES8336 dev register failed.\r\n");
  78. return ret;
  79. }
  80. ret = FDeviceInit(&fes8336.fes8336_device);
  81. if (FT_SUCCESS != ret)
  82. {
  83. printf("ES8336 dev init failed.\r\n");
  84. return ret;
  85. }
  86. ret = FDeviceOpen(&fes8336.fes8336_device, FDEVICE_FLAG_RDWR);
  87. if (FT_SUCCESS != ret)
  88. {
  89. printf("ES8336 dev open failed.\r\n");
  90. return ret;
  91. }
  92. ret = FDeviceControl(&fes8336.fes8336_device, FES8336_SET_FORMAT, &word_length); /* 设置ES8336工作模式 */
  93. if (FT_SUCCESS != ret)
  94. {
  95. printf("Set the ES8336 word length failed.\r\n");
  96. return ret;
  97. }
  98. ret = FDeviceControl(&fes8336.fes8336_device, FES8336_SET_VOLUMEL, &volumel); /* 设置ES8336工作模式 */
  99. if (FT_SUCCESS != ret)
  100. {
  101. printf("Set the ES8336 volumel failed.\r\n");
  102. return ret;
  103. }
  104. return ret;
  105. }
  106. static FError FI2sRxInit(struct phytium_i2s_device *i2s_dev, u32 word_length)
  107. {
  108. FError ret = FI2S_SUCCESS;
  109. memset(&i2s_dev->i2s_ctrl, 0, sizeof(FI2s));
  110. memset(&i2s_dev->i2s_ctrl, 0, sizeof(FI2sConfig));
  111. i2s_dev->i2s_ctrl.data_config.word_length = word_length;
  112. i2s_dev->i2s_config = *FI2sLookupConfig(i2s_ctrl_id);
  113. ret = FI2sCfgInitialize(&i2s_dev->i2s_ctrl, &i2s_dev->i2s_config);
  114. if (FI2S_SUCCESS != ret)
  115. {
  116. printf("Init the i2s failed.\r\n");
  117. return ret;
  118. }
  119. FI2sClkOutDiv(&i2s_dev->i2s_ctrl, i2s_dev->config.samplerate);
  120. FI2sTxRxEnable(&i2s_dev->i2s_ctrl, TRUE); /* 模块使能 */
  121. return ret;
  122. }
  123. static FError FI2sRxDdmaInit(struct phytium_i2s_device *i2s_dev)
  124. {
  125. FError ret = FI2S_SUCCESS;
  126. i2s_dev->ddmac_config = *FDdmaLookupConfig(ddma_ctrl_id);
  127. ret = FDdmaCfgInitialize(&i2s_dev->ddmac, &i2s_dev->ddmac_config);
  128. if (FI2S_SUCCESS != ret)
  129. {
  130. printf("DDMA config initialization failed.\r\n");
  131. return ret;
  132. }
  133. return ret;
  134. }
  135. static FError FI2sDdmaDeviceRX(struct phytium_i2s_device *i2s_dev, u32 work_mode, const void *src, fsize_t total_bytes, fsize_t per_buff_len)
  136. {
  137. FError ret = FI2S_SUCCESS;
  138. fsize_t bdl_num = total_bytes / per_buff_len;
  139. rt_hw_cpu_dcache_clean((uintptr)src, total_bytes);
  140. for (u32 chan = FDDMA_CHAN_0; chan < FDDMA_NUM_OF_CHAN; chan++) /* 清除中断 */
  141. {
  142. FDdmaClearChanIrq(i2s_dev->ddmac_config.base_addr, chan, i2s_dev->ddmac_config.caps);
  143. }
  144. FDdmaBdlDesc *bdl_desc_list = rt_malloc_align(bdl_num * sizeof(FDdmaBdlDesc), FDDMA_BDL_ADDR_ALIGMENT); /* DDMA描述符首地址需128字节对齐 */
  145. if ((NULL == bdl_desc_list))
  146. {
  147. printf("FDdmaBdlDesc allocate failed.\r\n");
  148. return FDDMA_ERR_IS_USED;
  149. }
  150. memset(bdl_desc_list, 0, bdl_num * sizeof(FDdmaBdlDesc));
  151. FDdmaBdlDescConfig *bdl_desc_config = rt_calloc(1, bdl_num * sizeof(FDdmaBdlDescConfig));
  152. if ((NULL == bdl_desc_config))
  153. {
  154. printf("FDdmaBdlDescConfig allocate failed.\r\n");
  155. return FDDMA_ERR_IS_USED;
  156. }
  157. /* set BDL descriptors */
  158. for (fsize_t loop = 0; loop < bdl_num; loop++)
  159. {
  160. bdl_desc_config[loop].current_desc_num = loop;
  161. bdl_desc_config[loop].src_addr = (uintptr)(src + per_buff_len * loop);
  162. bdl_desc_config[loop].trans_length = per_buff_len;
  163. }
  164. bdl_desc_config[bdl_num -1].ioc = TRUE;
  165. /* set BDL descriptor list with descriptor configs */
  166. for (fsize_t loop = 0; loop < bdl_num; loop++)
  167. {
  168. FDdmaBDLSetDesc(bdl_desc_list, &bdl_desc_config[loop]);
  169. }
  170. i2s_dev->rx_config.slave_id = 0U,
  171. i2s_dev->rx_config.req_mode = AUDIO_PCM_STREAM_CAPTURE;
  172. i2s_dev->rx_config.ddr_addr = (uintptr)src;
  173. i2s_dev->rx_config.dev_addr = i2s_dev->i2s_config.base_addr + FI2S_RXDMA ;
  174. i2s_dev->rx_config.trans_len = total_bytes;
  175. i2s_dev->rx_config.timeout = 0xffff,
  176. i2s_dev->rx_config.first_desc_addr = (uintptr)bdl_desc_list;
  177. i2s_dev->rx_config.valid_desc_num = bdl_num;
  178. ret = FDdmaChanBdlConfigure(&i2s_dev->ddmac, i2s_dev->rx_channel, &i2s_dev->rx_config);
  179. if (ret != FI2S_SUCCESS)
  180. {
  181. printf("DDMA BDL configure failer.\r\n");
  182. return ret;
  183. }
  184. rt_free(bdl_desc_config);
  185. return ret;
  186. }
  187. void dma_transfer_callback(void *args)
  188. {
  189. #if defined(RT_USING_I2S0)
  190. rt_audio_rx_done(&i2s_dev0.audio, &i2s_dev0.rx_fifo[0], TX_RX_BUF_LEN);
  191. #endif
  192. }
  193. static rt_err_t i2s_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  194. {
  195. rt_err_t result = RT_EOK;
  196. struct phytium_i2s_device *i2s_dev;
  197. RT_ASSERT(audio != RT_NULL);
  198. i2s_dev = (struct phytium_i2s_device *)audio->parent.user_data;
  199. switch (caps->main_type)
  200. {
  201. case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */
  202. {
  203. switch (caps->sub_type)
  204. {
  205. case AUDIO_TYPE_QUERY:
  206. caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER;
  207. break;
  208. default:
  209. result = -RT_ERROR;
  210. break;
  211. }
  212. break;
  213. }
  214. case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
  215. {
  216. switch (caps->sub_type)
  217. {
  218. case AUDIO_DSP_PARAM:
  219. caps->udata.config.samplerate = i2s_dev->config.samplerate;
  220. caps->udata.config.channels = i2s_dev->config.channels;
  221. caps->udata.config.samplebits = i2s_dev->config.samplebits;
  222. break;
  223. case AUDIO_DSP_SAMPLERATE:
  224. caps->udata.config.samplerate = i2s_dev->config.samplerate;
  225. break;
  226. case AUDIO_DSP_CHANNELS:
  227. caps->udata.config.channels = i2s_dev->config.channels;
  228. break;
  229. case AUDIO_DSP_SAMPLEBITS:
  230. caps->udata.config.samplebits = i2s_dev->config.samplebits;
  231. break;
  232. default:
  233. result = -RT_ERROR;
  234. break;
  235. }
  236. break;
  237. }
  238. case AUDIO_TYPE_MIXER: /* report the Mixer Units */
  239. {
  240. switch (caps->sub_type)
  241. {
  242. case AUDIO_MIXER_QUERY:
  243. caps->udata.mask = AUDIO_MIXER_VOLUME;
  244. break;
  245. case AUDIO_MIXER_VOLUME:
  246. caps->udata.value = i2s_dev->volume;
  247. break;
  248. default:
  249. result = -RT_ERROR;
  250. break;
  251. }
  252. break;
  253. }
  254. default:
  255. result = -RT_ERROR;
  256. break;
  257. }
  258. return result;
  259. }
  260. static rt_err_t i2s_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  261. {
  262. rt_err_t result = RT_EOK;
  263. struct phytium_i2s_device *i2s_dev;
  264. struct rt_audio_replay *replay;
  265. RT_ASSERT(audio != RT_NULL);
  266. i2s_dev = (struct phytium_i2s_device *)audio->parent.user_data;
  267. switch (caps->main_type)
  268. {
  269. case AUDIO_TYPE_INPUT:
  270. {
  271. switch (caps->sub_type)
  272. {
  273. case AUDIO_DSP_PARAM:
  274. {
  275. struct rt_audio_configure config = caps->udata.config;
  276. i2s_dev->config.channels = config.channels;
  277. i2s_dev->config.samplebits = config.samplebits;
  278. i2s_dev->config.samplerate = config.samplerate;
  279. }
  280. default:
  281. result = -RT_ERROR;
  282. break;
  283. }
  284. break;
  285. }
  286. default:
  287. break;
  288. }
  289. return result;
  290. }
  291. static rt_err_t i2s_init(struct rt_audio_device *audio)
  292. {
  293. struct phytium_i2s_device *i2s_dev;
  294. RT_ASSERT(audio != RT_NULL);
  295. i2s_dev = (struct phytium_i2s_device *)audio->parent.user_data;
  296. FError ret = FT_SUCCESS;
  297. u32 word_length = i2s_dev->config.samplebits; /* 16-bits word length */
  298. FI2sEs8336Init(word_length);
  299. if (FT_SUCCESS != ret)
  300. {
  301. printf("Init the escodec failed.\r\n");
  302. return ret;
  303. }
  304. ret = FI2sRxDdmaInit(i2s_dev);
  305. if (FT_SUCCESS != ret)
  306. {
  307. printf("Init DDMA-2 failed.\r\n");
  308. return ret;
  309. }
  310. ret = FI2sRxInit(i2s_dev, word_length);
  311. if (FI2S_SUCCESS != ret)
  312. {
  313. printf("Init the I2S failed.\r\n");
  314. return ret;
  315. }
  316. FDdmaSetupInterrupt(&i2s_dev->ddmac);
  317. FDdmaRegisterChanEvtHandler(&i2s_dev->ddmac, i2s_dev->rx_channel, FDDMA_CHAN_EVT_REQ_DONE, dma_transfer_callback, (void *)i2s_dev);
  318. return ret;
  319. }
  320. static rt_err_t i2s_start(struct rt_audio_device *audio, int stream)
  321. {
  322. struct phytium_i2s_device *i2s_dev;
  323. RT_ASSERT(audio != RT_NULL);
  324. i2s_dev = (struct phytium_i2s_device *)audio->parent.user_data;
  325. if (stream == AUDIO_STREAM_REPLAY)
  326. {
  327. }
  328. else if(stream == AUDIO_STREAM_RECORD)
  329. {
  330. FI2sDdmaDeviceRX(i2s_dev, AUDIO_PCM_STREAM_CAPTURE, &i2s_dev->rx_fifo[0], TX_RX_BUF_LEN, PER_BUFFER_SIZE);
  331. FDdmaChanActive(&i2s_dev->ddmac, i2s_dev->rx_channel);
  332. }
  333. FDdmaStart(&i2s_dev->ddmac);
  334. return RT_EOK;
  335. }
  336. static rt_err_t i2s_stop(struct rt_audio_device *audio, int stream)
  337. {
  338. struct phytium_i2s_device *i2s_dev;
  339. RT_ASSERT(audio != RT_NULL);
  340. i2s_dev = (struct phytium_i2s_device *)audio->parent.user_data;
  341. return RT_EOK;
  342. }
  343. static struct rt_audio_ops i2s_ops =
  344. {
  345. .getcaps = i2s_getcaps,
  346. .configure = i2s_configure,
  347. .init = i2s_init,
  348. .start = i2s_start,
  349. .stop = i2s_stop,
  350. .transmit = NULL,
  351. .buffer_info = NULL,
  352. };
  353. static int i2s_controller_init(struct phytium_i2s_device *i2s_dev)
  354. {
  355. struct rt_audio_device *audio = &i2s_dev->audio;
  356. i2s_dev->rx_fifo = rt_calloc(1, TX_RX_BUF_LEN);
  357. if (i2s_dev->rx_fifo == RT_NULL)
  358. {
  359. return -RT_ENOMEM;
  360. }
  361. i2s_dev->audio.ops = &i2s_ops;
  362. int ret = rt_audio_register(audio, i2s_dev->name, RT_DEVICE_FLAG_RDONLY, (void *)i2s_dev);
  363. RT_ASSERT(RT_EOK == ret);
  364. LOG_D("i2s_controller_init i2s bus reg success. \n");
  365. return ret;
  366. }
  367. int rt_hw_i2s_init(void)
  368. {
  369. #if defined(RT_USING_I2S0)
  370. i2s_dev0.name = "I2S0";
  371. i2s_dev0.i2s_ctrl.config.instance_id = FI2S0_ID;
  372. i2s_dev0.config.channels = 1;
  373. i2s_dev0.config.samplerate = RT_I2S_SAMPLERATE;
  374. i2s_dev0.config.samplebits = RT_I2S_SAMPLEBITS;
  375. i2s_controller_init(&i2s_dev0);
  376. #endif
  377. return RT_EOK;
  378. }
  379. INIT_DEVICE_EXPORT(rt_hw_i2s_init);