motu-protocol-v2.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * motu-protocol-v2.c - a part of driver for MOTU FireWire series
  3. *
  4. * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "motu.h"
  9. #define V2_CLOCK_STATUS_OFFSET 0x0b14
  10. #define V2_CLOCK_RATE_MASK 0x00000038
  11. #define V2_CLOCK_RATE_SHIFT 3
  12. #define V2_CLOCK_SRC_MASK 0x00000007
  13. #define V2_CLOCK_SRC_SHIFT 0
  14. #define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000
  15. #define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000
  16. #define V2_IN_OUT_CONF_OFFSET 0x0c04
  17. #define V2_OPT_OUT_IFACE_MASK 0x00000c00
  18. #define V2_OPT_OUT_IFACE_SHIFT 10
  19. #define V2_OPT_IN_IFACE_MASK 0x00000300
  20. #define V2_OPT_IN_IFACE_SHIFT 8
  21. #define V2_OPT_IFACE_MODE_NONE 0
  22. #define V2_OPT_IFACE_MODE_ADAT 1
  23. #define V2_OPT_IFACE_MODE_SPDIF 2
  24. static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
  25. {
  26. __be32 reg;
  27. unsigned int index;
  28. int err;
  29. err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  30. sizeof(reg));
  31. if (err < 0)
  32. return err;
  33. index = (be32_to_cpu(reg) & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
  34. if (index >= ARRAY_SIZE(snd_motu_clock_rates))
  35. return -EIO;
  36. *rate = snd_motu_clock_rates[index];
  37. return 0;
  38. }
  39. static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate)
  40. {
  41. __be32 reg;
  42. u32 data;
  43. int i;
  44. int err;
  45. for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
  46. if (snd_motu_clock_rates[i] == rate)
  47. break;
  48. }
  49. if (i == ARRAY_SIZE(snd_motu_clock_rates))
  50. return -EINVAL;
  51. err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  52. sizeof(reg));
  53. if (err < 0)
  54. return err;
  55. data = be32_to_cpu(reg);
  56. data &= ~V2_CLOCK_RATE_MASK;
  57. data |= i << V2_CLOCK_RATE_SHIFT;
  58. if (motu->spec == &snd_motu_spec_traveler) {
  59. data &= ~V2_CLOCK_TRAVELER_FETCH_ENABLE;
  60. data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
  61. }
  62. reg = cpu_to_be32(data);
  63. return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  64. sizeof(reg));
  65. }
  66. static int v2_get_clock_source(struct snd_motu *motu,
  67. enum snd_motu_clock_source *src)
  68. {
  69. __be32 reg;
  70. unsigned int index;
  71. int err;
  72. err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
  73. sizeof(reg));
  74. if (err < 0)
  75. return err;
  76. index = be32_to_cpu(reg) & V2_CLOCK_SRC_MASK;
  77. if (index > 5)
  78. return -EIO;
  79. /* To check the configuration of optical interface. */
  80. err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
  81. sizeof(reg));
  82. if (err < 0)
  83. return err;
  84. switch (index) {
  85. case 0:
  86. *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
  87. break;
  88. case 1:
  89. if (be32_to_cpu(reg) & 0x00000200)
  90. *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
  91. else
  92. *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
  93. break;
  94. case 2:
  95. *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
  96. break;
  97. case 4:
  98. *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
  99. break;
  100. case 5:
  101. *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
  102. break;
  103. default:
  104. return -EIO;
  105. }
  106. return 0;
  107. }
  108. static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
  109. {
  110. __be32 reg;
  111. u32 data;
  112. int err = 0;
  113. if (motu->spec == &snd_motu_spec_traveler) {
  114. err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
  115. &reg, sizeof(reg));
  116. if (err < 0)
  117. return err;
  118. data = be32_to_cpu(reg);
  119. data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
  120. V2_CLOCK_TRAVELER_FETCH_ENABLE);
  121. if (enable)
  122. data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
  123. else
  124. data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
  125. reg = cpu_to_be32(data);
  126. err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
  127. &reg, sizeof(reg));
  128. }
  129. return err;
  130. }
  131. static void calculate_fixed_part(struct snd_motu_packet_format *formats,
  132. enum amdtp_stream_direction dir,
  133. enum snd_motu_spec_flags flags,
  134. unsigned char analog_ports)
  135. {
  136. unsigned char pcm_chunks[3] = {0, 0, 0};
  137. formats->msg_chunks = 2;
  138. pcm_chunks[0] = analog_ports;
  139. pcm_chunks[1] = analog_ports;
  140. if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
  141. pcm_chunks[2] = analog_ports;
  142. if (dir == AMDTP_IN_STREAM) {
  143. if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) {
  144. pcm_chunks[0] += 2;
  145. pcm_chunks[1] += 2;
  146. }
  147. if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) {
  148. pcm_chunks[0] += 2;
  149. pcm_chunks[1] += 2;
  150. }
  151. } else {
  152. if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) {
  153. pcm_chunks[0] += 2;
  154. pcm_chunks[1] += 2;
  155. }
  156. // Packets to v2 units include 2 chunks for phone 1/2, except
  157. // for 176.4/192.0 kHz.
  158. pcm_chunks[0] += 2;
  159. pcm_chunks[1] += 2;
  160. }
  161. if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) {
  162. pcm_chunks[0] += 2;
  163. pcm_chunks[1] += 2;
  164. }
  165. /*
  166. * All of v2 models have a pair of coaxial interfaces for digital in/out
  167. * port. At 44.1/48.0/88.2/96.0 kHz, packets includes PCM from these
  168. * ports.
  169. */
  170. pcm_chunks[0] += 2;
  171. pcm_chunks[1] += 2;
  172. formats->fixed_part_pcm_chunks[0] = pcm_chunks[0];
  173. formats->fixed_part_pcm_chunks[1] = pcm_chunks[1];
  174. formats->fixed_part_pcm_chunks[2] = pcm_chunks[2];
  175. }
  176. static void calculate_differed_part(struct snd_motu_packet_format *formats,
  177. enum snd_motu_spec_flags flags,
  178. u32 data, u32 mask, u32 shift)
  179. {
  180. unsigned char pcm_chunks[2] = {0, 0};
  181. /*
  182. * When optical interfaces are configured for S/PDIF (TOSLINK),
  183. * the above PCM frames come from them, instead of coaxial
  184. * interfaces.
  185. */
  186. data = (data & mask) >> shift;
  187. if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) &&
  188. data == V2_OPT_IFACE_MODE_ADAT) {
  189. pcm_chunks[0] += 8;
  190. pcm_chunks[1] += 4;
  191. }
  192. /* At mode x4, no data chunks are supported in this part. */
  193. formats->differed_part_pcm_chunks[0] = pcm_chunks[0];
  194. formats->differed_part_pcm_chunks[1] = pcm_chunks[1];
  195. }
  196. static int v2_cache_packet_formats(struct snd_motu *motu)
  197. {
  198. __be32 reg;
  199. u32 data;
  200. int err;
  201. err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
  202. sizeof(reg));
  203. if (err < 0)
  204. return err;
  205. data = be32_to_cpu(reg);
  206. calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM,
  207. motu->spec->flags, motu->spec->analog_in_ports);
  208. calculate_differed_part(&motu->tx_packet_formats, motu->spec->flags,
  209. data, V2_OPT_IN_IFACE_MASK, V2_OPT_IN_IFACE_SHIFT);
  210. calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM,
  211. motu->spec->flags, motu->spec->analog_out_ports);
  212. calculate_differed_part(&motu->rx_packet_formats, motu->spec->flags,
  213. data, V2_OPT_OUT_IFACE_MASK, V2_OPT_OUT_IFACE_SHIFT);
  214. motu->tx_packet_formats.pcm_byte_offset = 10;
  215. motu->rx_packet_formats.pcm_byte_offset = 10;
  216. return 0;
  217. }
  218. const struct snd_motu_protocol snd_motu_protocol_v2 = {
  219. .get_clock_rate = v2_get_clock_rate,
  220. .set_clock_rate = v2_set_clock_rate,
  221. .get_clock_source = v2_get_clock_source,
  222. .switch_fetching_mode = v2_switch_fetching_mode,
  223. .cache_packet_formats = v2_cache_packet_formats,
  224. };