mc97.c 6.8 KB

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