aio-pxs2.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. .suspend = uniphier_aio_dai_suspend,
  157. .resume = uniphier_aio_dai_resume,
  158. .playback = {
  159. .stream_name = AUD_NAME_HPCMOUT1,
  160. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  161. .rates = SNDRV_PCM_RATE_48000,
  162. .channels_min = 2,
  163. .channels_max = 2,
  164. },
  165. .ops = &uniphier_aio_i2s_ops,
  166. },
  167. {
  168. .name = AUD_GNAME_LINE,
  169. .probe = uniphier_aio_pxs2_probe,
  170. .remove = uniphier_aio_dai_remove,
  171. .suspend = uniphier_aio_dai_suspend,
  172. .resume = uniphier_aio_dai_resume,
  173. .playback = {
  174. .stream_name = AUD_NAME_PCMOUT1,
  175. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  176. .rates = SNDRV_PCM_RATE_48000,
  177. .channels_min = 2,
  178. .channels_max = 2,
  179. },
  180. .capture = {
  181. .stream_name = AUD_NAME_PCMIN1,
  182. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  183. .rates = SNDRV_PCM_RATE_48000,
  184. .channels_min = 2,
  185. .channels_max = 2,
  186. },
  187. .ops = &uniphier_aio_i2s_ops,
  188. },
  189. {
  190. .name = AUD_GNAME_AUX,
  191. .probe = uniphier_aio_pxs2_probe,
  192. .remove = uniphier_aio_dai_remove,
  193. .suspend = uniphier_aio_dai_suspend,
  194. .resume = uniphier_aio_dai_resume,
  195. .playback = {
  196. .stream_name = AUD_NAME_PCMOUT2,
  197. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  198. .rates = SNDRV_PCM_RATE_48000,
  199. .channels_min = 2,
  200. .channels_max = 2,
  201. },
  202. .capture = {
  203. .stream_name = AUD_NAME_PCMIN2,
  204. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  205. .rates = SNDRV_PCM_RATE_48000,
  206. .channels_min = 2,
  207. .channels_max = 2,
  208. },
  209. .ops = &uniphier_aio_i2s_ops,
  210. },
  211. {
  212. .name = AUD_NAME_HIECOUT1,
  213. .probe = uniphier_aio_pxs2_probe,
  214. .remove = uniphier_aio_dai_remove,
  215. .suspend = uniphier_aio_dai_suspend,
  216. .resume = uniphier_aio_dai_resume,
  217. .playback = {
  218. .stream_name = AUD_NAME_HIECOUT1,
  219. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  220. .rates = SNDRV_PCM_RATE_48000,
  221. .channels_min = 2,
  222. .channels_max = 2,
  223. },
  224. .ops = &uniphier_aio_spdif_ops,
  225. },
  226. {
  227. .name = AUD_NAME_IECOUT1,
  228. .probe = uniphier_aio_pxs2_probe,
  229. .remove = uniphier_aio_dai_remove,
  230. .suspend = uniphier_aio_dai_suspend,
  231. .resume = uniphier_aio_dai_resume,
  232. .playback = {
  233. .stream_name = AUD_NAME_IECOUT1,
  234. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  235. .rates = SNDRV_PCM_RATE_48000,
  236. .channels_min = 2,
  237. .channels_max = 2,
  238. },
  239. .ops = &uniphier_aio_spdif_ops,
  240. },
  241. {
  242. .name = AUD_NAME_HIECCOMPOUT1,
  243. .probe = uniphier_aio_pxs2_probe,
  244. .remove = uniphier_aio_dai_remove,
  245. .suspend = uniphier_aio_dai_suspend,
  246. .resume = uniphier_aio_dai_resume,
  247. .compress_new = snd_soc_new_compress,
  248. .playback = {
  249. .stream_name = AUD_NAME_HIECCOMPOUT1,
  250. .channels_min = 1,
  251. .channels_max = 1,
  252. },
  253. .ops = &uniphier_aio_spdif_ops,
  254. },
  255. {
  256. .name = AUD_NAME_IECCOMPOUT1,
  257. .probe = uniphier_aio_pxs2_probe,
  258. .remove = uniphier_aio_dai_remove,
  259. .suspend = uniphier_aio_dai_suspend,
  260. .resume = uniphier_aio_dai_resume,
  261. .compress_new = snd_soc_new_compress,
  262. .playback = {
  263. .stream_name = AUD_NAME_IECCOMPOUT1,
  264. .channels_min = 1,
  265. .channels_max = 1,
  266. },
  267. .ops = &uniphier_aio_spdif_ops,
  268. },
  269. };
  270. static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = {
  271. .specs = uniphier_aio_pxs2,
  272. .num_specs = ARRAY_SIZE(uniphier_aio_pxs2),
  273. .dais = uniphier_aio_dai_pxs2,
  274. .num_dais = ARRAY_SIZE(uniphier_aio_dai_pxs2),
  275. .plls = uniphier_aio_pll_pxs2,
  276. .num_plls = ARRAY_SIZE(uniphier_aio_pll_pxs2),
  277. .addr_ext = 0,
  278. };
  279. static const struct of_device_id uniphier_aio_of_match[] = {
  280. {
  281. .compatible = "socionext,uniphier-pxs2-aio",
  282. .data = &uniphier_aio_pxs2_spec,
  283. },
  284. {},
  285. };
  286. MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
  287. static struct platform_driver uniphier_aio_driver = {
  288. .driver = {
  289. .name = "snd-uniphier-aio-pxs2",
  290. .of_match_table = of_match_ptr(uniphier_aio_of_match),
  291. },
  292. .probe = uniphier_aio_probe,
  293. .remove = uniphier_aio_remove,
  294. };
  295. module_platform_driver(uniphier_aio_driver);
  296. MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
  297. MODULE_DESCRIPTION("UniPhier PXs2 AIO driver.");
  298. MODULE_LICENSE("GPL v2");