aio-pxs2.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Socionext UniPhier AIO ALSA driver for PXs2.
  4. //
  5. // Copyright (c) 2018 Socionext Inc.
  6. #include <linux/module.h>
  7. #include "aio.h"
  8. static const struct uniphier_aio_spec uniphier_aio_pxs2[] = {
  9. /* for Line PCM In, Pin:AI1Dx */
  10. {
  11. .name = AUD_NAME_PCMIN1,
  12. .gname = AUD_GNAME_LINE,
  13. .swm = {
  14. .type = PORT_TYPE_I2S,
  15. .dir = PORT_DIR_INPUT,
  16. .rb = { 16, 11, },
  17. .ch = { 16, 11, },
  18. .iif = { 0, 0, },
  19. .iport = { 0, AUD_HW_PCMIN1, },
  20. },
  21. },
  22. /* for Speaker/Headphone/Mic PCM In, Pin:AI2Dx */
  23. {
  24. .name = AUD_NAME_PCMIN2,
  25. .gname = AUD_GNAME_AUX,
  26. .swm = {
  27. .type = PORT_TYPE_I2S,
  28. .dir = PORT_DIR_INPUT,
  29. .rb = { 17, 12, },
  30. .ch = { 17, 12, },
  31. .iif = { 1, 1, },
  32. .iport = { 1, AUD_HW_PCMIN2, },
  33. },
  34. },
  35. /* for HDMI PCM Out, Pin:AO1Dx (inner) */
  36. {
  37. .name = AUD_NAME_HPCMOUT1,
  38. .gname = AUD_GNAME_HDMI,
  39. .swm = {
  40. .type = PORT_TYPE_I2S,
  41. .dir = PORT_DIR_OUTPUT,
  42. .rb = { 0, 0, },
  43. .ch = { 0, 0, },
  44. .oif = { 0, 0, },
  45. .oport = { 3, AUD_HW_HPCMOUT1, },
  46. },
  47. },
  48. /* for Line PCM Out, Pin:AO2Dx */
  49. {
  50. .name = AUD_NAME_PCMOUT1,
  51. .gname = AUD_GNAME_LINE,
  52. .swm = {
  53. .type = PORT_TYPE_I2S,
  54. .dir = PORT_DIR_OUTPUT,
  55. .rb = { 1, 1, },
  56. .ch = { 1, 1, },
  57. .oif = { 1, 1, },
  58. .oport = { 0, AUD_HW_PCMOUT1, },
  59. },
  60. },
  61. /* for Speaker/Headphone/Mic PCM Out, Pin:AO3Dx */
  62. {
  63. .name = AUD_NAME_PCMOUT2,
  64. .gname = AUD_GNAME_AUX,
  65. .swm = {
  66. .type = PORT_TYPE_I2S,
  67. .dir = PORT_DIR_OUTPUT,
  68. .rb = { 2, 2, },
  69. .ch = { 2, 2, },
  70. .oif = { 2, 2, },
  71. .oport = { 1, AUD_HW_PCMOUT2, },
  72. },
  73. },
  74. /* for HDMI Out, Pin:AO1IEC */
  75. {
  76. .name = AUD_NAME_HIECOUT1,
  77. .swm = {
  78. .type = PORT_TYPE_SPDIF,
  79. .dir = PORT_DIR_OUTPUT,
  80. .rb = { 6, 4, },
  81. .ch = { 6, 4, },
  82. .oif = { 6, 4, },
  83. .oport = { 12, AUD_HW_HIECOUT1, },
  84. },
  85. },
  86. /* for HDMI Out, Pin:AO1IEC, Compress */
  87. {
  88. .name = AUD_NAME_HIECCOMPOUT1,
  89. .swm = {
  90. .type = PORT_TYPE_SPDIF,
  91. .dir = PORT_DIR_OUTPUT,
  92. .rb = { 6, 4, },
  93. .ch = { 6, 4, },
  94. .oif = { 6, 4, },
  95. .oport = { 12, AUD_HW_HIECOUT1, },
  96. },
  97. },
  98. /* for S/PDIF Out, Pin:AO2IEC */
  99. {
  100. .name = AUD_NAME_IECOUT1,
  101. .swm = {
  102. .type = PORT_TYPE_SPDIF,
  103. .dir = PORT_DIR_OUTPUT,
  104. .rb = { 7, 5, },
  105. .ch = { 7, 5, },
  106. .oif = { 7, 5, },
  107. .oport = { 13, AUD_HW_IECOUT1, },
  108. },
  109. },
  110. /* for S/PDIF Out, Pin:AO2IEC */
  111. {
  112. .name = AUD_NAME_IECCOMPOUT1,
  113. .swm = {
  114. .type = PORT_TYPE_SPDIF,
  115. .dir = PORT_DIR_OUTPUT,
  116. .rb = { 7, 5, },
  117. .ch = { 7, 5, },
  118. .oif = { 7, 5, },
  119. .oport = { 13, AUD_HW_IECOUT1, },
  120. },
  121. },
  122. };
  123. static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = {
  124. [AUD_PLL_A1] = { .enable = true, },
  125. [AUD_PLL_F1] = { .enable = true, },
  126. [AUD_PLL_A2] = { .enable = true, },
  127. [AUD_PLL_F2] = { .enable = true, },
  128. [AUD_PLL_APLL] = { .enable = true, },
  129. [AUD_PLL_HSC0] = { .enable = true, },
  130. };
  131. static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
  132. {
  133. int ret;
  134. ret = uniphier_aio_dai_probe(dai);
  135. if (ret < 0)
  136. return ret;
  137. ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
  138. if (ret < 0)
  139. return ret;
  140. ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
  141. if (ret < 0)
  142. return ret;
  143. ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
  144. if (ret < 0)
  145. return ret;
  146. ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
  147. if (ret < 0)
  148. return ret;
  149. return 0;
  150. }
  151. static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
  152. {
  153. .name = AUD_GNAME_HDMI,
  154. .probe = uniphier_aio_pxs2_probe,
  155. .remove = uniphier_aio_dai_remove,
  156. .playback = {
  157. .stream_name = AUD_NAME_HPCMOUT1,
  158. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  159. .rates = SNDRV_PCM_RATE_48000,
  160. .channels_min = 2,
  161. .channels_max = 2,
  162. },
  163. .ops = &uniphier_aio_i2s_ops,
  164. },
  165. {
  166. .name = AUD_GNAME_LINE,
  167. .probe = uniphier_aio_pxs2_probe,
  168. .remove = uniphier_aio_dai_remove,
  169. .playback = {
  170. .stream_name = AUD_NAME_PCMOUT1,
  171. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  172. .rates = SNDRV_PCM_RATE_48000,
  173. .channels_min = 2,
  174. .channels_max = 2,
  175. },
  176. .capture = {
  177. .stream_name = AUD_NAME_PCMIN1,
  178. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  179. .rates = SNDRV_PCM_RATE_48000,
  180. .channels_min = 2,
  181. .channels_max = 2,
  182. },
  183. .ops = &uniphier_aio_i2s_ops,
  184. },
  185. {
  186. .name = AUD_GNAME_AUX,
  187. .probe = uniphier_aio_pxs2_probe,
  188. .remove = uniphier_aio_dai_remove,
  189. .playback = {
  190. .stream_name = AUD_NAME_PCMOUT2,
  191. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  192. .rates = SNDRV_PCM_RATE_48000,
  193. .channels_min = 2,
  194. .channels_max = 2,
  195. },
  196. .capture = {
  197. .stream_name = AUD_NAME_PCMIN2,
  198. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  199. .rates = SNDRV_PCM_RATE_48000,
  200. .channels_min = 2,
  201. .channels_max = 2,
  202. },
  203. .ops = &uniphier_aio_i2s_ops,
  204. },
  205. {
  206. .name = AUD_NAME_HIECOUT1,
  207. .probe = uniphier_aio_pxs2_probe,
  208. .remove = uniphier_aio_dai_remove,
  209. .playback = {
  210. .stream_name = AUD_NAME_HIECOUT1,
  211. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  212. .rates = SNDRV_PCM_RATE_48000,
  213. .channels_min = 2,
  214. .channels_max = 2,
  215. },
  216. .ops = &uniphier_aio_spdif_ops,
  217. },
  218. {
  219. .name = AUD_NAME_IECOUT1,
  220. .probe = uniphier_aio_pxs2_probe,
  221. .remove = uniphier_aio_dai_remove,
  222. .playback = {
  223. .stream_name = AUD_NAME_IECOUT1,
  224. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  225. .rates = SNDRV_PCM_RATE_48000,
  226. .channels_min = 2,
  227. .channels_max = 2,
  228. },
  229. .ops = &uniphier_aio_spdif_ops,
  230. },
  231. {
  232. .name = AUD_NAME_HIECCOMPOUT1,
  233. .probe = uniphier_aio_pxs2_probe,
  234. .remove = uniphier_aio_dai_remove,
  235. .compress_new = snd_soc_new_compress,
  236. .playback = {
  237. .stream_name = AUD_NAME_HIECCOMPOUT1,
  238. .channels_min = 1,
  239. .channels_max = 1,
  240. },
  241. .ops = &uniphier_aio_spdif_ops,
  242. },
  243. {
  244. .name = AUD_NAME_IECCOMPOUT1,
  245. .probe = uniphier_aio_pxs2_probe,
  246. .remove = uniphier_aio_dai_remove,
  247. .compress_new = snd_soc_new_compress,
  248. .playback = {
  249. .stream_name = AUD_NAME_IECCOMPOUT1,
  250. .channels_min = 1,
  251. .channels_max = 1,
  252. },
  253. .ops = &uniphier_aio_spdif_ops,
  254. },
  255. };
  256. static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = {
  257. .specs = uniphier_aio_pxs2,
  258. .num_specs = ARRAY_SIZE(uniphier_aio_pxs2),
  259. .dais = uniphier_aio_dai_pxs2,
  260. .num_dais = ARRAY_SIZE(uniphier_aio_dai_pxs2),
  261. .plls = uniphier_aio_pll_pxs2,
  262. .num_plls = ARRAY_SIZE(uniphier_aio_pll_pxs2),
  263. .addr_ext = 0,
  264. };
  265. static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
  266. {
  267. .compatible = "socionext,uniphier-pxs2-aio",
  268. .data = &uniphier_aio_pxs2_spec,
  269. },
  270. {},
  271. };
  272. MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
  273. static struct platform_driver uniphier_aio_driver = {
  274. .driver = {
  275. .name = "snd-uniphier-aio-pxs2",
  276. .of_match_table = of_match_ptr(uniphier_aio_of_match),
  277. },
  278. .probe = uniphier_aio_probe,
  279. .remove = uniphier_aio_remove,
  280. };
  281. module_platform_driver(uniphier_aio_driver);
  282. MODULE_AUTHOR("Katsuhiro Suzuki <[email protected]>");
  283. MODULE_DESCRIPTION("UniPhier PXs2 AIO driver.");
  284. MODULE_LICENSE("GPL v2");