phy_audio_spdiftx.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright (c) 2020 Actions Semiconductor Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @file
  8. * @brief Audio SPDIFTX physical implementation
  9. */
  10. /*
  11. * Features
  12. * - 32 level * 24bits FIFO
  13. * - Support multiple devices (DAC + I2STX0 + SPDIFTX)
  14. * - Sample rate support 32k/44.1k/48k/88.2k/96k/176.4k/192k
  15. */
  16. #include <kernel.h>
  17. #include <device.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <soc.h>
  21. #include <board.h>
  22. #include <board_cfg.h>
  23. #include "../phy_audio_common.h"
  24. #include "../audio_acts_utils.h"
  25. #include <drivers/audio/audio_out.h>
  26. #include <logging/log.h>
  27. LOG_MODULE_REGISTER(spdiftx0, CONFIG_LOG_DEFAULT_LEVEL);
  28. /***************************************************************************************************
  29. * SPDIFTX_CTL
  30. */
  31. #define SPDIFT0_CTL_FIFO_SEL_SHIFT (3)
  32. #define SPDIFT0_CTL_FIFO_SEL_MASK (0x3 << SPDIFT0_CTL_FIFO_SEL_SHIFT)
  33. #define SPDIFT0_CTL_FIFO_SEL(x) ((x) << SPDIFT0_CTL_FIFO_SEL_SHIFT) /* 0: DAC FIFO1; 1: I2STX FIFO 2: DAC FIFO0 + DAC FIFO1 */
  34. #define SPDIFT0_CTL_VALIDITY BIT(2) /* validity flag */
  35. #define SPDIFT0_CTL_SPD_DIS_CTL BIT(1) /* 0: close spdif immediately; 1: close spidf after right channel has stopped */
  36. #define SPDIFT0_CTL_SPDEN BIT(0) /* SPDIFTX Enable */
  37. /***************************************************************************************************
  38. * SPDIFTX_CSL
  39. */
  40. #define SPDIFT0_CSL_SPDCSL_E (31) /* SPDIFTX Channel State Low */
  41. #define SPDIFT0_CSL_SPDCSL_SHIFT (0)
  42. #define SPDIFT0_CSL_SPDCSL_MASK (0xFFFFFFFF << SPDIFT0_CSL_SPDCSL_SHIFT)
  43. /***************************************************************************************************
  44. * SPDIFTX_CSH
  45. */
  46. #define SPDIFT0_CSH_SPDCSH_E (15) /* SPDIFTX Channel State High */
  47. #define SPDIFT0_CSH_SPDCSH_SHIFT (0)
  48. #define SPDIFT0_CSH_SPDCSH_MASK (0xFFFF << SPDIFT0_CSH_SPDCSH_SHIFT)
  49. /***************************************************************************************************
  50. * SPDIFTX FEATURES CONFIGURATION
  51. */
  52. #define SPDTX_CTL_SPDEN BIT(0)
  53. #define SPDTX_CTL_SPD_DIS_CTL BIT(1)
  54. #define SPDTX_CTL_VALIDITY BIT(2)
  55. /* test spdif channel state */
  56. #define TEST_SPDTX_CSL (0x12345678)
  57. #define TEST_SPDTX_CSH (0x9abc)
  58. /* spdiftx FIFO source selection */
  59. #define SPDIFTX_FIFO_SRC_DACFIFO1 (0)
  60. #define SPDIFTX_FIFO_SRC_I2STXFIFO (1)
  61. #define SPDIFTX_FIFO_SRC_DACFIFO0_1 (2) /* Only used in linkage with DAC mode */
  62. /*
  63. * enum a_spdiftx_clksrc_e
  64. * @brief The SPDIFTX clock source selection
  65. */
  66. typedef enum {
  67. CLK_SRCTX_DAC_256FS_DIV2 = 0, /* DAC_256FS_CLK / 2 */
  68. CLK_SRCTX_I2STX_MCLK, /* I2STX_MCLK */
  69. CLK_SRCTX_I2STX_MCLK_DIV2, /* I2STX_MCLK / 2 */
  70. CLK_SRCTX_SPDTXCLK /* SPDIFTX CLK */
  71. } a_spdiftx_clksrc_e;
  72. /*
  73. * @struct acts_audio_spdiftx
  74. * @brief SPDIFTX controller hardware register
  75. */
  76. struct acts_audio_spdiftx {
  77. volatile uint32_t ctl; /* SPDIFTX Control */
  78. volatile uint32_t csl; /* SPDIFTX Channel State Low */
  79. volatile uint32_t csh; /* SPDIFTX Channel State High */
  80. };
  81. /**
  82. * union phy_spdiftx_features
  83. * @brief The infomation from DTS to control the SPDIFTX features to enable or nor.
  84. */
  85. typedef union {
  86. uint8_t raw;
  87. struct {
  88. uint8_t clk_i2stx_div2 : 1; /* SPDIFTX clock from I2STX div2 clock */
  89. } v;
  90. } phy_spdiftx_features;
  91. /**
  92. * struct phy_spdiftx_drv_data
  93. * @brief The software related data that used by physical spdiftx driver.
  94. */
  95. struct phy_spdiftx_drv_data {
  96. uint8_t clksrc; /* spdiftx clock source selection */
  97. uint8_t fifo_sel; /* Record the used FIFO */
  98. uint8_t linkage_mode : 1; /* The flag of linkage with i2stx */
  99. };
  100. /**
  101. * struct phy_spdiftx_config_data
  102. * @brief The hardware related data that used by physical spdiftx driver.
  103. */
  104. struct phy_spdiftx_config_data {
  105. uint32_t reg_base; /* SPDIFTX controller register base address */
  106. uint8_t clk_id; /* SPDIFTX devclk id */
  107. uint8_t rst_id; /* SPDIFTX reset id */
  108. phy_spdiftx_features features; /* SPDIFTX features */
  109. };
  110. /* @brief get the base address of SPDIFTX register */
  111. static inline struct acts_audio_spdiftx *get_spdiftx_reg_base(struct device *dev)
  112. {
  113. const struct phy_spdiftx_config_data *cfg = dev->config;
  114. return (struct acts_audio_spdiftx *)cfg->reg_base;
  115. }
  116. /* @brief dump spdiftx controller register */
  117. static void spdiftx_dump_register(struct device *dev)
  118. {
  119. struct acts_audio_spdiftx *spdiftx_base = get_spdiftx_reg_base(dev);
  120. LOG_INF("** spdiftx contoller regster **");
  121. LOG_INF(" BASE: %08x", (uint32_t)spdiftx_base);
  122. LOG_INF(" SPDIFTX_CTL: %08x", spdiftx_base->ctl);
  123. LOG_INF(" SPDIFTX_CSL: %08x", spdiftx_base->csl);
  124. LOG_INF(" SPDIFTX_CSH: %08x", spdiftx_base->csh);
  125. LOG_INF(" AUDIOPLL0_CTL: %08x", sys_read32(AUDIO_PLL0_CTL));
  126. LOG_INF(" AUDIOPLL1_CTL: %08x", sys_read32(AUDIO_PLL1_CTL));
  127. LOG_INF(" CMU_DACCLK: %08x", sys_read32(CMU_DACCLK));
  128. LOG_INF(" CMU_I2STXCLK: %08x", sys_read32(CMU_I2STXCLK));
  129. LOG_INF(" CMU_SPDIFTX: %08x", sys_read32(CMU_SPDIFTXCLK));
  130. }
  131. /* @brief SPDIFTX sample rate config */
  132. static int spdiftx_sample_rate_set(struct device *dev, u16_t sr_khz,
  133. a_spdiftx_clksrc_e clksrc, bool direct_set)
  134. {
  135. int ret;
  136. uint8_t pre_div, clk_div, series, pll_index;
  137. uint32_t reg, reg1;
  138. ARG_UNUSED(dev);
  139. reg = sys_read32(CMU_SPDIFTXCLK) & ~CMU_SPDIFTXCLK_SPDIFTXCLKSRC_MASK;
  140. if (direct_set)
  141. goto out;
  142. /* Get audio PLL setting */
  143. if (CLK_SRCTX_I2STX_MCLK == clksrc) {
  144. ret = audio_get_pll_setting_i2s(sr_khz, MCLK_128FS, &clk_div, &series);
  145. } else {
  146. if (CLK_SRCTX_DAC_256FS_DIV2 == clksrc || (CLK_SRCTX_I2STX_MCLK_DIV2 == clksrc))
  147. ret = audio_get_pll_setting(sr_khz, MCLK_256FS, &pre_div, &clk_div, &series);
  148. else
  149. ret = audio_get_pll_setting(sr_khz, MCLK_128FS, &pre_div, &clk_div, &series);
  150. }
  151. if (ret) {
  152. LOG_ERR("get pll setting error:%d", ret);
  153. return ret;
  154. }
  155. /* Check the pll usage and then config */
  156. ret = audio_pll_check_config(series, &pll_index);
  157. if (ret) {
  158. LOG_ERR("check pll config error:%d", ret);
  159. return ret;
  160. }
  161. if (CLK_SRCTX_DAC_256FS_DIV2 == clksrc) {
  162. reg1 = sys_read32(CMU_DACCLK) & ~0x1FF;
  163. /* Select pll0 or pll1 */
  164. reg1 |= (pll_index & 0x1) << CMU_DACCLK_DACCLKSRC;
  165. reg1 |= (pre_div << CMU_DACCLK_DACCLKPREDIV) | (clk_div << CMU_DACCLK_DACCLKDIV_SHIFT);
  166. sys_write32(reg1, CMU_DACCLK);
  167. } else if ((CLK_SRCTX_I2STX_MCLK == clksrc)
  168. || (CLK_SRCTX_I2STX_MCLK_DIV2 == clksrc)) {
  169. reg1 = sys_read32(CMU_I2STXCLK) & ~0xFFFF;
  170. /* Select pll0 or pll1 */
  171. reg1 |= (pll_index & 0x1) << CMU_I2STXCLK_I2SG0CLKSRC;
  172. reg1 |= clk_div << CMU_I2STXCLK_I2SG0CLKDIV_SHIFT;
  173. sys_write32(reg1, CMU_I2STXCLK);
  174. } else if (CLK_SRCTX_SPDTXCLK == clksrc) {
  175. reg = sys_read32(CMU_SPDIFTXCLK) & ~0x3FFF;
  176. reg |= 3 << CMU_SPDIFTXCLK_SPDIFTXCLKSRC_SHIFT;
  177. reg |= (pll_index & 0x1) << CMU_SPDIFTXCLK_SPDTXCLKSRC;
  178. reg |= (pre_div << CMU_SPDIFTXCLK_SPDTXCLKPREDIV) | (clk_div << CMU_SPDIFTXCLK_SPDTXCLKDIV_SHIFT);
  179. } else {
  180. LOG_ERR("Invalid spdiftx clk source %d", clksrc);
  181. return -EINVAL;
  182. }
  183. out:
  184. sys_write32(reg | (clksrc << CMU_SPDIFTXCLK_SPDIFTXCLKSRC_SHIFT), CMU_SPDIFTXCLK);
  185. return 0;
  186. }
  187. /* @brief Get the sample rate from the SPDIFTX config */
  188. static int spdiftx_sample_rate_get(struct device *dev)
  189. {
  190. uint8_t pre_div, clk_div, pll_index;
  191. uint32_t reg = sys_read32(CMU_SPDIFTXCLK);
  192. uint8_t clk_src;
  193. ARG_UNUSED(dev);
  194. clk_src = (reg & CMU_SPDIFTXCLK_SPDIFTXCLKSRC_MASK) >> CMU_SPDIFTXCLK_SPDIFTXCLKSRC_SHIFT;
  195. if ((clk_src == CLK_SRCTX_I2STX_MCLK) || (clk_src == CLK_SRCTX_I2STX_MCLK_DIV2)) {
  196. reg = sys_read32(CMU_I2STXCLK);
  197. clk_div = reg & 0xF;
  198. pll_index = (reg >> CMU_I2STXCLK_I2SG0CLKSRC) & 0x1;
  199. return audio_get_pll_sample_rate_i2s(MCLK_128FS, clk_div, pll_index);
  200. } else if (clk_src == CLK_SRCTX_DAC_256FS_DIV2) {
  201. reg = sys_read32(CMU_DACCLK);
  202. pll_index = (reg >> CMU_DACCLK_DACCLKSRC) & 0x1;
  203. pre_div = (reg & (1 << CMU_DACCLK_DACCLKPREDIV)) >> CMU_DACCLK_DACCLKPREDIV;
  204. clk_div = reg & CMU_DACCLK_DACCLKDIV_MASK;
  205. } else {
  206. pll_index = (reg & (1 << CMU_SPDIFTXCLK_SPDTXCLKSRC)) >> CMU_SPDIFTXCLK_SPDTXCLKSRC;
  207. pre_div = (reg & (1 << CMU_SPDIFTXCLK_SPDTXCLKPREDIV)) >> CMU_SPDIFTXCLK_SPDTXCLKPREDIV;
  208. clk_div = reg & CMU_SPDIFTXCLK_SPDTXCLKDIV_MASK;
  209. }
  210. return audio_get_pll_sample_rate(MCLK_128FS, pre_div, clk_div, pll_index);
  211. }
  212. /* @brief Get the AUDIO_PLL APS used by SPDIFTX */
  213. static int spdiftx_get_pll_aps(struct device *dev)
  214. {
  215. uint32_t reg;
  216. uint8_t pll_index;
  217. ARG_UNUSED(dev);
  218. reg = sys_read32(CMU_SPDIFTXCLK);
  219. pll_index = (reg & (1 << CMU_SPDIFTXCLK_SPDTXCLKSRC)) >> CMU_SPDIFTXCLK_SPDTXCLKSRC;
  220. return audio_pll_get_aps((a_pll_type_e)pll_index);
  221. }
  222. /* @brief Set the AUDIO_PLL APS used by SPDIFTX */
  223. static int spdiftx_set_pll_aps(struct device *dev, audio_aps_level_e level)
  224. {
  225. uint32_t reg;
  226. uint8_t pll_index;
  227. ARG_UNUSED(dev);
  228. reg = sys_read32(CMU_SPDIFTXCLK);
  229. pll_index = (reg & (1 << CMU_SPDIFTXCLK_SPDTXCLKSRC)) >> CMU_SPDIFTXCLK_SPDTXCLKSRC;
  230. return audio_pll_set_aps((a_pll_type_e)pll_index, level);
  231. }
  232. /* @brief Config the SPDIFTX FIFO source */
  233. static int phy_spdiftx_fifo_config(struct device *dev, uint8_t fifo_sel)
  234. {
  235. struct acts_audio_spdiftx *spdiftx_base = get_spdiftx_reg_base(dev);
  236. uint32_t reg = spdiftx_base->ctl & ~SPDIFT0_CTL_FIFO_SEL_MASK;
  237. if (SPDIFTX_FIFO_SRC_DACFIFO0_1 == fifo_sel)
  238. reg |= SPDIFT0_CTL_FIFO_SEL(2);
  239. else if (SPDIFTX_FIFO_SRC_DACFIFO1 == fifo_sel)
  240. reg |= SPDIFT0_CTL_FIFO_SEL(0);
  241. else if (SPDIFTX_FIFO_SRC_I2STXFIFO == fifo_sel)
  242. reg |= SPDIFT0_CTL_FIFO_SEL(1);
  243. else
  244. return -EINVAL;
  245. spdiftx_base->ctl = reg;
  246. return 0;
  247. }
  248. /* @brief Set the SPDIFTX channel status */
  249. static void phy_spdiftx_channel_status_set(struct device *dev, audio_spdif_ch_status_t *status)
  250. {
  251. struct acts_audio_spdiftx *spdiftx_base = get_spdiftx_reg_base(dev);
  252. if (status) {
  253. spdiftx_base->csl = status->csl;
  254. spdiftx_base->csh = (uint32_t)status->csh;
  255. } else {
  256. spdiftx_base->csl = TEST_SPDTX_CSL;
  257. spdiftx_base->csh = TEST_SPDTX_CSH;
  258. }
  259. }
  260. /* @brief Get the SPDIFTX channel status */
  261. static void phy_spdiftx_channel_status_get(struct device *dev, audio_spdif_ch_status_t *status)
  262. {
  263. struct acts_audio_spdiftx *spdiftx_base = get_spdiftx_reg_base(dev);
  264. if (status) {
  265. status->csl = spdiftx_base->csl;
  266. status->csh = (uint16_t)spdiftx_base->csh;
  267. }
  268. }
  269. /* @brief physical spdiftx device enable */
  270. static int phy_spdiftx_enable(struct device *dev, void *param)
  271. {
  272. const struct phy_spdiftx_config_data *cfg = dev->config;
  273. struct acts_audio_spdiftx *spdiftx_base = get_spdiftx_reg_base(dev);
  274. struct phy_spdiftx_drv_data *data = dev->data;
  275. aout_param_t *out_param = (aout_param_t *)param;
  276. bool is_linkmode;
  277. a_spdiftx_clksrc_e clksrc;
  278. int ret;
  279. uint8_t sr;
  280. struct board_pinmux_info pinmux_info;
  281. board_get_spdiftx0_pinmux_info(&pinmux_info);
  282. if (!out_param) {
  283. LOG_ERR("Invalid parameters");
  284. return -EINVAL;
  285. }
  286. sr = out_param->sample_rate;
  287. if (out_param->channel_type & AUDIO_CHANNEL_DAC) {
  288. LOG_INF("Enable linkage with DAC");
  289. clksrc = CLK_SRCTX_DAC_256FS_DIV2;
  290. data->fifo_sel = SPDIFTX_FIFO_SRC_DACFIFO0_1;
  291. is_linkmode = true;
  292. } else if (out_param->channel_type & AUDIO_CHANNEL_I2STX) {
  293. LOG_INF("Enable linkage with I2STX");
  294. /* SPDIFTX uses 128FS but I2STX uses 256FS */
  295. clksrc = CLK_SRCTX_I2STX_MCLK_DIV2,
  296. data->fifo_sel = SPDIFTX_FIFO_SRC_I2STXFIFO;
  297. if ((out_param->outfifo_type == AOUT_FIFO_DAC0)
  298. || (out_param->outfifo_type == AOUT_FIFO_DAC1)) {
  299. clksrc = CLK_SRCTX_DAC_256FS_DIV2;
  300. data->fifo_sel = SPDIFTX_FIFO_SRC_DACFIFO0_1;
  301. }
  302. is_linkmode = true;
  303. } else {
  304. /* DAC FIFO1 depends on DAC FIFO0 on working */
  305. if ((out_param->outfifo_type == AOUT_FIFO_DAC0)
  306. || (out_param->outfifo_type == AOUT_FIFO_DAC1)) {
  307. clksrc = CLK_SRCTX_DAC_256FS_DIV2;
  308. data->fifo_sel = SPDIFTX_FIFO_SRC_DACFIFO0_1;
  309. } else if (out_param->outfifo_type == AOUT_FIFO_DAC1_ONLY_SPDIF) {
  310. clksrc = CLK_SRCTX_SPDTXCLK;
  311. data->fifo_sel = SPDIFTX_FIFO_SRC_DACFIFO1;
  312. } else if (out_param->outfifo_type == AOUT_FIFO_I2STX0) {
  313. if (PHY_DEV_FEATURE(clk_i2stx_div2))
  314. clksrc = CLK_SRCTX_I2STX_MCLK_DIV2;
  315. else
  316. clksrc = CLK_SRCTX_I2STX_MCLK;
  317. data->fifo_sel = SPDIFTX_FIFO_SRC_I2STXFIFO;
  318. } else {
  319. LOG_ERR("Invalid fifo type:%d", out_param->outfifo_type);
  320. return -EINVAL;
  321. }
  322. is_linkmode = false;
  323. }
  324. data->clksrc = clksrc;
  325. data->linkage_mode = is_linkmode;
  326. /* Config the spdiftx pin state */
  327. acts_pinmux_setup_pins(pinmux_info.pins_config, pinmux_info.pins_num);
  328. /* spdiftx clock enable */
  329. acts_clock_peripheral_enable(cfg->clk_id);
  330. ret = spdiftx_sample_rate_set(dev, sr, clksrc,
  331. is_linkmode ? true : false);
  332. if (ret) {
  333. LOG_ERR("Failed to set spdiftx sample rate (err=%d)", ret);
  334. return ret;
  335. }
  336. ret = phy_spdiftx_fifo_config(dev, data->fifo_sel);
  337. if (ret) {
  338. LOG_ERR("Failed to config spidftx fifo %d", out_param->outfifo_type);
  339. return ret;
  340. }
  341. phy_spdiftx_channel_status_set(dev, out_param->spdiftx_setting->status);
  342. if (!is_linkmode)
  343. spdiftx_base->ctl |= SPDTX_CTL_SPDEN;
  344. return 0;
  345. }
  346. static int phy_spdiftx_disable(struct device *dev, void *param)
  347. {
  348. const struct phy_spdiftx_config_data *cfg = dev->config;
  349. struct acts_audio_spdiftx *spdiftx_base = get_spdiftx_reg_base(dev);
  350. struct phy_spdiftx_drv_data *data = dev->data;
  351. uint8_t i;
  352. struct board_pinmux_info pinmux_info;
  353. board_get_spdiftx0_pinmux_info(&pinmux_info);
  354. /* set the spdiftx pin state to gpio to save power */
  355. for (i = 0; i < pinmux_info.pins_num; i++)
  356. acts_pinmux_set(pinmux_info.pins_config[i].pin_num, 0);
  357. spdiftx_base->ctl &= (~SPDTX_CTL_SPDEN);
  358. /* spdif tx clock gating disable */
  359. acts_clock_peripheral_disable(cfg->clk_id);
  360. data->fifo_sel = AUDIO_FIFO_INVALID_TYPE;
  361. return 0;
  362. }
  363. static int phy_spdiftx_ioctl(struct device *dev, uint32_t cmd, void *param)
  364. {
  365. int ret = 0;
  366. struct phy_spdiftx_drv_data *data = dev->data;
  367. switch (cmd) {
  368. case PHY_CMD_DUMP_REGS:
  369. {
  370. spdiftx_dump_register(dev);
  371. break;
  372. }
  373. case AOUT_CMD_GET_SAMPLERATE:
  374. {
  375. ret = spdiftx_sample_rate_get(dev);
  376. if (ret < 0) {
  377. LOG_ERR("Failed to get SPDIFTX sample rate (err=%d)", ret);
  378. return ret;
  379. }
  380. *(audio_sr_sel_e *)param = (audio_sr_sel_e)ret;
  381. ret = 0;
  382. break;
  383. }
  384. case AOUT_CMD_SET_SAMPLERATE:
  385. {
  386. audio_sr_sel_e val = *(audio_sr_sel_e *)param;
  387. ret = spdiftx_sample_rate_set(dev, val, data->clksrc, data->linkage_mode ? true: false);
  388. if (ret) {
  389. LOG_ERR("Failed to set I2STX sample rate (err=%d)", ret);
  390. return ret;
  391. }
  392. break;
  393. }
  394. case AOUT_CMD_GET_APS:
  395. {
  396. ret = spdiftx_get_pll_aps(dev);
  397. if (ret < 0) {
  398. LOG_ERR("Failed to get audio pll APS (err=%d)", ret);
  399. return ret;
  400. }
  401. *(audio_aps_level_e *)param = (audio_aps_level_e)ret;
  402. ret = 0;
  403. break;
  404. }
  405. case AOUT_CMD_SET_APS:
  406. {
  407. audio_aps_level_e level = *(audio_aps_level_e *)param;
  408. ret = spdiftx_set_pll_aps(dev, level);
  409. if (ret) {
  410. LOG_ERR("Failed to set audio pll APS (err=%d)", ret);
  411. return ret;
  412. }
  413. break;
  414. }
  415. case AOUT_CMD_SPDIF_SET_CHANNEL_STATUS:
  416. {
  417. audio_spdif_ch_status_t *status = (audio_spdif_ch_status_t *)param;
  418. if (!status) {
  419. LOG_ERR("Invalid parameters");
  420. return -EINVAL;
  421. }
  422. phy_spdiftx_channel_status_set(dev, status);
  423. break;
  424. }
  425. case AOUT_CMD_SPDIF_GET_CHANNEL_STATUS:
  426. {
  427. phy_spdiftx_channel_status_get(dev, (audio_spdif_ch_status_t *)param);
  428. break;
  429. }
  430. default:
  431. LOG_ERR("Unsupport command %d", cmd);
  432. return -ENOTSUP;
  433. }
  434. return ret;
  435. }
  436. const struct phy_audio_driver_api phy_spdiftx_drv_api = {
  437. .audio_enable = phy_spdiftx_enable,
  438. .audio_disable = phy_spdiftx_disable,
  439. .audio_ioctl = phy_spdiftx_ioctl
  440. };
  441. /* dump spdiftx device tree infomation */
  442. static void __spdiftx_dt_dump_info(const struct phy_spdiftx_config_data *cfg)
  443. {
  444. #if (PHY_DEV_SHOW_DT_INFO == 1)
  445. LOG_INF("** SPDIFTX BASIC INFO **");
  446. LOG_INF(" BASE: %08x", cfg->reg_base);
  447. LOG_INF("CLK-ID: %08x", cfg->clk_id);
  448. LOG_INF("RST-ID: %08x", cfg->rst_id);
  449. LOG_INF("** SPDIFTX FEATURES **");
  450. LOG_INF("CLK-I2STX-DIV2: %d", PHY_DEV_FEATURE(clk_i2stx_div2));
  451. #endif
  452. }
  453. static int phy_spdiftx_init(const struct device *dev)
  454. {
  455. const struct phy_spdiftx_config_data *cfg = dev->config;
  456. struct phy_spdiftx_drv_data *data = dev->data;
  457. memset(data, 0, sizeof(struct phy_spdiftx_drv_data));
  458. __spdiftx_dt_dump_info(cfg);
  459. /* reset SPDIFTX controller */
  460. acts_reset_peripheral(cfg->rst_id);
  461. data->fifo_sel = AUDIO_FIFO_INVALID_TYPE;
  462. printk("SPDIFTX init successfully\n");
  463. return 0;
  464. }
  465. /* physical spdiftx driver data */
  466. static struct phy_spdiftx_drv_data phy_spdiftx_drv_data0;
  467. /* physical spdiftx config data */
  468. static const struct phy_spdiftx_config_data phy_spdiftx_config_data0 = {
  469. .reg_base = AUDIO_SPDIFTX_REG_BASE,
  470. .clk_id = CLOCK_ID_SPDIFTX,
  471. .rst_id = RESET_ID_SPDIFTX,
  472. PHY_DEV_FEATURE_DEF(clk_i2stx_div2) = CONFIG_AUDIO_SPDIFTX_0_CLK_I2STX_DIV2,
  473. };
  474. #if IS_ENABLED(CONFIG_AUDIO_SPDIFTX_0)
  475. DEVICE_DEFINE(spdiftx0, CONFIG_AUDIO_SPDIFTX_0_NAME, phy_spdiftx_init, NULL,
  476. &phy_spdiftx_drv_data0, &phy_spdiftx_config_data0,
  477. POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, &phy_spdiftx_drv_api);
  478. #endif