drv_sound_wm8904.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-03-12 Vandoul the first version
  9. */
  10. #include <rtthread.h>
  11. #include <drivers/audio.h>
  12. #include <drivers/i2c.h>
  13. #include "drv_sound_wm8904.h"
  14. /**
  15. * @brief object of wm8904.
  16. */
  17. struct drv_sound_wm8904{
  18. struct rt_i2c_bus_device *i2c_bus;
  19. rt_device_t i2s_bus;
  20. int i2c_addr;
  21. };
  22. rt_err_t wm8904_write_register(struct drv_sound_wm8904 *dev, rt_uint8_t reg, rt_uint16_t value)
  23. {
  24. struct rt_i2c_msg msg[2];
  25. rt_uint8_t buf[2];
  26. buf[0] = (value>>8)&0xFF;
  27. buf[1] = value&0xFF;
  28. msg[0].addr = dev->i2c_addr;
  29. msg[0].buf = &reg;
  30. msg[0].flags = RT_I2C_WR;
  31. msg[0].len = 1;
  32. msg[1].addr = dev->i2c_addr;
  33. msg[1].buf = buf;
  34. msg[1].flags = RT_I2C_WR|RT_I2C_NO_START;
  35. msg[1].len = 2;
  36. if(rt_i2c_transfer(dev->i2c_bus, msg, 2) != 2)
  37. {
  38. return -RT_ERROR;
  39. }
  40. return RT_EOK;
  41. }
  42. rt_err_t wm8904_read_register(struct drv_sound_wm8904 *dev, rt_uint8_t reg, rt_uint16_t *value)
  43. {
  44. struct rt_i2c_msg msg[2];
  45. rt_uint8_t buf[2];
  46. msg[0].addr = dev->i2c_addr;
  47. msg[0].buf = &reg;
  48. msg[0].flags = RT_I2C_WR;
  49. msg[0].len = 1;
  50. msg[1].addr = dev->i2c_addr;
  51. msg[1].buf = buf;
  52. msg[1].flags = RT_I2C_RD|RT_I2C_NO_START;
  53. msg[1].len = 2;
  54. if(rt_i2c_transfer(dev->i2c_bus, msg, 2) != 2)
  55. {
  56. return -RT_ERROR;
  57. }
  58. return RT_EOK;
  59. }
  60. rt_err_t wm8904_modify_register(struct drv_sound_wm8904 *dev, rt_uint8_t reg, rt_uint16_t mask, rt_uint16_t value)
  61. {
  62. rt_uint16_t reg_value;
  63. rt_err_t ret;
  64. ret = wm8904_read_register(dev, reg, &reg_value);
  65. if(ret != RT_EOK)
  66. {
  67. return ret;
  68. }
  69. reg_value &= (uint16_t)~mask;
  70. reg_value |= value;
  71. return wm8904_write_register(dev, reg, reg_value);
  72. }
  73. static rt_err_t wm8904_wait_on_write_sequencer(struct drv_sound_wm8904 *dev)
  74. {
  75. rt_err_t ret;
  76. rt_uint16_t value;
  77. do {
  78. ret = wm8904_read_register(dev, WM8904_WRT_SEQUENCER_4, &value);
  79. }while((ret == RT_EOK) && ((value & 1U) != 0u));
  80. return ret;
  81. }
  82. static rt_err_t wm8904_updateformat(struct drv_sound_wm8904 *dev, wm8904_fs_ratio_t fs_ratio, wm8904_sample_rate_t sample_rate, wm8904_bit_width_t bit_width)
  83. {
  84. rt_err_t err = RT_EOK;
  85. /** Disable SYSCLK */
  86. err = wm8904_write_register(dev, WM8904_CLK_RATES_2, 0x00);
  87. if(err != RT_EOK)
  88. {
  89. return err;
  90. }
  91. /** Set clock ratio and sample rate */
  92. err = wm8904_write_register(dev, WM8904_CLK_RATES_1, (rt_uint16_t)((rt_uint16_t)fs_ratio << 10U) | (rt_uint16_t)sample_rate);
  93. if(err != RT_EOK)
  94. {
  95. return err;
  96. }
  97. /** Set bit resolution. */
  98. err = wm8904_modify_register(dev, WM8904_AUDIO_IF_1, (0x000CU), (rt_uint16_t)bit_width << 2U);
  99. if(err != RT_EOK)
  100. {
  101. return err;
  102. }
  103. /** Enable SYSCLK */
  104. err = wm8904_write_register(dev, WM8904_CLK_RATES_2, 0x1007);
  105. if(err != RT_EOK)
  106. {
  107. return err;
  108. }
  109. return RT_EOK;
  110. }
  111. static rt_err_t wm8904_i2c_bus_init(struct rt_i2c_bus_device *i2c_bus)
  112. {
  113. (void)i2c_bus;
  114. return RT_EOK;
  115. }
  116. static rt_err_t wm8904_i2s_bus_init(rt_device_t i2s_bus)
  117. {
  118. (void)i2s_bus;
  119. return RT_EOK;
  120. }
  121. const static uint16_t wm8904_init_list[][2] = {
  122. /* TOCLK_RATE_DIV16=0, TOCLK_RATE_x4=1, SR_MODE=0, MCLK_DIV=1
  123. * (Required for MMCs: SGY, KRT see erratum CE000546) */
  124. {WM8904_CLK_RATES_0, 0xA45F},
  125. /* INL_ENA=1, INR ENA=1 */
  126. {WM8904_POWER_MGMT_0, 0x0003},
  127. /* HPL_PGA_ENA=1, HPR_PGA_ENA=1 */
  128. {WM8904_POWER_MGMT_2, 0x0003},
  129. /* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
  130. {WM8904_POWER_MGMT_6, 0x000F},
  131. /* ADC_OSR128=1 */
  132. {WM8904_ANALOG_ADC_0, 0x0001},
  133. /* DACL_DATINV=0, DACR_DATINV=0, DAC_BOOST=00, LOOPBACK=0, AIFADCL_SRC=0,
  134. * AIFADCR_SRC=1, AIFDACL_SRC=0, AIFDACR_SRC=1, ADC_COMP=0, ADC_COMPMODE=0,
  135. * DAC_COMP=0, DAC_COMPMODE=0 */
  136. {WM8904_AUDIO_IF_0, 0x0050},
  137. /* DAC_MONO=0, DAC_SB_FILT-0, DAC_MUTERATE=0, DAC_UNMUTE RAMP=0,
  138. * DAC_OSR128=1, DAC_MUTE=0, DEEMPH=0 (none) */
  139. {WM8904_DAC_DIG_1, 0x0040},
  140. /* LINMUTE=0, LIN_VOL=0_0101 */
  141. {WM8904_ANALOG_LEFT_IN_0, 0x0005},
  142. /* RINMUTE=0, RIN VOL=0_0101 LINEOUTL RMV SHORT-1, LINEOUTL ENA_OUTP=1,
  143. * LINEOUTL_ENA_DLY=1, LINEOUTL_ENA=1, LINEOUTR_RMV_SHORT-1,
  144. * LINEOUTR_ENA_OUTP=1 */
  145. {WM8904_ANALOG_RIGHT_IN_0, 0x0005},
  146. /* HPOUTL_MUTE=0, HPOUT_VU=0, HPOUTLZC=0, HPOUTL_VOL=10_1101 */
  147. {WM8904_ANALOG_OUT1_LEFT, 0x00AD},
  148. /* HPOUTR_MUTE=0, HPOUT_VU=0, HPOUTRZC=0, HPOUTR_VOL=10_1101 */
  149. {WM8904_ANALOG_OUT1_RIGHT, 0x00AD},
  150. /* Enable DC servos for headphone out */
  151. {WM8904_DC_SERVO_0, 0x0003},
  152. /* HPL_RMV_SHORT=1, HPL_ENA_OUTP=1, HPL_ENA_DLY=1, HPL_ENA=1,
  153. * HPR_RMV_SHORT=1, HPR_ENA_OUTP=1, HPR_ENA_DLY=1, HPR_ENA=1 */
  154. {WM8904_ANALOG_HP_0, 0x00FF},
  155. /* CP_DYN_PWR=1 */
  156. {WM8904_CLS_W_0, 0x0001},
  157. /* CP_ENA=1 */
  158. {WM8904_CHRG_PUMP_0, 0x0001},
  159. /* TOCLK_RATE_DIV16=0, TOCLK_RATE_x4=1, SR_MODE=0, MCLK_DIV=1
  160. * (Required for MMCs: SGY, KRT see erratum CE000546) */
  161. {WM8904_CLK_RATES_0, 0xA45F},
  162. /* INL_ENA=1, INR ENA=1 */
  163. {WM8904_POWER_MGMT_0, 0x0003},
  164. /* HPL_PGA_ENA=1, HPR_PGA_ENA=1 */
  165. {WM8904_POWER_MGMT_2, 0x0003},
  166. /* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
  167. {WM8904_POWER_MGMT_6, 0x000F},
  168. /* ADC_OSR128=1 */
  169. {WM8904_ANALOG_ADC_0, 0x0001},
  170. /* DACL_DATINV=0, DACR_DATINV=0, DAC_BOOST=00, LOOPBACK=0, AIFADCL_SRC=0,
  171. * AIFADCR_SRC=1, AIFDACL_SRC=0, AIFDACR_SRC=1, ADC_COMP=0, ADC_COMPMODE=0,
  172. * DAC_COMP=0, DAC_COMPMODE=0 */
  173. {WM8904_AUDIO_IF_0, 0x0050},
  174. /* DAC_MONO=0, DAC_SB_FILT-0, DAC_MUTERATE=0, DAC_UNMUTE RAMP=0,
  175. * DAC_OSR128=1, DAC_MUTE=0, DEEMPH=0 (none) */
  176. {WM8904_DAC_DIG_1, 0x0040},
  177. /* LINMUTE=0, LIN_VOL=0_0101 */
  178. {WM8904_ANALOG_LEFT_IN_0, 0x0005},
  179. /* RINMUTE=0, RIN VOL=0_0101 LINEOUTL RMV SHORT-1, LINEOUTL ENA_OUTP=1,
  180. * LINEOUTL_ENA_DLY=1, LINEOUTL_ENA=1, LINEOUTR_RMV_SHORT-1,
  181. * LINEOUTR_ENA_OUTP=1 */
  182. {WM8904_ANALOG_RIGHT_IN_0, 0x0005},
  183. /* HPOUTL_MUTE=0, HPOUT_VU=0, HPOUTLZC=0, HPOUTL_VOL=10_1101 */
  184. {WM8904_ANALOG_OUT1_LEFT, 0x00AD},
  185. /* HPOUTR_MUTE=0, HPOUT_VU=0, HPOUTRZC=0, HPOUTR_VOL=10_1101 */
  186. {WM8904_ANALOG_OUT1_RIGHT, 0x00AD},
  187. /* Enable DC servos for headphone out */
  188. {WM8904_DC_SERVO_0, 0x0003},
  189. /* HPL_RMV_SHORT=1, HPL_ENA_OUTP=1, HPL_ENA_DLY=1, HPL_ENA=1,
  190. * HPR_RMV_SHORT=1, HPR_ENA_OUTP=1, HPR_ENA_DLY=1, HPR_ENA=1 */
  191. {WM8904_ANALOG_HP_0, 0x00FF},
  192. /* CP_DYN_PWR=1 */
  193. {WM8904_CLS_W_0, 0x0001},
  194. /* CP_ENA=1 */
  195. {WM8904_CHRG_PUMP_0, 0x0001},
  196. };
  197. rt_err_t wm8904_init(struct drv_sound_wm8904 *dev, struct wm8904_config *config)
  198. {
  199. rt_err_t ret;
  200. dev->i2c_bus = rt_i2c_bus_device_find(config->i2c_bus_name);
  201. if(dev->i2c_bus == RT_NULL)
  202. {
  203. return -RT_EINVAL;
  204. }
  205. dev->i2s_bus = rt_device_find(config->i2s_bus_name);
  206. if(dev->i2s_bus == RT_NULL)
  207. {
  208. return -RT_EINVAL;
  209. }
  210. wm8904_i2c_bus_init(dev->i2c_bus);
  211. wm8904_i2s_bus_init(dev->i2s_bus);
  212. ret = wm8904_write_register(dev, WM8904_RESET, 0x0000);
  213. if(ret != RT_EOK)
  214. {
  215. return ret;
  216. }
  217. /* MCLK_INV=0, SYSCLK_SRC=0, TOCLK_RATE=0, OPCLK_ENA=1,
  218. * CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
  219. ret = wm8904_write_register(dev, WM8904_CLK_RATES_2, 0x000F);
  220. if(ret != RT_EOK)
  221. {
  222. return ret;
  223. }
  224. /* WSEQ_ENA=1, WSEQ_WRITE_INDEX=0_0000 */
  225. ret = wm8904_write_register(dev, WM8904_WRT_SEQUENCER_0, 0x0100);
  226. if(ret != RT_EOK)
  227. {
  228. return ret;
  229. }
  230. /* WSEQ_ABORT=0, WSEQ_START=1, WSEQ_START_INDEX=00_0000 */
  231. ret = wm8904_write_register(dev, WM8904_WRT_SEQUENCER_3, 0x0100);
  232. if(ret != RT_EOK)
  233. {
  234. return ret;
  235. }
  236. /* WSEQ_ENA=1, WSEQ_SRITE_INDEX=0_0000 */
  237. ret = wm8904_write_register(dev, WM8904_WRT_SEQUENCER_0, 0x0100);
  238. if(ret != RT_EOK)
  239. {
  240. return ret;
  241. }
  242. ret = wm8904_wait_on_write_sequencer(dev);
  243. if(ret != RT_EOK)
  244. {
  245. return ret;
  246. }
  247. for(int i=0; i<sizeof(wm8904_init_list)/sizeof(wm8904_init_list[0]); i++)
  248. {
  249. ret = wm8904_write_register(dev, wm8904_init_list[i][0], wm8904_init_list[i][1]);
  250. if(ret != RT_EOK)
  251. {
  252. return ret;
  253. }
  254. }
  255. return ret;
  256. }
  257. rt_err_t wm8904_deinit(struct drv_sound_wm8904 *dev)
  258. {
  259. return wm8904_write_register(dev, WM8904_RESET, 0x0000);
  260. }
  261. rt_err_t wm8904_set_master_clock(struct drv_sound_wm8904 *dev, rt_uint32_t sysclk, rt_uint32_t sample_rate, rt_uint32_t bit_width)
  262. {
  263. rt_uint32_t bclk = sample_rate * bit_width * 2U;
  264. rt_uint32_t bclk_div = 0U;
  265. rt_uint16_t audio_interface = 0U;
  266. rt_err_t err = RT_EOK;
  267. rt_uint16_t sysclk_div = 0;
  268. err = wm8904_read_register(dev, WM8904_CLK_RATES_0, &sysclk_div);
  269. sysclk = sysclk >> (sysclk_div & 0x1U);
  270. if((sysclk / bclk > 48U) || (bclk / sample_rate > 2047U) || (bclk / sample_rate < 8U))
  271. {
  272. return -RT_EINVAL;
  273. }
  274. err = wm8904_read_register(dev, WM8904_AUDIO_IF_2, &audio_interface);
  275. if(err != RT_EOK)
  276. {
  277. return err;
  278. }
  279. audio_interface &= ~(rt_uint16_t)0x1FU;
  280. bclk_div = (sysclk * 10U) / bclk;
  281. switch(bclk_div)
  282. {
  283. case 10:
  284. audio_interface |= 0U;
  285. break;
  286. case 15:
  287. audio_interface |= 1U;
  288. break;
  289. case 20:
  290. audio_interface |= 2U;
  291. break;
  292. case 30:
  293. audio_interface |= 3U;
  294. break;
  295. case 40:
  296. audio_interface |= 4U;
  297. break;
  298. case 50:
  299. audio_interface |= 5U;
  300. break;
  301. case 55:
  302. audio_interface |= 6U;
  303. break;
  304. case 60:
  305. audio_interface |= 7U;
  306. break;
  307. case 80:
  308. audio_interface |= 8U;
  309. break;
  310. case 100:
  311. audio_interface |= 9U;
  312. break;
  313. case 110:
  314. audio_interface |= 10U;
  315. break;
  316. case 120:
  317. audio_interface |= 11U;
  318. break;
  319. case 160:
  320. audio_interface |= 12U;
  321. break;
  322. case 200:
  323. audio_interface |= 13U;
  324. break;
  325. case 220:
  326. audio_interface |= 14U;
  327. break;
  328. case 240:
  329. audio_interface |= 15U;
  330. break;
  331. case 250:
  332. audio_interface |= 16U;
  333. break;
  334. case 300:
  335. audio_interface |= 17U;
  336. break;
  337. case 320:
  338. audio_interface |= 18U;
  339. break;
  340. case 440:
  341. audio_interface |= 19U;
  342. break;
  343. case 480:
  344. audio_interface |= 20U;
  345. break;
  346. default:
  347. err = -RT_EINVAL;
  348. break;
  349. }
  350. if(err != RT_EOK)
  351. {
  352. return err;
  353. }
  354. /** bclk divider */
  355. err = wm8904_write_register(dev, WM8904_AUDIO_IF_2, audio_interface);
  356. if(err != RT_EOK)
  357. {
  358. return err;
  359. }
  360. err = wm8904_modify_register(dev, WM8904_GPIO_CONTROL_4, 0x8FU, 1U);
  361. if(err != RT_EOK)
  362. {
  363. return err;
  364. }
  365. /** LRCLK direction and divider */
  366. audio_interface = (rt_uint16_t)((1UL << 11U) | (bclk / sample_rate));
  367. err = wm8904_modify_register(dev, WM8904_AUDIO_IF_3, 0xFFFU, audio_interface);
  368. if(err != RT_EOK)
  369. {
  370. return err;
  371. }
  372. return RT_EOK;
  373. }
  374. rt_err_t wm8904_set_fll_config(struct drv_sound_wm8904 *dev, wm8904_fll_config_t *config)
  375. {
  376. RT_ASSERT(dev != RT_NULL);
  377. RT_ASSERT(config != RT_NULL);
  378. rt_uint32_t reference_clock = config->ref_clock_hz;
  379. rt_uint32_t input_divider = 0U;
  380. rt_uint32_t fvco = 0U, output_div = 0U, ratio = 0U;
  381. rt_uint32_t n = 0U, k = 0U;
  382. /* it is recommended that the highest possible frequency - within the 13.5MHz limit - should be selected */
  383. if(reference_clock < 13500000U)
  384. {
  385. input_divider = 0;
  386. }
  387. else if(reference_clock / 2U < 13500000U)
  388. {
  389. input_divider = 1;
  390. }
  391. else if(reference_clock / 4U < 13500000U)
  392. {
  393. input_divider = 2;
  394. }
  395. else
  396. {
  397. input_divider = 3;
  398. }
  399. if(reference_clock / (1UL << input_divider) > 13500000)
  400. {
  401. return -RT_EINVAL;
  402. }
  403. reference_clock = reference_clock / (1UL << input_divider);
  404. for (output_div = 4U; output_div <= 64U; output_div++)
  405. {
  406. fvco = output_div * config->output_clock_hz;
  407. if ((fvco >= 90000000U) && (fvco <= 100000000U))
  408. {
  409. break;
  410. }
  411. }
  412. if(reference_clock <= 64000U)
  413. {
  414. ratio = 4U;
  415. }
  416. else if(reference_clock <= 128000U)
  417. {
  418. ratio = 3U;
  419. }
  420. else if(reference_clock <= 256000U)
  421. {
  422. ratio = 2U;
  423. }
  424. else if(reference_clock <= 1000000U)
  425. {
  426. ratio = 1U;
  427. }
  428. else
  429. {
  430. ratio = 0U;
  431. }
  432. n = fvco / ((ratio + 1U) * reference_clock);
  433. k = (rt_uint32_t)((rt_uint64_t)fvco * 1000000U) / ((ratio + 1U) * reference_clock);
  434. if(n != 0U)
  435. {
  436. k = k - n * 1000000U;
  437. }
  438. k = (rt_uint32_t)((rt_uint64_t)k * 65536U) / 1000000U;
  439. /* configure WM8904 */
  440. if (wm8904_modify_register(dev, WM8904_FLL_CONTROL_1, 7U, 4U) != RT_EOK)
  441. {
  442. return -RT_ERROR;
  443. }
  444. /* configure WM8904 */
  445. if (wm8904_modify_register(dev, WM8904_FLL_CONTROL_2, 0x3F07U, (rt_uint16_t)(((output_div - 1U) << 8U) | ratio)) != RT_EOK)
  446. {
  447. return -RT_ERROR;
  448. }
  449. if (wm8904_write_register(dev, WM8904_FLL_CONTROL_3, (rt_uint16_t)k) != RT_EOK)
  450. {
  451. return -RT_ERROR;
  452. }
  453. if (wm8904_modify_register(dev, WM8904_FLL_CONTROL_4, 0x7FE0U, (rt_uint16_t)(n << 5U)) != RT_EOK)
  454. {
  455. return -RT_ERROR;
  456. }
  457. if (wm8904_write_register(dev, WM8904_FLL_CONTROL_5, (rt_uint16_t)((input_divider << 3U) | (rt_uint16_t)config->source)) != RT_EOK)
  458. {
  459. return -RT_ERROR;
  460. }
  461. if (wm8904_modify_register(dev, WM8904_FLL_CONTROL_1, 1U, 1) != RT_EOK)
  462. {
  463. return -RT_ERROR;
  464. }
  465. /** enable GPIO1 output fll output clock */
  466. if (wm8904_write_register(dev, WM8904_GPIO_CONTROL_1, (rt_uint16_t)9U) != RT_EOK)
  467. {
  468. return -RT_ERROR;
  469. }
  470. return RT_EOK;
  471. }
  472. rt_err_t wm8904_set_protocol(struct drv_sound_wm8904 *dev, wm8904_protocol_t p)
  473. {
  474. return wm8904_modify_register(dev, WM8904_AUDIO_IF_1, (0x0003U | (1U << 4U)), (rt_uint16_t)p);
  475. }
  476. rt_err_t wm8904_select_lrc_polarity(struct drv_sound_wm8904 *dev, rt_uint32_t polarity)
  477. {
  478. return wm8904_modify_register(dev, WM8904_AUDIO_IF_1, 0x0010U, (rt_uint16_t)polarity);
  479. }
  480. rt_err_t wm8904_enable_dac_time_slot(struct drv_sound_wm8904 *dev, wm8904_timeslot_t timeslot)
  481. {
  482. return wm8904_modify_register(dev, WM8904_AUDIO_IF_1, ((rt_uint16_t)3U << 12U), (((rt_uint16_t)1U << 13U) | ((rt_uint16_t)timeslot << 12U)));
  483. }
  484. rt_err_t wm8904_enable_adc_time_slot(struct drv_sound_wm8904 *dev, wm8904_timeslot_t timeslot)
  485. {
  486. return wm8904_modify_register(dev, WM8904_AUDIO_IF_1, ((rt_uint16_t)3U << 10U), (((rt_uint16_t)1U << 11U) | ((rt_uint16_t)timeslot << 10U)));
  487. }
  488. rt_err_t wm8904_check_audio_format(struct drv_sound_wm8904 *dev, wm8904_audio_format_t *format, rt_uint32_t mclk_freq)
  489. {
  490. RT_ASSERT((dev != RT_NULL) && (format != RT_NULL));
  491. rt_err_t err = RT_EOK;
  492. rt_uint16_t mclk_div = 0U;
  493. rt_uint32_t sample_rate = 0U;
  494. rt_uint32_t fs_ratio = 0;
  495. wm8904_sample_rate_t reg_sample_rate = format->sampleRate;
  496. err = wm8904_read_register(dev, WM8904_CLK_RATES_0, &mclk_div);
  497. if(err != RT_EOK)
  498. {
  499. return err;
  500. }
  501. switch(format->sampleRate)
  502. {
  503. case WM8904_SAMPLERATE_8kHz:
  504. sample_rate = 8000;
  505. break;
  506. case WM8904_SAMPLERATE_12kHz :
  507. sample_rate = 12000;
  508. break;
  509. case WM8904_SAMPLERATE_16kHz :
  510. sample_rate = 16000;
  511. break;
  512. case WM8904_SAMPLERATE_24kHz :
  513. sample_rate = 24000;
  514. break;
  515. case WM8904_SAMPLERATE_32kHz :
  516. sample_rate = 32000;
  517. break;
  518. case WM8904_SAMPLERATE_48kHz :
  519. sample_rate = 48000;
  520. break;
  521. case WM8904_SAMPLERATE_11025Hz:
  522. sample_rate = 11025;
  523. reg_sample_rate = WM8904_SAMPLERATE_12kHz;
  524. break;
  525. case WM8904_SAMPLERATE_22050Hz:
  526. sample_rate = 22050;
  527. reg_sample_rate = WM8904_SAMPLERATE_24kHz;
  528. break;
  529. case WM8904_SAMPLERATE_44100Hz:
  530. sample_rate = 44100;
  531. reg_sample_rate = WM8904_SAMPLERATE_48kHz;
  532. break;
  533. default:
  534. err = -RT_EINVAL;
  535. break;
  536. }
  537. if(err != RT_EOK)
  538. {
  539. return err;
  540. }
  541. fs_ratio = (mclk_freq >> (mclk_div & 0x1U)) / sample_rate;
  542. switch(fs_ratio)
  543. {
  544. case 64:
  545. format->fsRatio = WM8904_FSRATIO_64X;
  546. break;
  547. case 128 :
  548. format->fsRatio = WM8904_FSRATIO_128X;
  549. break;
  550. case 192 :
  551. format->fsRatio = WM8904_FSRATIO_192X;
  552. break;
  553. case 256 :
  554. format->fsRatio = WM8904_FSRATIO_256X;
  555. break;
  556. case 384 :
  557. format->fsRatio = WM8904_FSRATIO_384X;
  558. break;
  559. case 512 :
  560. format->fsRatio = WM8904_FSRATIO_512X;
  561. break;
  562. case 768 :
  563. format->fsRatio = WM8904_FSRATIO_768X;
  564. break;
  565. case 1024:
  566. format->fsRatio = WM8904_FSRATIO_1024X;
  567. break;
  568. case 1408:
  569. format->fsRatio = WM8904_FSRATIO_1408X;
  570. break;
  571. case 1536:
  572. format->fsRatio = WM8904_FSRATIO_1536X;
  573. break;
  574. default:
  575. err = -RT_EINVAL;
  576. break;
  577. }
  578. if(err != RT_EOK)
  579. {
  580. return err;
  581. }
  582. return wm8904_updateformat(dev, format->fsRatio, reg_sample_rate, format->bitWidth);
  583. }
  584. rt_err_t wm8904_set_audio_format(struct drv_sound_wm8904 *dev, rt_uint32_t sysclk, rt_uint32_t sample_rate, rt_uint32_t bit_width)
  585. {
  586. rt_uint32_t ratio = 0;
  587. rt_err_t err = RT_EOK;
  588. wm8904_bit_width_t reg_bit_width = WM8904_BITWIDTH_32;
  589. wm8904_sample_rate_t reg_sample_reate = WM8904_SAMPLERATE_48kHz;
  590. wm8904_fs_ratio_t reg_fsratio = WM8904_FSRATIO_1536X;
  591. rt_uint16_t temp_reg = 0U;
  592. err = wm8904_read_register(dev, WM8904_CLK_RATES_0, &temp_reg);
  593. if(err != RT_EOK)
  594. {
  595. return err;
  596. }
  597. switch(sample_rate)
  598. {
  599. case 8000:
  600. sample_rate = WM8904_SAMPLERATE_8kHz;
  601. break;
  602. case 11025:
  603. sample_rate = WM8904_SAMPLERATE_12kHz;
  604. break;
  605. case 12000:
  606. sample_rate = WM8904_SAMPLERATE_12kHz;
  607. break;
  608. case 16000:
  609. sample_rate = WM8904_SAMPLERATE_16kHz;
  610. break;
  611. case 22050:
  612. sample_rate = WM8904_SAMPLERATE_24kHz;
  613. break;
  614. case 24000:
  615. sample_rate = WM8904_SAMPLERATE_24kHz;
  616. break;
  617. case 32000:
  618. sample_rate = WM8904_SAMPLERATE_32kHz;
  619. break;
  620. case 44100:
  621. sample_rate = WM8904_SAMPLERATE_48kHz;
  622. break;
  623. case 48000:
  624. sample_rate = WM8904_SAMPLERATE_48kHz;
  625. break;
  626. default:
  627. err = -RT_EINVAL;
  628. break;
  629. }
  630. if(err != RT_EOK)
  631. {
  632. return err;
  633. }
  634. switch(bit_width)
  635. {
  636. case 16:
  637. reg_bit_width = WM8904_BITWIDTH_16;
  638. break;
  639. case 20:
  640. reg_bit_width = WM8904_BITWIDTH_20;
  641. break;
  642. case 24:
  643. reg_bit_width = WM8904_BITWIDTH_24;
  644. break;
  645. case 32:
  646. reg_bit_width = WM8904_BITWIDTH_32;
  647. break;
  648. default:
  649. err = -RT_EINVAL;
  650. break;
  651. }
  652. if(err != RT_EOK)
  653. {
  654. return err;
  655. }
  656. ratio = (sysclk >> (temp_reg & 0x1U)) / sample_rate;
  657. switch(ratio)
  658. {
  659. case 64:
  660. reg_fsratio = WM8904_FSRATIO_64X;
  661. break;
  662. case 128 :
  663. reg_fsratio = WM8904_FSRATIO_128X;
  664. break;
  665. case 192 :
  666. reg_fsratio = WM8904_FSRATIO_192X;
  667. break;
  668. case 256 :
  669. reg_fsratio = WM8904_FSRATIO_256X;
  670. break;
  671. case 384 :
  672. reg_fsratio = WM8904_FSRATIO_384X;
  673. break;
  674. case 512 :
  675. reg_fsratio = WM8904_FSRATIO_512X;
  676. break;
  677. case 768 :
  678. reg_fsratio = WM8904_FSRATIO_768X;
  679. break;
  680. case 1024:
  681. reg_fsratio = WM8904_FSRATIO_1024X;
  682. break;
  683. case 1408:
  684. reg_fsratio = WM8904_FSRATIO_1408X;
  685. break;
  686. case 1536:
  687. reg_fsratio = WM8904_FSRATIO_1536X;
  688. break;
  689. default:
  690. err = -RT_EINVAL;
  691. break;
  692. }
  693. if(err != RT_EOK)
  694. {
  695. return err;
  696. }
  697. err = wm8904_updateformat(dev, reg_fsratio, reg_sample_reate, reg_bit_width);
  698. if(err != RT_EOK)
  699. {
  700. return err;
  701. }
  702. err = wm8904_read_register(dev, WM8904_AUDIO_IF_1, &temp_reg);
  703. if(err != RT_EOK)
  704. {
  705. return err;
  706. }
  707. if((temp_reg & (1UL << 6U)) != 0)
  708. {
  709. err = wm8904_set_master_clock(dev, sysclk, sample_rate, bit_width);
  710. }
  711. return err;
  712. }
  713. rt_err_t wm8904_set_volume(struct drv_sound_wm8904 *dev, rt_uint16_t volume_left, rt_uint16_t volume_right)
  714. {
  715. RT_ASSERT(volume_left <= WM8904_MAP_HEADPHONE_LINEOUT_MAX_VOLUME);
  716. RT_ASSERT(volume_right <= WM8904_MAP_HEADPHONE_LINEOUT_MAX_VOLUME);
  717. rt_err_t err = RT_EOK;
  718. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_LEFT, 0x1BF, volume_left);
  719. if(err != RT_EOK)
  720. {
  721. return err;
  722. }
  723. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_RIGHT, 0x1BF, ((rt_uint16_t)volume_right | 0x0080U));
  724. if(err != RT_EOK)
  725. {
  726. return err;
  727. }
  728. return RT_EOK;
  729. }
  730. rt_err_t wm8904_set_mute(struct drv_sound_wm8904 *dev, rt_bool_t mute_left, rt_bool_t mute_right)
  731. {
  732. rt_err_t err = RT_EOK;
  733. rt_uint16_t left = (rt_uint16_t)(mute_left ? 0x0100U : 0x0000U);
  734. rt_uint16_t right = (rt_uint16_t)(mute_right ? 0x0100U : 0x0000U);
  735. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_LEFT, 0x0100U, left);
  736. if(err != RT_EOK)
  737. {
  738. return err;
  739. }
  740. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_RIGHT, 0x0180U, ((rt_uint16_t)right | 0x0080U));
  741. if(err != RT_EOK)
  742. {
  743. return err;
  744. }
  745. return err;
  746. }
  747. rt_err_t wm8904_set_channel_volume(struct drv_sound_wm8904 *dev, rt_uint32_t channel, rt_uint32_t volume)
  748. {
  749. RT_ASSERT(volume <= WM8904_MAP_HEADPHONE_LINEOUT_MAX_VOLUME);
  750. rt_err_t err = RT_EOK;
  751. /* headphone left channel 0x1BF means unmute the OUT and reset the OUT volume update bit and volume range fields */
  752. if((channel & (rt_uint32_t)WM8904_HEADPHONE_LEFT) != 0U)
  753. {
  754. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_LEFT, 0x1BFU, (rt_uint16_t)volume | 0x80U);
  755. }
  756. /* headphone right channel */
  757. if((channel & (rt_uint32_t)WM8904_HEADPHONE_RIGHT) != 0U)
  758. {
  759. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_RIGHT, 0x1BFU, (rt_uint16_t)volume | 0x80U);
  760. }
  761. /* line out left channel */
  762. if((channel & (rt_uint32_t)WM8904_LINEOUT_LEFT) != 0U)
  763. {
  764. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT2_LEFT, 0x1BFU, (rt_uint16_t)volume | 0x80U);
  765. }
  766. /* line out right channel */
  767. if((channel & (rt_uint32_t)WM8904_LINEOUT_RIGHT) != 0U)
  768. {
  769. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT2_RIGHT, 0x1BFU, (rt_uint16_t)volume | 0x80U);
  770. }
  771. return err;
  772. }
  773. rt_err_t wm8904_set_channel_mute(struct drv_sound_wm8904 *dev, rt_uint32_t channel, rt_bool_t is_mute)
  774. {
  775. rt_err_t err = RT_EOK;
  776. rt_uint16_t reg_value = 0U, reg_mask = 0U;
  777. reg_value = is_mute ? 0x180U : 0x80U;
  778. reg_mask = 0x100U;
  779. /* headphone left channel */
  780. if((channel & (rt_uint32_t)WM8904_HEADPHONE_LEFT) != 0U)
  781. {
  782. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_LEFT, reg_mask, reg_value);
  783. }
  784. /* headphone right channel */
  785. if((channel & (rt_uint32_t)WM8904_HEADPHONE_RIGHT) != 0U)
  786. {
  787. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT1_RIGHT, reg_mask, reg_value);
  788. }
  789. /* line out left channel */
  790. if((channel & (rt_uint32_t)WM8904_LINEOUT_LEFT) != 0U)
  791. {
  792. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT2_LEFT, reg_mask, reg_value);
  793. }
  794. /* line out right channel */
  795. if((channel & (rt_uint32_t)WM8904_LINEOUT_RIGHT) != 0U)
  796. {
  797. err = wm8904_modify_register(dev, WM8904_ANALOG_OUT2_RIGHT, reg_mask, reg_value);
  798. }
  799. return err;
  800. }
  801. rt_err_t wm8904_enable_dac_volume(struct drv_sound_wm8904 *dev, rt_uint8_t volume)
  802. {
  803. rt_err_t err = RT_EOK;
  804. err = wm8904_write_register(dev, WM8904_DAC_DIGITAL_VOLUME_LEFT, (rt_uint16_t)(volume | 0x100UL));
  805. if(err == RT_EOK)
  806. {
  807. err = wm8904_write_register(dev, WM8904_DAC_DIGITAL_VOLUME_RIGHT, (rt_uint16_t)(volume | 0x100UL));
  808. }
  809. return err;
  810. }
  811. rt_err_t wm8904_set_module_power(struct drv_sound_wm8904 *dev, wm8904_module_t module, rt_bool_t is_enabled)
  812. {
  813. rt_uint8_t reg_addr = 0, reg_bit_mask = 0U, reg_value = 0U;
  814. rt_err_t err = RT_EOK;
  815. switch(module)
  816. {
  817. case WM8904_MODULE_ADC:
  818. reg_addr = WM8904_POWER_MGMT_6;
  819. reg_bit_mask = 3U;
  820. reg_value = is_enabled ? 3U : 0U;
  821. break;
  822. case WM8904_MODULE_DAC:
  823. reg_addr = WM8904_POWER_MGMT_6;
  824. reg_bit_mask = 0xCU;
  825. reg_value = is_enabled ? 0xCU : 0U;
  826. break;
  827. case WM8904_MODULE_PGA:
  828. reg_addr = WM8904_POWER_MGMT_0;
  829. reg_bit_mask = 3U;
  830. reg_value = is_enabled ? 3U : 0U;
  831. break;
  832. case WM8904_MODULE_HEADPHONE:
  833. reg_addr = WM8904_POWER_MGMT_2;
  834. reg_bit_mask = 3U;
  835. reg_value = is_enabled ? 3U : 0U;
  836. break;
  837. case WM8904_MODULE_LINEOUT:
  838. reg_addr = WM8904_POWER_MGMT_3;
  839. reg_bit_mask = 3U;
  840. reg_value = is_enabled ? 3U : 0U;
  841. break;
  842. default:
  843. err = -RT_EINVAL;
  844. break;
  845. }
  846. if(err == RT_EOK)
  847. {
  848. err = wm8904_modify_register(dev, reg_addr, reg_bit_mask, reg_value);
  849. }
  850. return err;
  851. }
  852. rt_err_t wm8904_set_record(struct drv_sound_wm8904 *dev, rt_uint32_t record_source)
  853. {
  854. rt_uint8_t reg_left_addr = WM8904_ANALOG_LEFT_IN_1, reg_right_addr = WM8904_ANALOG_RIGHT_IN_1;
  855. rt_uint16_t reg_left_value = 0U, reg_right_value = 0U, reg_bit_mask = 0U;
  856. rt_err_t err = RT_EOK;
  857. switch(record_source)
  858. {
  859. case WM8904_RECORD_SOURCE_DIFFERENTIAL_LINE:
  860. reg_left_value = 1U;
  861. reg_right_value = 1U;
  862. reg_bit_mask = 0x3FU;
  863. break;
  864. case WM8904_RECORD_SOURCE_DIFFERENTIAL_MIC:
  865. reg_left_value = 2U;
  866. reg_right_value = 2U;
  867. reg_bit_mask = 0x3FU;
  868. break;
  869. case WM8904_RECORD_SOURCE_LINE_INPUT:
  870. reg_left_value = 0U;
  871. reg_right_value = 0U;
  872. reg_bit_mask = 0x3FU;
  873. break;
  874. case WM8904_RECORD_SOURCE_DIGITAL_MIC:
  875. reg_left_value = 1U << 12;
  876. reg_left_addr = WM8904_DAC_DIG_0;
  877. reg_right_addr = 0U;
  878. reg_bit_mask = 1U << 12;
  879. break;
  880. default:
  881. err = -RT_EINVAL;
  882. break;
  883. }
  884. if(err != RT_EOK)
  885. {
  886. return err;
  887. }
  888. err = wm8904_modify_register(dev, reg_left_addr, reg_bit_mask, reg_left_value);
  889. if((err == RT_EOK) && (reg_right_addr != 0U))
  890. {
  891. err = wm8904_modify_register(dev, reg_right_addr, reg_bit_mask, reg_right_value);
  892. }
  893. return err;
  894. }
  895. rt_err_t wm8904_set_record_channel(struct drv_sound_wm8904 *dev, rt_uint32_t left_record_channel, rt_uint32_t right_record_channel)
  896. {
  897. rt_uint8_t reg_left_addr = WM8904_ANALOG_LEFT_IN_1, reg_right_addr = WM8904_ANALOG_RIGHT_IN_1;
  898. rt_uint16_t reg_left_value = 0U, reg_right_value = 0U, reg_bit_mask;
  899. rt_err_t err = RT_EOK;
  900. rt_uint8_t left_positive_channel = 0U, left_negative_channel = 0U, right_positive_channel = 0U, right_negative_channel = 0U;
  901. if((left_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_POSITIVE1) != 0U)
  902. {
  903. left_positive_channel = 0U;
  904. }
  905. else if((left_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_POSITIVE2) != 0U)
  906. {
  907. left_positive_channel = 1U;
  908. }
  909. else
  910. {
  911. left_positive_channel = 2U;
  912. }
  913. if((left_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_NEGATIVE1) != 0U)
  914. {
  915. left_negative_channel = 0U;
  916. }
  917. else if((left_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_NEGATIVE2) != 0U)
  918. {
  919. left_negative_channel = 1U;
  920. }
  921. else if((left_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_NEGATIVE3) != 0U)
  922. {
  923. left_negative_channel = 2U;
  924. }
  925. else
  926. {
  927. left_negative_channel = left_positive_channel;
  928. }
  929. if((right_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_POSITIVE1) != 0U)
  930. {
  931. right_positive_channel = 0U;
  932. }
  933. else if((right_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_POSITIVE2) != 0U)
  934. {
  935. right_positive_channel = 1U;
  936. }
  937. else
  938. {
  939. right_positive_channel = 2U;
  940. }
  941. if((right_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_NEGATIVE1) != 0U)
  942. {
  943. right_negative_channel = 0U;
  944. }
  945. else if((right_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_NEGATIVE2) != 0U)
  946. {
  947. right_negative_channel = 1U;
  948. }
  949. else if((right_record_channel & (rt_uint32_t)WM8904_RECORD_CHANNEL_DIFFERENTIAL_NEGATIVE3) != 0U)
  950. {
  951. right_negative_channel = 2U;
  952. }
  953. else
  954. {
  955. right_negative_channel = right_positive_channel;
  956. }
  957. reg_left_value = (((rt_uint16_t)left_negative_channel & 3U) << 4U) | (((rt_uint16_t)left_positive_channel & 3U) << 2U);
  958. reg_right_value = (((rt_uint16_t)right_negative_channel & 3U) << 4U) | (((rt_uint16_t)right_positive_channel & 3U) << 2U);
  959. reg_bit_mask = 0x3CU;
  960. err = wm8904_modify_register(dev, reg_left_addr, reg_bit_mask, reg_left_value);
  961. if(err == RT_EOK)
  962. {
  963. return wm8904_modify_register(dev, reg_right_addr, reg_bit_mask, reg_right_value);
  964. }
  965. return -RT_ERROR;
  966. }
  967. rt_err_t wm8904_set_play(struct drv_sound_wm8904 *dev, rt_uint32_t play_source)
  968. {
  969. rt_uint16_t reg_value = 0U, reg_bit_mask = 0xFU;
  970. /* source from PGA */
  971. if(play_source == (rt_uint32_t)WM8904_PLAY_SOURCE_PGA)
  972. {
  973. reg_value |= (3U << 2U) | 3U;
  974. } else
  975. /* source from DAC */
  976. if(play_source == (rt_uint32_t)WM8904_PLAY_SOURCE_DAC)
  977. {
  978. reg_value &= (rt_uint16_t) ~((3U << 2U) | 3U);
  979. }
  980. return wm8904_modify_register(dev, WM8904_ANALOG_OUT12_ZC, reg_bit_mask, reg_value);
  981. }
  982. /*******************************************************************************************/
  983. rt_err_t wm8904_audio_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  984. {
  985. return RT_EOK;
  986. }
  987. rt_err_t wm8904_audio_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
  988. {
  989. return RT_EOK;
  990. }
  991. rt_err_t wm8904_audio_init(struct rt_audio_device *audio)
  992. {
  993. return RT_EOK;
  994. }
  995. rt_err_t wm8904_audio_start(struct rt_audio_device *audio, int stream)
  996. {
  997. return RT_EOK;
  998. }
  999. rt_err_t wm8904_audio_stop(struct rt_audio_device *audio, int stream)
  1000. {
  1001. return RT_EOK;
  1002. }
  1003. rt_ssize_t wm8904_audio_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size)
  1004. {
  1005. return 0;
  1006. }
  1007. void wm8904_audio_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
  1008. {
  1009. }
  1010. /**
  1011. *
  1012. */
  1013. struct rt_audio_ops wm8904_audio_ops =
  1014. {
  1015. .getcaps = wm8904_audio_getcaps,
  1016. .configure = wm8904_audio_configure,
  1017. .init = wm8904_audio_init,
  1018. .start = wm8904_audio_start,
  1019. .stop = wm8904_audio_stop,
  1020. .transmit = wm8904_audio_transmit,
  1021. .buffer_info = wm8904_audio_buffer_info,
  1022. };