bsp_wm8960.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-12-05 zylx The first version for STM32F4xx
  9. * 2019-4-25 misonyo port to IMXRT
  10. */
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include "bsp_wm8960.h"
  14. #include <stdlib.h>
  15. #include <drv_log.h>
  16. #include <rthw.h>
  17. static rt_uint16_t wm8960_regval_tbl[56] = {
  18. 0x0097, 0x0097, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x000a, 0x01c0, 0x0000, 0x00ff, 0x00ff, 0x0000, 0x0000,
  19. 0x0000, 0x0000, 0x0000, 0x007b, 0x0100, 0x0032, 0x0000, 0x00c3, 0x00c3, 0x01c0, 0x0000, 0x0000, 0x0000, 0x0000,
  20. 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0100, 0x0050, 0x0050, 0x0050, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000,
  21. 0x0040, 0x0000, 0x0000, 0x0050, 0x0050, 0x0000, 0x0002, 0x0037, 0x004d, 0x0080, 0x0008, 0x0031, 0x0026, 0x00e9,
  22. };
  23. static rt_uint16_t reg_cache[WM8960_CACHEREGNUM];
  24. static void wm8960_write_reg(struct rt_i2c_bus_device *dev, rt_uint8_t reg, rt_uint16_t val)
  25. {
  26. struct rt_i2c_msg msg;
  27. rt_uint8_t send_buffer[2];
  28. RT_ASSERT(dev != RT_NULL);
  29. /* store temp */
  30. rt_uint16_t buff = val;
  31. reg_cache[reg] = buff;
  32. send_buffer[0] = (reg << 1) | ((val >> 8U) & 0x0001U);
  33. send_buffer[1] = (rt_uint8_t)(val & 0xFF);
  34. msg.addr = 0x1A;////WM8960_I2C_ADDR 0x1A
  35. msg.flags = RT_I2C_WR;
  36. msg.len = 2;
  37. msg.buf = send_buffer;
  38. rt_i2c_transfer(dev, &msg, 1);
  39. }
  40. static void wm8960_read_reg(struct rt_i2c_bus_device *dev, rt_uint8_t reg, rt_uint16_t *val)
  41. {
  42. *val = reg_cache[reg];
  43. }
  44. static void wm8960_modify_reg(struct rt_i2c_bus_device *dev, rt_uint8_t reg, rt_uint16_t mask, rt_uint16_t val)
  45. {
  46. uint16_t reg_val = 0;
  47. wm8960_read_reg(dev, reg, &reg_val);
  48. reg_val &= (rt_uint16_t)~mask;
  49. reg_val |= val;
  50. wm8960_write_reg(dev, reg, reg_val);
  51. }
  52. void WM8960_SetMasterSlave(struct rt_i2c_bus_device *dev, rt_bool_t master)
  53. {
  54. if (master == 1)
  55. {
  56. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_MASTER));
  57. }
  58. else
  59. {
  60. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_SLAVE));
  61. }
  62. }
  63. void WM8960_SetModule(struct rt_i2c_bus_device *dev, wm8960_module_t module, rt_bool_t isEnabled)
  64. {
  65. switch (module)
  66. {
  67. case kWM8960_ModuleADC:
  68. wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_ADCL_MASK,
  69. ((uint16_t)isEnabled << WM8960_POWER1_ADCL_SHIFT));
  70. wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_ADCR_MASK,
  71. ((uint16_t)isEnabled << WM8960_POWER1_ADCR_SHIFT));
  72. break;
  73. case kWM8960_ModuleDAC:
  74. wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_DACL_MASK,
  75. ((uint16_t)isEnabled << WM8960_POWER2_DACL_SHIFT));
  76. wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_DACR_MASK,
  77. ((uint16_t)isEnabled << WM8960_POWER2_DACR_SHIFT));
  78. break;
  79. case kWM8960_ModuleVREF:
  80. wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_VREF_MASK,
  81. ((uint16_t)isEnabled << WM8960_POWER1_VREF_SHIFT));
  82. break;
  83. case kWM8960_ModuleLineIn:
  84. wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_AINL_MASK,
  85. ((uint16_t)isEnabled << WM8960_POWER1_AINL_SHIFT));
  86. wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_AINR_MASK,
  87. ((uint16_t)isEnabled << WM8960_POWER1_AINR_SHIFT));
  88. break;
  89. case kWM8960_ModuleLineOut:
  90. wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_LOUT1_MASK,
  91. ((uint16_t)isEnabled << WM8960_POWER2_LOUT1_SHIFT));
  92. wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_ROUT1_MASK,
  93. ((uint16_t)isEnabled << WM8960_POWER2_ROUT1_SHIFT));
  94. break;
  95. case kWM8960_ModuleMICB:
  96. wm8960_modify_reg(dev, WM8960_POWER1, WM8960_POWER1_MICB_MASK,
  97. ((uint16_t)isEnabled << WM8960_POWER1_MICB_SHIFT));
  98. break;
  99. case kWM8960_ModuleSpeaker:
  100. wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_SPKL_MASK,
  101. ((uint16_t)isEnabled << WM8960_POWER2_SPKL_SHIFT));
  102. wm8960_modify_reg(dev, WM8960_POWER2, WM8960_POWER2_SPKR_MASK,
  103. ((uint16_t)isEnabled << WM8960_POWER2_SPKR_SHIFT));
  104. wm8960_write_reg(dev, WM8960_CLASSD1, 0xF7);
  105. break;
  106. case kWM8960_ModuleMIC:
  107. wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_LMIC_MASK,
  108. ((uint16_t)isEnabled << WM8960_POWER3_LMIC_SHIFT));
  109. wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_RMIC_MASK,
  110. ((uint16_t)isEnabled << WM8960_POWER3_RMIC_SHIFT));
  111. break;
  112. case kWM8960_ModuleOMIX:
  113. wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_LOMIX_MASK,
  114. ((uint16_t)isEnabled << WM8960_POWER3_LOMIX_SHIFT));
  115. wm8960_modify_reg(dev, WM8960_POWER3, WM8960_POWER3_ROMIX_MASK,
  116. ((uint16_t)isEnabled << WM8960_POWER3_ROMIX_SHIFT));
  117. break;
  118. default:
  119. break;
  120. }
  121. }
  122. void WM8960_SetDataRoute(struct rt_i2c_bus_device *dev, wm8960_route_t route)
  123. {
  124. switch (route)
  125. {
  126. case kWM8960_RouteBypass:
  127. /* Bypass means from line-in to HP*/
  128. /*
  129. * Left LINPUT3 to left output mixer, LINPUT3 left output mixer volume = 0dB
  130. */
  131. wm8960_write_reg(dev, WM8960_LOUTMIX, 0x80);
  132. /*
  133. * Right RINPUT3 to right output mixer, RINPUT3 right output mixer volume = 0dB
  134. */
  135. wm8960_write_reg(dev, WM8960_ROUTMIX, 0x80);
  136. break;
  137. case kWM8960_RoutePlayback:
  138. /* Data route I2S_IN-> DAC-> HP */
  139. /*
  140. * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
  141. */
  142. wm8960_write_reg(dev, WM8960_LOUTMIX, 0x100);
  143. /*
  144. * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
  145. */
  146. wm8960_write_reg(dev, WM8960_ROUTMIX, 0x100);
  147. wm8960_write_reg(dev, WM8960_POWER3, 0x0C);
  148. /* Set power for DAC */
  149. WM8960_SetModule(dev, kWM8960_ModuleDAC, RT_TRUE);
  150. WM8960_SetModule(dev, kWM8960_ModuleOMIX, RT_TRUE);
  151. WM8960_SetModule(dev, kWM8960_ModuleLineOut, RT_TRUE);
  152. break;
  153. case kWM8960_RoutePlaybackandRecord:
  154. /*
  155. * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
  156. */
  157. wm8960_write_reg(dev, WM8960_LOUTMIX, 0x100);
  158. /*
  159. * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
  160. */
  161. wm8960_write_reg(dev, WM8960_ROUTMIX, 0x100);
  162. wm8960_write_reg(dev, WM8960_POWER3, 0x3C);
  163. WM8960_SetModule(dev, kWM8960_ModuleDAC, RT_TRUE);
  164. WM8960_SetModule(dev, kWM8960_ModuleADC, RT_TRUE);
  165. WM8960_SetModule(dev, kWM8960_ModuleLineIn, RT_TRUE);
  166. WM8960_SetModule(dev, kWM8960_ModuleOMIX, RT_TRUE);
  167. WM8960_SetModule(dev, kWM8960_ModuleLineOut, RT_TRUE);
  168. break;
  169. case kWM8960_RouteRecord:
  170. /* LINE_IN->ADC->I2S_OUT */
  171. /*
  172. * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
  173. */
  174. wm8960_write_reg(dev, WM8960_POWER3, 0x30);
  175. /* Power up ADC and AIN */
  176. WM8960_SetModule(dev, kWM8960_ModuleLineIn, RT_TRUE);
  177. WM8960_SetModule(dev, kWM8960_ModuleADC, RT_TRUE);
  178. break;
  179. default:
  180. break;
  181. }
  182. }
  183. void WM8960_SetLeftInput(struct rt_i2c_bus_device *dev, wm8960_input_t input)
  184. {
  185. uint16_t val = 0;
  186. switch (input)
  187. {
  188. case kWM8960_InputSingleEndedMic:
  189. /* Only LMN1 enabled, LMICBOOST to 13db, LMIC2B enabled */
  190. wm8960_read_reg(dev,WM8960_POWER1, &val);
  191. val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK | WM8960_POWER1_MICB_MASK);
  192. wm8960_write_reg(dev, WM8960_POWER1, val);
  193. wm8960_write_reg(dev, WM8960_LINPATH, 0x138);
  194. wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
  195. break;
  196. case kWM8960_InputDifferentialMicInput2:
  197. wm8960_read_reg(dev,WM8960_POWER1, &val);
  198. val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK | WM8960_POWER1_MICB_MASK);
  199. wm8960_write_reg(dev, WM8960_POWER1, val);
  200. wm8960_write_reg(dev, WM8960_LINPATH, 0x178);
  201. wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
  202. break;
  203. case kWM8960_InputDifferentialMicInput3:
  204. wm8960_read_reg(dev,WM8960_POWER1, &val);
  205. val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK | WM8960_POWER1_MICB_MASK);
  206. wm8960_write_reg(dev, WM8960_POWER1, val);
  207. wm8960_write_reg(dev, WM8960_LINPATH, 0x1B8);
  208. wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
  209. break;
  210. case kWM8960_InputLineINPUT2:
  211. wm8960_read_reg(dev,WM8960_POWER1, &val);
  212. val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK);
  213. wm8960_write_reg(dev, WM8960_POWER1, val);
  214. wm8960_read_reg(dev,WM8960_INBMIX1, &val);
  215. val |= 0xE;
  216. wm8960_write_reg(dev, WM8960_INBMIX1, val);
  217. break;
  218. case kWM8960_InputLineINPUT3:
  219. wm8960_read_reg(dev,WM8960_POWER1, &val);
  220. val |= (WM8960_POWER1_AINL_MASK | WM8960_POWER1_ADCL_MASK);
  221. wm8960_write_reg(dev, WM8960_POWER1, val);
  222. wm8960_read_reg(dev,WM8960_INBMIX1, &val);
  223. val |= 0x70;
  224. wm8960_write_reg(dev, WM8960_INBMIX1, val);
  225. break;
  226. default:
  227. break;
  228. }
  229. }
  230. void WM8960_SetRightInput(struct rt_i2c_bus_device *dev, wm8960_input_t input)
  231. {
  232. uint16_t val = 0;
  233. switch (input)
  234. {
  235. case kWM8960_InputSingleEndedMic:
  236. /* Only LMN1 enabled, LMICBOOST to 13db, LMIC2B enabled */
  237. wm8960_read_reg(dev,WM8960_POWER1, &val);
  238. val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK | WM8960_POWER1_MICB_MASK);
  239. wm8960_write_reg(dev, WM8960_POWER1, val);
  240. wm8960_write_reg(dev, WM8960_RINPATH, 0x138);
  241. wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
  242. break;
  243. case kWM8960_InputDifferentialMicInput2:
  244. wm8960_read_reg(dev,WM8960_POWER1, &val);
  245. val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK | WM8960_POWER1_MICB_MASK);
  246. wm8960_write_reg(dev, WM8960_POWER1, val);
  247. wm8960_write_reg(dev, WM8960_RINPATH, 0x178);
  248. wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
  249. break;
  250. case kWM8960_InputDifferentialMicInput3:
  251. wm8960_read_reg(dev,WM8960_POWER1, &val);
  252. val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK | WM8960_POWER1_MICB_MASK);
  253. wm8960_write_reg(dev, WM8960_POWER1, val);
  254. wm8960_write_reg(dev, WM8960_RINPATH, 0x1B8);
  255. wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
  256. break;
  257. case kWM8960_InputLineINPUT2:
  258. wm8960_read_reg(dev,WM8960_POWER1, &val);
  259. val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK);
  260. wm8960_write_reg(dev, WM8960_POWER1, val);
  261. wm8960_read_reg(dev,WM8960_INBMIX2, &val);
  262. val |= 0xE;
  263. wm8960_write_reg(dev, WM8960_INBMIX2, val);
  264. break;
  265. case kWM8960_InputLineINPUT3:
  266. wm8960_read_reg(dev,WM8960_POWER1, &val);
  267. val |= (WM8960_POWER1_AINR_MASK | WM8960_POWER1_ADCR_MASK);
  268. wm8960_write_reg(dev, WM8960_POWER1, val);
  269. wm8960_read_reg(dev,WM8960_INBMIX2, &val);
  270. val |= 0x70;
  271. wm8960_write_reg(dev, WM8960_INBMIX2, val);
  272. break;
  273. default:
  274. break;
  275. }
  276. }
  277. void WM8960_SetProtocol(struct rt_i2c_bus_device *dev, wm8960_protocol_t protocol)
  278. {
  279. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK | WM8960_IFACE1_LRP_MASK, protocol);
  280. }
  281. void WM8960_SetVolume(struct rt_i2c_bus_device *dev, wm8960_module_t module, rt_uint32_t volume)
  282. {
  283. uint16_t vol = 0;
  284. switch (module)
  285. {
  286. case kWM8960_ModuleADC:
  287. vol = volume;
  288. wm8960_write_reg(dev, WM8960_LADC, vol);
  289. wm8960_write_reg(dev, WM8960_RADC, vol);
  290. /* Update volume */
  291. vol = 0x100 | volume;
  292. wm8960_write_reg(dev, WM8960_LADC, vol);
  293. wm8960_write_reg(dev, WM8960_RADC, vol);
  294. break;
  295. case kWM8960_ModuleDAC:
  296. vol = volume;
  297. wm8960_write_reg(dev, WM8960_LDAC, vol);
  298. wm8960_write_reg(dev, WM8960_RDAC, vol);
  299. vol = 0x100 | volume;
  300. wm8960_write_reg(dev, WM8960_LDAC, vol);
  301. wm8960_write_reg(dev, WM8960_RDAC, vol);
  302. break;
  303. case kWM8960_ModuleHP:
  304. vol = volume;
  305. wm8960_write_reg(dev, WM8960_LOUT1, vol);
  306. wm8960_write_reg(dev, WM8960_ROUT1, vol);
  307. vol = 0x100 | volume;
  308. wm8960_write_reg(dev, WM8960_LOUT1, vol);
  309. wm8960_write_reg(dev, WM8960_ROUT1, vol);
  310. break;
  311. case kWM8960_ModuleLineIn:
  312. vol = volume;
  313. wm8960_write_reg(dev, WM8960_LINVOL, vol);
  314. wm8960_write_reg(dev, WM8960_RINVOL, vol);
  315. vol = 0x100 | volume;
  316. wm8960_write_reg(dev, WM8960_LINVOL, vol);
  317. wm8960_write_reg(dev, WM8960_RINVOL, vol);
  318. break;
  319. case kWM8960_ModuleSpeaker:
  320. vol = volume;
  321. wm8960_write_reg(dev, WM8960_LOUT2, vol);
  322. wm8960_write_reg(dev, WM8960_ROUT2, vol);
  323. vol = 0x100 | volume;
  324. wm8960_write_reg(dev, WM8960_LOUT2, vol);
  325. wm8960_write_reg(dev, WM8960_ROUT2, vol);
  326. break;
  327. default:
  328. break;
  329. }
  330. }
  331. rt_uint32_t WM8960_GetVolume(struct rt_i2c_bus_device *dev, wm8960_module_t module)
  332. {
  333. uint16_t vol = 0;
  334. switch (module)
  335. {
  336. case kWM8960_ModuleADC:
  337. wm8960_read_reg(dev,WM8960_LADC, &vol);
  338. vol &= 0xFF;
  339. break;
  340. case kWM8960_ModuleDAC:
  341. wm8960_read_reg(dev,WM8960_LDAC, &vol);
  342. vol &= 0xFF;
  343. break;
  344. case kWM8960_ModuleHP:
  345. wm8960_read_reg(dev,WM8960_LOUT1, &vol);
  346. vol &= 0x7F;
  347. break;
  348. case kWM8960_ModuleLineOut:
  349. wm8960_read_reg(dev,WM8960_LINVOL, &vol);
  350. vol &= 0x3F;
  351. break;
  352. default:
  353. vol = 0;
  354. break;
  355. }
  356. return vol;
  357. }
  358. void WM8960_SetMute(struct rt_i2c_bus_device *dev, wm8960_module_t module, rt_bool_t isEnabled)
  359. {
  360. switch (module)
  361. {
  362. case kWM8960_ModuleADC:
  363. /*
  364. * Digital Mute
  365. */
  366. if (isEnabled)
  367. {
  368. wm8960_write_reg(dev, WM8960_LADC, 0x100);
  369. wm8960_write_reg(dev, WM8960_RADC, 0x100);
  370. }
  371. else
  372. {
  373. wm8960_write_reg(dev, WM8960_LADC, 0x1C3);
  374. wm8960_write_reg(dev, WM8960_RADC, 0x1C3);
  375. }
  376. break;
  377. case kWM8960_ModuleDAC:
  378. /*
  379. * Digital mute
  380. */
  381. if (isEnabled)
  382. {
  383. wm8960_write_reg(dev, WM8960_LDAC, 0x100);
  384. wm8960_write_reg(dev, WM8960_RDAC, 0x100);
  385. }
  386. else
  387. {
  388. wm8960_write_reg(dev, WM8960_LDAC, 0x1FF);
  389. wm8960_write_reg(dev, WM8960_RDAC, 0x1FF);
  390. }
  391. break;
  392. case kWM8960_ModuleHP:
  393. /*
  394. * Analog mute
  395. */
  396. if (isEnabled)
  397. {
  398. wm8960_write_reg(dev, WM8960_LOUT1, 0x100);
  399. wm8960_write_reg(dev, WM8960_ROUT1, 0x100);
  400. }
  401. else
  402. {
  403. wm8960_write_reg(dev, WM8960_LOUT1, 0x16F);
  404. wm8960_write_reg(dev, WM8960_ROUT1, 0x16F);
  405. }
  406. break;
  407. case kWM8960_ModuleSpeaker:
  408. if (isEnabled)
  409. {
  410. wm8960_write_reg(dev, WM8960_LOUT2, 0x100);
  411. wm8960_write_reg(dev, WM8960_ROUT2, 0x100);
  412. }
  413. else
  414. {
  415. wm8960_write_reg(dev, WM8960_LOUT2, 0x16F);
  416. wm8960_write_reg(dev, WM8960_ROUT2, 0x16f);
  417. }
  418. break;
  419. case kWM8960_ModuleLineOut:
  420. break;
  421. default:
  422. break;
  423. }
  424. }
  425. void WM8960_ConfigDataFormat(struct rt_i2c_bus_device *dev, rt_uint32_t sysclk, rt_uint32_t sample_rate, rt_uint32_t bits)
  426. {
  427. uint32_t divider = 0;
  428. uint16_t val = 0;
  429. /* Compute sample rate divider, dac and adc are the same sample rate */
  430. divider = sysclk / sample_rate;
  431. if (divider == 256)
  432. {
  433. val = 0;
  434. }
  435. if (divider > 256)
  436. {
  437. val = (((divider / 256U) << 6U) | ((divider / 256U) << 3U));
  438. }
  439. wm8960_write_reg(dev, WM8960_CLOCK1, val);
  440. /* Compute bclk divider */
  441. divider /= bits * 2;
  442. switch (divider)
  443. {
  444. case 4:
  445. case 5:
  446. case 6:
  447. val = (0x1C0 | divider);
  448. break;
  449. case 8:
  450. val = 0x1C7;
  451. break;
  452. case 11:
  453. val = 0x1C8;
  454. break;
  455. case 12:
  456. val = 0x1C9;
  457. break;
  458. case 16:
  459. val = 0x1CA;
  460. break;
  461. case 22:
  462. val = 0x1CB;
  463. break;
  464. case 24:
  465. val = 0x1CC;
  466. break;
  467. case 32:
  468. val = 0x1CF;
  469. break;
  470. default:
  471. break;
  472. }
  473. wm8960_write_reg(dev, WM8960_CLOCK2, val);
  474. /*
  475. * Slave mode (MS = 0), LRP = 0, 32bit WL, left justified (FORMAT[1:0]=0b01)
  476. */
  477. switch (bits)
  478. {
  479. case 16:
  480. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  481. WM8960_IFACE1_WL(WM8960_IFACE1_WL_16BITS));
  482. break;
  483. case 20:
  484. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  485. WM8960_IFACE1_WL(WM8960_IFACE1_WL_20BITS));
  486. break;
  487. case 24:
  488. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  489. WM8960_IFACE1_WL(WM8960_IFACE1_WL_24BITS));
  490. break;
  491. case 32:
  492. wm8960_modify_reg(dev, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
  493. WM8960_IFACE1_WL(WM8960_IFACE1_WL_32BITS));
  494. break;
  495. default:
  496. break;
  497. }
  498. }
  499. void WM8960_Deinit(struct rt_i2c_bus_device *dev)
  500. {
  501. WM8960_SetModule(dev, kWM8960_ModuleADC, RT_FALSE);
  502. WM8960_SetModule(dev, kWM8960_ModuleDAC, RT_FALSE);
  503. WM8960_SetModule(dev, kWM8960_ModuleVREF, RT_FALSE);
  504. WM8960_SetModule(dev, kWM8960_ModuleLineIn, RT_FALSE);
  505. WM8960_SetModule(dev, kWM8960_ModuleLineOut, RT_FALSE);
  506. WM8960_SetModule(dev, kWM8960_ModuleSpeaker, RT_FALSE);
  507. }
  508. void WM8960_init(struct rt_i2c_bus_device *dev, wm8960_config_t *wm8960Config)
  509. {
  510. wm8960_config_t *config = wm8960Config;
  511. rt_memcpy(reg_cache, wm8960_regval_tbl, sizeof(wm8960_regval_tbl));
  512. /* Reset the codec */
  513. wm8960_write_reg(dev, WM8960_RESET, 0x00);
  514. /*
  515. * VMID=50K, Enable VREF, AINL, AINR, ADCL and ADCR
  516. * I2S_IN (bit 0), I2S_OUT (bit 1), DAP (bit 4), DAC (bit 5), ADC (bit 6) are powered on
  517. */
  518. wm8960_write_reg(dev, WM8960_POWER1, 0xFE);
  519. /*
  520. * Enable DACL, DACR, LOUT1, ROUT1, PLL down
  521. */
  522. wm8960_write_reg(dev, WM8960_POWER2, 0x1E0);
  523. /*
  524. * Enable left and right channel input PGA, left and right output mixer
  525. */
  526. wm8960_write_reg(dev, WM8960_POWER3, 0x3C);
  527. /* ADC and DAC uses same clock */
  528. wm8960_write_reg(dev, WM8960_IFACE2, 0x40);
  529. /* set data route */
  530. WM8960_SetDataRoute(dev, config->route);
  531. /* set data protocol */
  532. WM8960_SetProtocol(dev, config->bus);
  533. /* set master or slave */
  534. WM8960_SetMasterSlave(dev, config->master_slave);
  535. /* select left input */
  536. WM8960_SetLeftInput(dev, config->leftInputSource);
  537. /* select right input */
  538. WM8960_SetRightInput(dev, config->rightInputSource);
  539. /* speaker power */
  540. if (config->enableSpeaker)
  541. {
  542. WM8960_SetModule(dev, kWM8960_ModuleSpeaker, RT_TRUE);
  543. }
  544. wm8960_write_reg(dev, WM8960_ADDCTL1, 0x0C0);
  545. wm8960_write_reg(dev, WM8960_ADDCTL4, 0x40);
  546. wm8960_write_reg(dev, WM8960_BYPASS1, 0x0);
  547. wm8960_write_reg(dev, WM8960_BYPASS2, 0x0);
  548. /*
  549. * ADC volume, 0dB
  550. */
  551. wm8960_write_reg(dev, WM8960_LADC, 0x1C3);
  552. wm8960_write_reg(dev, WM8960_RADC, 0x1C3);
  553. /*
  554. * Digital DAC volume, 0dB
  555. */
  556. wm8960_write_reg(dev, WM8960_LDAC, 0x1E0);
  557. wm8960_write_reg(dev, WM8960_RDAC, 0x1E0);
  558. /*
  559. * Headphone volume, LOUT1 and ROUT1, 0dB
  560. */
  561. wm8960_write_reg(dev, WM8960_LOUT1, 0x16F);
  562. wm8960_write_reg(dev, WM8960_ROUT1, 0x16F);
  563. /* Unmute DAC. */
  564. wm8960_write_reg(dev, WM8960_DACCTL1, 0x0000);
  565. wm8960_write_reg(dev, WM8960_LINVOL, 0x117);
  566. wm8960_write_reg(dev, WM8960_RINVOL, 0x117);
  567. WM8960_ConfigDataFormat(dev, config->format.mclk_HZ, config->format.sampleRate, config->format.bitWidth);
  568. }
  569. void WM8960_SetPlay(struct rt_i2c_bus_device *dev, uint32_t playSource)
  570. {
  571. if (kWM8960_PlaySourcePGA & playSource)
  572. {
  573. wm8960_modify_reg(dev, WM8960_BYPASS1, 0x80U, 0x80U);
  574. wm8960_modify_reg(dev, WM8960_BYPASS2, 0x80U, 0x80U);
  575. wm8960_modify_reg(dev, WM8960_LOUTMIX, 0x180U, 0U);
  576. wm8960_modify_reg(dev, WM8960_ROUTMIX, 0x180U, 0U);
  577. }
  578. if (playSource & kWM8960_PlaySourceDAC)
  579. {
  580. wm8960_modify_reg(dev, WM8960_BYPASS1, 0x80U, 0x00U);
  581. wm8960_modify_reg(dev, WM8960_BYPASS2, 0x80U, 0x00U);
  582. wm8960_modify_reg(dev, WM8960_LOUTMIX, 0x180U, 0x100U);
  583. wm8960_modify_reg(dev, WM8960_ROUTMIX, 0x180U, 0x100U);
  584. }
  585. if (playSource & kWM8960_PlaySourceInput)
  586. {
  587. wm8960_modify_reg(dev, WM8960_BYPASS1, 0x80U, 0x0U);
  588. wm8960_modify_reg(dev, WM8960_BYPASS2, 0x80U, 0x0U);
  589. wm8960_modify_reg(dev, WM8960_LOUTMIX, 0x180U, 0x80U);
  590. wm8960_modify_reg(dev, WM8960_ROUTMIX, 0x180U, 0x80U);
  591. }
  592. }