fsl_wm8960.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. * Copyright (c) 2016, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2017 NXP
  4. *
  5. * Redistribution and use in source and binary forms, with or without modification,
  6. * are permitted provided that the following conditions are met:
  7. *
  8. * o Redistributions of source code must retain the above copyright notice, this list
  9. * of conditions and the following disclaimer.
  10. *
  11. * o Redistributions in binary form must reproduce the above copyright notice, this
  12. * list of conditions and the following disclaimer in the documentation and/or
  13. * other materials provided with the distribution.
  14. *
  15. * o Neither the name of the copyright holder nor the names of its
  16. * contributors may be used to endorse or promote products derived from this
  17. * software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  23. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  26. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include "fsl_wm8960.h"
  31. #include "fsl_common.h"
  32. /*******************************************************************************
  33. * Definitations
  34. ******************************************************************************/
  35. /*******************************************************************************
  36. * Prototypes
  37. ******************************************************************************/
  38. /*******************************************************************************
  39. * Variables
  40. ******************************************************************************/
  41. /*
  42. * wm8960 register cache
  43. * We can't read the WM8960 register space when we are
  44. * using 2 wire for device control, so we cache them instead.
  45. */
  46. static const uint16_t wm8960_reg[WM8960_CACHEREGNUM] = {
  47. 0x0097, 0x0097, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x000a, 0x01c0, 0x0000, 0x00ff, 0x00ff, 0x0000, 0x0000,
  48. 0x0000, 0x0000, 0x0000, 0x007b, 0x0100, 0x0032, 0x0000, 0x00c3, 0x00c3, 0x01c0, 0x0000, 0x0000, 0x0000, 0x0000,
  49. 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0100, 0x0050, 0x0050, 0x0050, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000,
  50. 0x0040, 0x0000, 0x0000, 0x0050, 0x0050, 0x0000, 0x0002, 0x0037, 0x004d, 0x0080, 0x0008, 0x0031, 0x0026, 0x00e9,
  51. };
  52. static uint16_t reg_cache[WM8960_CACHEREGNUM];
  53. /*******************************************************************************
  54. * Code
  55. ******************************************************************************/
  56. void WM8960_Init(wm8960_handle_t *handle, wm8960_config_t *config)
  57. {
  58. uint32_t i = 4000000;
  59. memcpy(reg_cache, wm8960_reg, sizeof(wm8960_reg));
  60. /* Set WM8960 I2C address */
  61. handle->xfer.slaveAddress = WM8960_I2C_ADDR;
  62. /* NULL pointer means default setting. */
  63. if (config == NULL)
  64. {
  65. /*
  66. * Reset all registers
  67. */
  68. WM8960_WriteReg(handle, WM8960_RESET, 0x00);
  69. WM8960_WriteReg(handle, WM8960_IFACE2, 0x40);
  70. /*
  71. * VMID=50K, Enable VREF, AINL, AINR, ADCL and ADCR
  72. * I2S_IN (bit 0), I2S_OUT (bit 1), DAP (bit 4), DAC (bit 5), ADC (bit 6) are powered on
  73. */
  74. WM8960_WriteReg(handle, WM8960_POWER1, 0xCA);
  75. /*
  76. * Enable DACL, DACR, LOUT1, ROUT1, PLL down
  77. */
  78. WM8960_WriteReg(handle, WM8960_POWER2, 0x1E0);
  79. /*
  80. * Enable left and right channel input PGA, left and right output mixer
  81. */
  82. WM8960_WriteReg(handle, WM8960_POWER3, 0xC);
  83. /* Configure SYS_FS clock to 44.1kHz, MCLK_FREQ to 256*Fs, SYSCLK derived from MCLK input */
  84. WM8960_WriteReg(handle, WM8960_CLOCK1, 0x00);
  85. /*
  86. * Audio data length = 32bit, Left justified data format
  87. */
  88. WM8960_WriteReg(handle, WM8960_IFACE1, 0x0D);
  89. /*
  90. * LMICBOOST = 0dB, Connect left and right PGA to left and right Input Boost Mixer
  91. */
  92. WM8960_WriteReg(handle, WM8960_LINPATH, 0x18);
  93. WM8960_WriteReg(handle, WM8960_RINPATH, 0x18);
  94. /*
  95. * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
  96. */
  97. WM8960_WriteReg(handle, WM8960_INBMIX1, 0x70);
  98. WM8960_WriteReg(handle, WM8960_INBMIX2, 0x70);
  99. /*
  100. * Left DAC and LINPUT3 to left output mixer, LINPUT3 left output mixer volume = 0dB
  101. */
  102. WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x100);
  103. /*
  104. * Right DAC and RINPUT3 to right output mixer, RINPUT3 right output mixer volume = 0dB
  105. */
  106. WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x100);
  107. WM8960_WriteReg(handle, WM8960_BYPASS1, 0x0);
  108. WM8960_WriteReg(handle, WM8960_BYPASS2, 0x0);
  109. WM8960_WriteReg(handle, WM8960_MONOMIX1, 0x00);
  110. WM8960_WriteReg(handle, WM8960_MONOMIX2, 0x00);
  111. }
  112. else
  113. {
  114. WM8960_SetDataRoute(handle, config->route);
  115. WM8960_SetProtocol(handle, config->bus);
  116. WM8960_SetMasterSlave(handle, config->master_slave);
  117. }
  118. WM8960_WriteReg(handle, WM8960_ADDCTL1, 0x0C4);
  119. WM8960_WriteReg(handle, WM8960_ADDCTL4, 0x40);
  120. /*
  121. * ADC volume, 0dB
  122. */
  123. WM8960_WriteReg(handle, WM8960_LADC, 0x1F3);
  124. WM8960_WriteReg(handle, WM8960_RADC, 0x1F3);
  125. /*
  126. * Digital DAC volume, 0dB
  127. */
  128. WM8960_WriteReg(handle, WM8960_LDAC, 0x1E0);
  129. WM8960_WriteReg(handle, WM8960_RDAC, 0x1E0);
  130. /*
  131. * Headphone volume, LOUT1 and ROUT1, 0dB
  132. */
  133. WM8960_WriteReg(handle, WM8960_LOUT1, 0x16F);
  134. WM8960_WriteReg(handle, WM8960_ROUT1, 0x16F);
  135. /* Delay for some while */
  136. while (i)
  137. {
  138. __ASM("nop");
  139. i--;
  140. }
  141. /* Unmute DAC. */
  142. WM8960_WriteReg(handle, WM8960_DACCTL1, 0x0000);
  143. }
  144. void WM8960_Deinit(wm8960_handle_t *handle)
  145. {
  146. WM8960_SetModule(handle, kWM8960_ModuleADC, false);
  147. WM8960_SetModule(handle, kWM8960_ModuleDAC, false);
  148. WM8960_SetModule(handle, kWM8960_ModuleVREF, false);
  149. WM8960_SetModule(handle, kWM8960_ModuleLineIn, false);
  150. WM8960_SetModule(handle, kWM8960_ModuleLineOut, false);
  151. WM8960_SetModule(handle, kWM8960_ModuleSpeaker, false);
  152. }
  153. void WM8960_SetMasterSlave(wm8960_handle_t *handle, bool master)
  154. {
  155. if (master == 1)
  156. {
  157. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_MASTER));
  158. }
  159. else
  160. {
  161. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_SLAVE));
  162. }
  163. }
  164. status_t WM8960_SetModule(wm8960_handle_t *handle, wm8960_module_t module, bool isEnabled)
  165. {
  166. status_t ret = kStatus_Success;
  167. switch (module)
  168. {
  169. case kWM8960_ModuleADC:
  170. WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_ADCL_MASK,
  171. ((uint16_t)isEnabled << WM8960_POWER1_ADCL_SHIFT));
  172. WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_ADCR_MASK,
  173. ((uint16_t)isEnabled << WM8960_POWER1_ADCR_SHIFT));
  174. break;
  175. case kWM8960_ModuleDAC:
  176. WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_DACL_MASK,
  177. ((uint16_t)isEnabled << WM8960_POWER2_DACL_SHIFT));
  178. WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_DACR_MASK,
  179. ((uint16_t)isEnabled << WM8960_POWER2_DACR_SHIFT));
  180. break;
  181. case kWM8960_ModuleVREF:
  182. WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_VREF_MASK,
  183. ((uint16_t)isEnabled << WM8960_POWER1_VREF_SHIFT));
  184. break;
  185. case kWM8960_ModuleLineIn:
  186. WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_AINL_MASK,
  187. ((uint16_t)isEnabled << WM8960_POWER1_AINL_SHIFT));
  188. WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_AINR_MASK,
  189. ((uint16_t)isEnabled << WM8960_POWER1_AINR_SHIFT));
  190. break;
  191. case kWM8960_ModuleLineOut:
  192. WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_LOUT1_MASK,
  193. ((uint16_t)isEnabled << WM8960_POWER2_LOUT1_SHIFT));
  194. WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_ROUT1_MASK,
  195. ((uint16_t)isEnabled << WM8960_POWER2_ROUT1_SHIFT));
  196. break;
  197. case kWM8960_ModuleSpeaker:
  198. WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_SPKL_MASK,
  199. ((uint16_t)isEnabled << WM8960_POWER2_SPKL_SHIFT));
  200. WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_SPKR_MASK,
  201. ((uint16_t)isEnabled << WM8960_POWER2_SPKR_SHIFT));
  202. WM8960_WriteReg(handle, WM8960_CLASSD1, 0xF7);
  203. break;
  204. default:
  205. ret = kStatus_InvalidArgument;
  206. break;
  207. }
  208. return ret;
  209. }
  210. status_t WM8960_SetDataRoute(wm8960_handle_t *handle, wm8960_route_t route)
  211. {
  212. status_t ret = kStatus_Success;
  213. switch (route)
  214. {
  215. case kWM8960_RouteBypass:
  216. /* Bypass means from line-in to HP*/
  217. /*
  218. * Left LINPUT3 to left output mixer, LINPUT3 left output mixer volume = 0dB
  219. */
  220. WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x80);
  221. /*
  222. * Right RINPUT3 to right output mixer, RINPUT3 right output mixer volume = 0dB
  223. */
  224. WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x80);
  225. break;
  226. case kWM8960_RoutePlayback:
  227. /* Data route I2S_IN-> DAC-> HP */
  228. /*
  229. * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
  230. */
  231. WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x100);
  232. /*
  233. * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
  234. */
  235. WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x100);
  236. break;
  237. case kWM8960_RoutePlaybackandRecord:
  238. /* I2S IN->DAC->HP LINE_IN->ADC->I2S_OUT */
  239. /*
  240. * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
  241. */
  242. WM8960_WriteReg(handle, WM8960_INBMIX1, 0x50);
  243. WM8960_WriteReg(handle, WM8960_INBMIX2, 0x50);
  244. /*
  245. * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
  246. */
  247. WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x100);
  248. /*
  249. * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
  250. */
  251. WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x100);
  252. break;
  253. case kWM8960_RoutePlaybackwithDAP:
  254. /* I2S_IN->DAP->DAC->HP */
  255. break;
  256. case kWM8960_RoutePlaybackwithDAPandRecord:
  257. /* I2S_IN->DAP->DAC->HP, LINE_IN->ADC->I2S_OUT */
  258. break;
  259. case kWM8960_RouteRecord:
  260. /* LINE_IN->ADC->I2S_OUT */
  261. /*
  262. * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
  263. */
  264. WM8960_WriteReg(handle, WM8960_INBMIX1, 0x50);
  265. WM8960_WriteReg(handle, WM8960_INBMIX2, 0x50);
  266. break;
  267. default:
  268. ret = kStatus_InvalidArgument;
  269. break;
  270. }
  271. return ret;
  272. }
  273. status_t WM8960_SetProtocol(wm8960_handle_t *handle, wm8960_protocol_t protocol)
  274. {
  275. status_t ret = kStatus_Success;
  276. switch (protocol)
  277. {
  278. case kWM8960_BusI2S:
  279. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
  280. WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_I2S));
  281. break;
  282. case kWM8960_BusLeftJustified:
  283. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
  284. WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_LJ));
  285. break;
  286. case kWM8960_BusRightJustified:
  287. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
  288. WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_RJ));
  289. break;
  290. case kWM8960_BusPCMA:
  291. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
  292. WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_DSP));
  293. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_LRP_MASK, WM8960_IFACE1_LRP(WM8960_IFACE1_DSP_MODEA));
  294. break;
  295. case kWM8960_BusPCMB:
  296. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
  297. WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_DSP));
  298. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_LRP_MASK, WM8960_IFACE1_LRP(WM8960_IFACE1_DSP_MODEB));
  299. break;
  300. default:
  301. ret = kStatus_InvalidArgument;
  302. break;
  303. }
  304. WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK, WM8960_IFACE1_WL(WM8960_IFACE1_WL_32BITS));
  305. return ret;
  306. }
  307. status_t WM8960_SetVolume(wm8960_handle_t *handle, wm8960_module_t module, uint32_t volume)
  308. {
  309. uint16_t vol = 0;
  310. status_t ret = kStatus_Success;
  311. switch (module)
  312. {
  313. case kWM8960_ModuleADC:
  314. vol = 0x100 | volume;
  315. ret = WM8960_WriteReg(handle, WM8960_LADC, vol);
  316. ret = WM8960_WriteReg(handle, WM8960_RADC, vol);
  317. break;
  318. case kWM8960_ModuleDAC:
  319. vol = 0x100 | volume;
  320. ret = WM8960_WriteReg(handle, WM8960_LDAC, vol);
  321. ret = WM8960_WriteReg(handle, WM8960_RDAC, vol);
  322. break;
  323. case kWM8960_ModuleHP:
  324. vol = 0x100 | volume;
  325. ret = WM8960_WriteReg(handle, WM8960_LOUT1, vol);
  326. ret = WM8960_WriteReg(handle, WM8960_ROUT1, vol);
  327. break;
  328. case kWM8960_ModuleLineIn:
  329. vol = 0x100 | volume;
  330. ret = WM8960_WriteReg(handle, WM8960_LINVOL, vol);
  331. ret = WM8960_WriteReg(handle, WM8960_RINVOL, vol);
  332. break;
  333. case kWM8960_ModuleSpeaker:
  334. vol = 0x100 | volume;
  335. ret = WM8960_WriteReg(handle, WM8960_LOUT2, vol);
  336. ret = WM8960_WriteReg(handle, WM8960_ROUT2, vol);
  337. break;
  338. default:
  339. ret = kStatus_InvalidArgument;
  340. break;
  341. }
  342. return ret;
  343. }
  344. uint32_t WM8960_GetVolume(wm8960_handle_t *handle, wm8960_module_t module)
  345. {
  346. uint16_t vol = 0;
  347. switch (module)
  348. {
  349. case kWM8960_ModuleADC:
  350. WM8960_ReadReg(WM8960_LADC, &vol);
  351. vol &= 0xFF;
  352. break;
  353. case kWM8960_ModuleDAC:
  354. WM8960_ReadReg(WM8960_LDAC, &vol);
  355. vol &= 0xFF;
  356. break;
  357. case kWM8960_ModuleHP:
  358. WM8960_ReadReg(WM8960_LOUT1, &vol);
  359. vol &= 0x7F;
  360. break;
  361. case kWM8960_ModuleLineOut:
  362. WM8960_ReadReg(WM8960_LINVOL, &vol);
  363. vol &= 0x3F;
  364. break;
  365. default:
  366. vol = 0;
  367. break;
  368. }
  369. return vol;
  370. }
  371. status_t WM8960_SetMute(wm8960_handle_t *handle, wm8960_module_t module, bool isEnabled)
  372. {
  373. status_t ret = kStatus_Success;
  374. switch (module)
  375. {
  376. case kWM8960_ModuleADC:
  377. /*
  378. * Digital Mute
  379. */
  380. if (isEnabled)
  381. {
  382. ret = WM8960_WriteReg(handle, WM8960_LADC, 0x100);
  383. ret = WM8960_WriteReg(handle, WM8960_RADC, 0x100);
  384. }
  385. else
  386. {
  387. ret = WM8960_WriteReg(handle, WM8960_LADC, 0x1C3);
  388. ret = WM8960_WriteReg(handle, WM8960_RADC, 0x1C3);
  389. }
  390. break;
  391. case kWM8960_ModuleDAC:
  392. /*
  393. * Digital mute
  394. */
  395. if (isEnabled)
  396. {
  397. ret = WM8960_WriteReg(handle, WM8960_LDAC, 0x100);
  398. ret = WM8960_WriteReg(handle, WM8960_RDAC, 0x100);
  399. }
  400. else
  401. {
  402. ret = WM8960_WriteReg(handle, WM8960_LDAC, 0x1FF);
  403. ret = WM8960_WriteReg(handle, WM8960_RDAC, 0x1FF);
  404. }
  405. break;
  406. case kWM8960_ModuleHP:
  407. /*
  408. * Analog mute
  409. */
  410. if (isEnabled)
  411. {
  412. ret = WM8960_WriteReg(handle, WM8960_LOUT1, 0x100);
  413. ret = WM8960_WriteReg(handle, WM8960_ROUT1, 0x100);
  414. }
  415. else
  416. {
  417. ret = WM8960_WriteReg(handle, WM8960_LOUT1, 0x179);
  418. ret = WM8960_WriteReg(handle, WM8960_ROUT1, 0x179);
  419. }
  420. break;
  421. case kWM8960_ModuleLineOut:
  422. break;
  423. default:
  424. ret = kStatus_InvalidArgument;
  425. break;
  426. }
  427. return ret;
  428. }
  429. status_t WM8960_ConfigDataFormat(wm8960_handle_t *handle, uint32_t mclk, uint32_t sample_rate, uint8_t bits)
  430. {
  431. status_t retval = kStatus_Success;
  432. switch (sample_rate)
  433. {
  434. case 8000:
  435. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x1B0);
  436. break;
  437. case 11025:
  438. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
  439. break;
  440. case 12000:
  441. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x120);
  442. break;
  443. case 16000:
  444. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
  445. break;
  446. case 22050:
  447. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
  448. break;
  449. case 24000:
  450. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x90);
  451. break;
  452. case 32000:
  453. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x48);
  454. break;
  455. case 44100:
  456. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
  457. break;
  458. case 48000:
  459. retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x00);
  460. break;
  461. default:
  462. retval = kStatus_InvalidArgument;
  463. break;
  464. }
  465. /*
  466. * Slave mode (MS = 0), LRP = 0, 32bit WL, left justified (FORMAT[1:0]=0b01)
  467. */
  468. switch (bits)
  469. {
  470. case 16:
  471. retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  472. WM8960_IFACE1_WL(WM8960_IFACE1_WL_16BITS));
  473. break;
  474. case 20:
  475. retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  476. WM8960_IFACE1_WL(WM8960_IFACE1_WL_20BITS));
  477. break;
  478. case 24:
  479. retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  480. WM8960_IFACE1_WL(WM8960_IFACE1_WL_24BITS));
  481. break;
  482. case 32:
  483. retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  484. WM8960_IFACE1_WL(WM8960_IFACE1_WL_32BITS));
  485. break;
  486. default:
  487. retval = kStatus_InvalidArgument;
  488. break;
  489. }
  490. return retval;
  491. }
  492. status_t WM8960_SetJackDetect(wm8960_handle_t *handle, bool isEnabled)
  493. {
  494. uint8_t retval = 0;
  495. uint16_t val = 0;
  496. WM8960_ReadReg(WM8960_ADDCTL2, &val);
  497. if (isEnabled)
  498. {
  499. val |= 0x40U;
  500. }
  501. else
  502. {
  503. val &= 0xCF;
  504. }
  505. retval = WM8960_WriteReg(handle, WM8960_ADDCTL2, val);
  506. return retval;
  507. }
  508. status_t WM8960_WriteReg(wm8960_handle_t *handle, uint8_t reg, uint16_t val)
  509. {
  510. uint8_t cmd, buff;
  511. uint8_t retval = 0;
  512. /* The register address */
  513. cmd = (reg << 1) | ((val >> 8U) & 0x0001U);
  514. /* Data */
  515. buff = val & 0xFF;
  516. /* Copy data to cache */
  517. reg_cache[reg] = val;
  518. #if defined(FSL_FEATURE_SOC_LPI2C_COUNT) && (FSL_FEATURE_SOC_LPI2C_COUNT)
  519. uint8_t data[2];
  520. data[0] = cmd;
  521. data[1] = buff;
  522. retval = LPI2C_MasterStart(handle->base, WM8960_I2C_ADDR, kLPI2C_Write);
  523. retval = LPI2C_MasterSend(handle->base, data, 2);
  524. retval = LPI2C_MasterStop(handle->base);
  525. #else
  526. /* Config the I2C xfer */
  527. handle->xfer.direction = kI2C_Write;
  528. handle->xfer.subaddress = cmd;
  529. handle->xfer.subaddressSize = 1U;
  530. handle->xfer.data = &buff;
  531. handle->xfer.dataSize = 1U;
  532. retval = I2C_MasterTransferBlocking(handle->base, &handle->xfer);
  533. #endif
  534. if (retval != kStatus_Success)
  535. {
  536. return kStatus_Fail;
  537. }
  538. return kStatus_Success;
  539. }
  540. status_t WM8960_ReadReg(uint8_t reg, uint16_t *val)
  541. {
  542. if (reg >= WM8960_CACHEREGNUM)
  543. {
  544. return kStatus_InvalidArgument;
  545. }
  546. *val = reg_cache[reg];
  547. return kStatus_Success;
  548. }
  549. status_t WM8960_ModifyReg(wm8960_handle_t *handle, uint8_t reg, uint16_t mask, uint16_t val)
  550. {
  551. uint8_t retval = 0;
  552. uint16_t reg_val = 0;
  553. retval = WM8960_ReadReg(reg, &reg_val);
  554. if (retval != kStatus_Success)
  555. {
  556. return kStatus_Fail;
  557. }
  558. reg_val &= (uint16_t)~mask;
  559. reg_val |= val;
  560. retval = WM8960_WriteReg(handle, reg, reg_val);
  561. if (retval != kStatus_Success)
  562. {
  563. return kStatus_Fail;
  564. }
  565. return kStatus_Success;
  566. }