mc97.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * mc97.c
  3. *
  4. * MC97 controller
  5. *
  6. * Copyright (C) 2021 Sylvain Munaut
  7. * SPDX-License-Identifier: LGPL-3.0-or-later
  8. */
  9. #include <stdbool.h>
  10. #include <stdint.h>
  11. #include "console.h"
  12. #include "mc97.h"
  13. #include "mc97_country.h"
  14. #include "config.h"
  15. struct wb_mc97 {
  16. uint32_t csr;
  17. uint32_t lls;
  18. uint32_t cra;
  19. uint32_t _rsvd;
  20. uint32_t gpio_in;
  21. uint32_t gpio_out;
  22. uint32_t fifo_data;
  23. uint32_t fifo_csr;
  24. } __attribute__((packed,aligned(4)));
  25. #define MC97_CSR_RFI (1 << 3)
  26. #define MC97_CSR_GPIO_ENA (1 << 2)
  27. #define MC97_CSR_RESET_N (1 << 1)
  28. #define MC97_CSR_RUN (1 << 0)
  29. #define MC97_LLS_CODEC_READY (1 << 31)
  30. #define MC97_LLS_SLOT_REQ(n) (1 << ((n)+16))
  31. #define MC97_LLS_SLOT_VALID(n) (1 << ((n)+16))
  32. #define MC97_CRA_BUSY (1 << 31)
  33. #define MC97_CRA_WRITE (1 << 30)
  34. #define MC97_CRA_READ_ERR (1 << 29)
  35. #define MC97_CRA_ADDR(x) (((x) >> 1) << 16)
  36. #define MC97_CRA_VAL(x) (x)
  37. #define MC97_CRA_GET_VAL(x) ((x) & 0xffff)
  38. #define MC97_FIFO_DATA_EMPTY (1 << 31)
  39. #define MC97_FIFO_CSR_PCM_IN_ENABLE (1 << 31)
  40. #define MC97_FIFO_CSR_PCM_IN_FLUSH (1 << 30)
  41. #define MC97_FIFO_CSR_PCM_IN_FULL (1 << 29)
  42. #define MC97_FIFO_CSR_PCM_IN_EMPTY (1 << 28)
  43. #define MC97_FIFO_CSR_PCM_IN_LEVEL(x) (((x) >> 16) & 0xfff)
  44. #define MC97_FIFO_CSR_PCM_OUT_ENABLE (1 << 15)
  45. #define MC97_FIFO_CSR_PCM_OUT_FLUSH (1 << 14)
  46. #define MC97_FIFO_CSR_PCM_OUT_FULL (1 << 13)
  47. #define MC97_FIFO_CSR_PCM_OUT_EMPTY (1 << 12)
  48. #define MC97_FIFO_CSR_PCM_OUT_LEVEL(x) ((x) & 0xfff)
  49. static volatile struct wb_mc97 * const mc97_regs = (void*)(MC97_BASE);
  50. static struct {
  51. uint16_t rc_46; /* Cache of reg 0x46 */
  52. uint16_t rc_5c; /* Cache of reg 0x5c */
  53. uint16_t rc_62; /* Cache of reg 0x62 */
  54. bool test_ring;
  55. } g_mc97;
  56. void
  57. mc97_codec_reg_write(uint8_t addr, uint16_t val)
  58. {
  59. /* Submit request */
  60. mc97_regs->cra =
  61. MC97_CRA_WRITE |
  62. MC97_CRA_ADDR(addr) |
  63. MC97_CRA_VAL(val);
  64. /* Wait until not busy */
  65. while (mc97_regs->cra & MC97_CRA_BUSY);
  66. }
  67. uint16_t
  68. mc97_codec_reg_read(uint8_t addr)
  69. {
  70. uint32_t v;
  71. /* Submit request */
  72. mc97_regs->cra = MC97_CRA_ADDR(addr);
  73. /* Wait until not busy */
  74. while ((v = mc97_regs->cra) & MC97_CRA_BUSY);
  75. /* Check for read errors */
  76. if (v & MC97_CRA_READ_ERR)
  77. return 0xffff; /* Not much we can do */
  78. /* Return result */
  79. return MC97_CRA_GET_VAL(v);
  80. }
  81. void
  82. mc97_init(void)
  83. {
  84. /* Initialize controller and reset codec */
  85. mc97_regs->csr = MC97_CSR_RUN;
  86. mc97_regs->csr = MC97_CSR_RUN | MC97_CSR_RESET_N | MC97_CSR_GPIO_ENA;
  87. /* Init the codec */
  88. mc97_codec_reg_write(0x40, 0x1f40); /* Line 1 rate 8 kHz */
  89. mc97_codec_reg_write(0x3e, 0xf000); /* Power up */
  90. mc97_codec_reg_write(0x46, 0x0000); /* Mute Off, no gain/attenuation */
  91. mc97_codec_reg_write(0x4c, 0x002a); /* GPIO Direction */
  92. mc97_codec_reg_write(0x4e, 0x002a); /* GPIO polarity/type */
  93. /* Init cache */
  94. g_mc97.rc_46 = 0x0000;
  95. g_mc97.rc_5c = 0x0000;
  96. g_mc97.rc_62 = 0x0000;
  97. /* Country default */
  98. mc97_select_country(0);
  99. }
  100. void
  101. mc97_debug(void)
  102. {
  103. printf("CSR : %08x\n", mc97_regs->csr);
  104. printf("LLS : %08x\n", mc97_regs->lls);
  105. printf("CRA : %08x\n", mc97_regs->cra);
  106. printf("GI : %08x\n", mc97_regs->gpio_in);
  107. printf("GO : %08x\n", mc97_regs->gpio_out);
  108. printf("Fdat : %08x\n", mc97_regs->fifo_data);
  109. printf("Fcsr : %08x\n", mc97_regs->fifo_csr);
  110. }
  111. bool
  112. mc97_select_country(int cc)
  113. {
  114. for (int i=0; country_data[i].cc >= 0; i++) {
  115. /* Match ? */
  116. if (country_data[i].cc != cc)
  117. continue;
  118. #if 0
  119. printf("Configured for %s\n", country_data[i].name);
  120. #endif
  121. /* Configure */
  122. g_mc97.rc_5c = (g_mc97.rc_5c & 0xff02) | country_data[i].regs[0];
  123. g_mc97.rc_62 = (g_mc97.rc_62 & 0xff87) | country_data[i].regs[1];
  124. mc97_codec_reg_write(0x5c, g_mc97.rc_5c);
  125. mc97_codec_reg_write(0x62, g_mc97.rc_62);
  126. /* Done */
  127. return true;
  128. }
  129. return false;
  130. }
  131. void
  132. mc97_set_aux_relay(bool disconnect)
  133. {
  134. mc97_regs->gpio_out = (mc97_regs->gpio_out & ~(1 << 8)) | (disconnect << 8);
  135. }
  136. void
  137. mc97_set_hook(enum mc97_hook_state s)
  138. {
  139. uint32_t gpio_out = mc97_regs->gpio_out & ~((1 << 4) | (1 << 6));
  140. switch (s) {
  141. case ON_HOOK: break;
  142. case CALLER_ID: gpio_out |= (1 << 6); break;
  143. case OFF_HOOK: gpio_out |= (1 << 4); break;
  144. }
  145. mc97_regs->gpio_out = gpio_out;
  146. }
  147. void
  148. mc97_test_ring(void)
  149. {
  150. g_mc97.test_ring = true;
  151. }
  152. bool
  153. mc97_get_ring_detect(void)
  154. {
  155. if (g_mc97.test_ring) {
  156. g_mc97.test_ring = false;
  157. return true;
  158. }
  159. return (
  160. (mc97_regs->gpio_in & (1 << 5)) &&
  161. (mc97_regs->csr & MC97_CSR_RFI)
  162. ) ? true : false;
  163. }
  164. void
  165. mc97_set_loopback(enum mc97_loopback_mode m)
  166. {
  167. mc97_codec_reg_write(0x56, m);
  168. }
  169. uint8_t
  170. mc97_get_rx_gain(void)
  171. {
  172. return (g_mc97.rc_46 & 0xf) * 3;
  173. }
  174. void
  175. mc97_set_rx_gain(uint8_t gain)
  176. {
  177. gain = (gain > 45) ? 0xf : (gain / 3);
  178. g_mc97.rc_46 = (g_mc97.rc_46 & 0xff80) | (gain << 8);
  179. mc97_codec_reg_write(0x46, g_mc97.rc_46);
  180. }
  181. bool
  182. mc97_get_rx_mute(void)
  183. {
  184. return (g_mc97.rc_46 & 0x0080) ? true : false;
  185. }
  186. void
  187. mc97_set_rx_mute(bool mute)
  188. {
  189. g_mc97.rc_46 = (g_mc97.rc_46 & 0xff7f) | (mute ? 0x0080 : 0x0000);
  190. mc97_codec_reg_write(0x46, g_mc97.rc_46);
  191. }
  192. uint8_t
  193. mc97_get_tx_attenuation(void)
  194. {
  195. return ((g_mc97.rc_46 >> 8) & 0xf) * 3;
  196. }
  197. void
  198. mc97_set_tx_attenuation(uint8_t attenuation)
  199. {
  200. attenuation = (attenuation > 45) ? 0xf : (attenuation / 3);
  201. g_mc97.rc_46 = (g_mc97.rc_46 & 0x80ff) | (attenuation << 8);
  202. mc97_codec_reg_write(0x46, g_mc97.rc_46);
  203. }
  204. bool
  205. mc97_get_tx_mute(void)
  206. {
  207. return (g_mc97.rc_46 & 0x8000) ? true : false;
  208. }
  209. void
  210. mc97_set_tx_mute(bool mute)
  211. {
  212. g_mc97.rc_46 = (g_mc97.rc_46 & 0x7fff) | (mute ? 0x8000 : 0x0000);
  213. mc97_codec_reg_write(0x46, g_mc97.rc_46);
  214. }
  215. void
  216. mc97_flow_rx_reset(void)
  217. {
  218. mc97_regs->fifo_csr = (mc97_regs->fifo_csr & ~MC97_FIFO_CSR_PCM_IN_ENABLE) | MC97_FIFO_CSR_PCM_IN_FLUSH;
  219. while (mc97_regs->fifo_csr & MC97_FIFO_CSR_PCM_IN_FLUSH);
  220. }
  221. void
  222. mc97_flow_rx_start(void)
  223. {
  224. mc97_regs->fifo_csr |= MC97_FIFO_CSR_PCM_IN_ENABLE;
  225. }
  226. void
  227. mc97_flow_rx_stop(void)
  228. {
  229. mc97_regs->fifo_csr &= ~MC97_FIFO_CSR_PCM_IN_ENABLE;
  230. }
  231. int
  232. mc97_flow_rx_pull(int16_t *data, int n)
  233. {
  234. for (int i=0; i<n; i++) {
  235. uint32_t v = mc97_regs->fifo_data;
  236. if (v & MC97_FIFO_DATA_EMPTY)
  237. return i;
  238. data[i] = v & 0xffff;
  239. }
  240. return n;
  241. }
  242. int
  243. mc97_flow_rx_level(void)
  244. {
  245. return MC97_FIFO_CSR_PCM_IN_LEVEL(mc97_regs->fifo_csr);
  246. }
  247. bool
  248. mc97_flow_rx_active(void)
  249. {
  250. return mc97_regs->fifo_csr & MC97_FIFO_CSR_PCM_IN_ENABLE;
  251. }
  252. void
  253. mc97_flow_tx_reset(void)
  254. {
  255. mc97_regs->fifo_csr = (mc97_regs->fifo_csr & ~MC97_FIFO_CSR_PCM_OUT_ENABLE) | MC97_FIFO_CSR_PCM_OUT_FLUSH;
  256. while (mc97_regs->fifo_csr & MC97_FIFO_CSR_PCM_OUT_FLUSH);
  257. }
  258. void
  259. mc97_flow_tx_start(void)
  260. {
  261. mc97_regs->fifo_csr |= MC97_FIFO_CSR_PCM_OUT_ENABLE;
  262. }
  263. void
  264. mc97_flow_tx_stop(void)
  265. {
  266. mc97_regs->fifo_csr &= ~MC97_FIFO_CSR_PCM_OUT_ENABLE;
  267. }
  268. int
  269. mc97_flow_tx_push(int16_t *data, int n)
  270. {
  271. int max = MC97_FIFO_SIZE - MC97_FIFO_CSR_PCM_OUT_LEVEL(mc97_regs->fifo_csr);
  272. if (n > max)
  273. n = max;
  274. for (int i=0; i<n; i++)
  275. mc97_regs->fifo_data = data[i];
  276. return n;
  277. }
  278. int
  279. mc97_flow_tx_level(void)
  280. {
  281. return MC97_FIFO_CSR_PCM_OUT_LEVEL(mc97_regs->fifo_csr);
  282. }
  283. bool
  284. mc97_flow_tx_active(void)
  285. {
  286. return mc97_regs->fifo_csr & MC97_FIFO_CSR_PCM_OUT_ENABLE;
  287. }