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