mc97.c 6.8 KB

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