xref: /openbmc/linux/sound/soc/uniphier/aio-ld11.c (revision b830f94f)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Socionext UniPhier AIO ALSA driver for LD11/LD20.
4 //
5 // Copyright (c) 2016-2018 Socionext Inc.
6 
7 #include <linux/module.h>
8 
9 #include "aio.h"
10 
11 static const struct uniphier_aio_spec uniphier_aio_ld11[] = {
12 	/* for HDMI PCM In, Pin:AI1Dx */
13 	{
14 		.name = AUD_NAME_PCMIN1,
15 		.gname = AUD_GNAME_HDMI,
16 		.swm = {
17 			.type  = PORT_TYPE_I2S,
18 			.dir   = PORT_DIR_INPUT,
19 			.rb    = { 21, 14, },
20 			.ch    = { 21, 14, },
21 			.iif   = { 5, 3, },
22 			.iport = { 0, AUD_HW_PCMIN1, },
23 		},
24 	},
25 
26 	/* for SIF In, Pin:AI2Dx */
27 	{
28 		.name = AUD_NAME_PCMIN2,
29 		.swm = {
30 			.type  = PORT_TYPE_I2S,
31 			.dir   = PORT_DIR_INPUT,
32 			.rb    = { 22, 15, },
33 			.ch    = { 22, 15, },
34 			.iif   = { 6, 4, },
35 			.iport = { 1, AUD_HW_PCMIN2, },
36 		},
37 	},
38 
39 	/* for Line In, Pin:AI3Dx */
40 	{
41 		.name = AUD_NAME_PCMIN3,
42 		.gname = AUD_GNAME_LINE,
43 		.swm = {
44 			.type  = PORT_TYPE_EVE,
45 			.dir   = PORT_DIR_INPUT,
46 			.rb    = { 23, 16, },
47 			.ch    = { 23, 16, },
48 			.iif   = { 7, 5, },
49 			.iport = { 2, AUD_HW_PCMIN3, },
50 		},
51 	},
52 
53 	/* for S/PDIF In, Pin:AI1IEC */
54 	{
55 		.name = AUD_NAME_IECIN1,
56 		.gname = AUD_GNAME_IEC,
57 		.swm = {
58 			.type  = PORT_TYPE_SPDIF,
59 			.dir   = PORT_DIR_INPUT,
60 			.rb    = { 26, 17, },
61 			.ch    = { 26, 17, },
62 			.iif   = { 10, 6, },
63 			.iport = { 3, AUD_HW_IECIN1, },
64 		},
65 	},
66 
67 	/* for Speaker, Pin:AO1Dx */
68 	{
69 		.name = AUD_NAME_HPCMOUT1,
70 		.swm = {
71 			.type  = PORT_TYPE_I2S,
72 			.dir   = PORT_DIR_OUTPUT,
73 			.rb    = { 0, 0, },
74 			.ch    = { 0, 0, },
75 			.oif   = { 0, 0, },
76 			.oport = { 0, AUD_HW_HPCMOUT1, },
77 		},
78 	},
79 
80 	/* for HDMI PCM, Pin:AO2Dx */
81 	{
82 		.name = AUD_NAME_PCMOUT1,
83 		.gname = AUD_GNAME_HDMI,
84 		.swm = {
85 			.type  = PORT_TYPE_I2S,
86 			.dir   = PORT_DIR_OUTPUT,
87 			.rb    = { 0, 0, },
88 			.ch    = { 0, 0, },
89 			.oif   = { 0, 0, },
90 			.oport = { 3, AUD_HW_PCMOUT1, },
91 		},
92 	},
93 
94 	/* for Line Out, Pin:LO2_x */
95 	{
96 		.name = AUD_NAME_PCMOUT2,
97 		.gname = AUD_GNAME_LINE,
98 		.swm = {
99 			.type  = PORT_TYPE_EVE,
100 			.dir   = PORT_DIR_OUTPUT,
101 			.rb    = { 2, 2, },
102 			.ch    = { 2, 2, },
103 			.oif   = { 2, 2, },
104 			.oport = { 1, AUD_HW_PCMOUT2, },
105 		},
106 	},
107 
108 	/* for Headphone, Pin:HP1_x */
109 	{
110 		.name = AUD_NAME_PCMOUT3,
111 		.swm = {
112 			.type  = PORT_TYPE_EVE,
113 			.dir   = PORT_DIR_OUTPUT,
114 			.rb    = { 3, 3, },
115 			.ch    = { 3, 3, },
116 			.oif   = { 3, 3, },
117 			.oport = { 2, AUD_HW_PCMOUT3, },
118 		},
119 	},
120 
121 	/* for HW Sampling Rate Converter */
122 	{
123 		.name = AUD_NAME_EPCMOUT2,
124 		.swm = {
125 			.type  = PORT_TYPE_CONV,
126 			.dir   = PORT_DIR_OUTPUT,
127 			.rb    = { 7, 5, },
128 			.ch    = { 7, 5, },
129 			.oif   = { 7, 5, },
130 			.oport = { 6, AUD_HW_EPCMOUT2, },
131 			.och   = { 17, 12, },
132 			.iif   = { 1, 1, },
133 		},
134 	},
135 
136 	/* for HW Sampling Rate Converter 2 */
137 	{
138 		.name = AUD_NAME_EPCMOUT3,
139 		.swm = {
140 			.type  = PORT_TYPE_CONV,
141 			.dir   = PORT_DIR_OUTPUT,
142 			.rb    = { 8, 6, },
143 			.ch    = { 8, 6, },
144 			.oif   = { 8, 6, },
145 			.oport = { 7, AUD_HW_EPCMOUT3, },
146 			.och   = { 18, 13, },
147 			.iif   = { 2, 2, },
148 		},
149 	},
150 
151 	/* for S/PDIF Out, Pin:AO1IEC */
152 	{
153 		.name = AUD_NAME_HIECOUT1,
154 		.gname = AUD_GNAME_IEC,
155 		.swm = {
156 			.type  = PORT_TYPE_SPDIF,
157 			.dir   = PORT_DIR_OUTPUT,
158 			.rb    = { 1, 1, },
159 			.ch    = { 1, 1, },
160 			.oif   = { 1, 1, },
161 			.oport = { 12, AUD_HW_HIECOUT1, },
162 		},
163 	},
164 
165 	/* for S/PDIF Out, Pin:AO1IEC, Compress */
166 	{
167 		.name = AUD_NAME_HIECCOMPOUT1,
168 		.gname = AUD_GNAME_IEC,
169 		.swm = {
170 			.type  = PORT_TYPE_SPDIF,
171 			.dir   = PORT_DIR_OUTPUT,
172 			.rb    = { 1, 1, },
173 			.ch    = { 1, 1, },
174 			.oif   = { 1, 1, },
175 			.oport = { 12, AUD_HW_HIECOUT1, },
176 		},
177 	},
178 };
179 
180 static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = {
181 	[AUD_PLL_A1]   = { .enable = true, },
182 	[AUD_PLL_F1]   = { .enable = true, },
183 	[AUD_PLL_A2]   = { .enable = true, },
184 	[AUD_PLL_F2]   = { .enable = true, },
185 	[AUD_PLL_APLL] = { .enable = true, },
186 	[AUD_PLL_RX0]  = { .enable = true, },
187 	[AUD_PLL_USB0] = { .enable = true, },
188 	[AUD_PLL_HSC0] = { .enable = true, },
189 };
190 
191 static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
192 {
193 	int ret;
194 
195 	ret = uniphier_aio_dai_probe(dai);
196 	if (ret < 0)
197 		return ret;
198 
199 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
200 	if (ret < 0)
201 		return ret;
202 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
203 	if (ret < 0)
204 		return ret;
205 
206 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
207 	if (ret < 0)
208 		return ret;
209 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
210 	if (ret < 0)
211 		return ret;
212 
213 	return 0;
214 }
215 
216 static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
217 	{
218 		.name    = AUD_GNAME_HDMI,
219 		.probe   = uniphier_aio_ld11_probe,
220 		.remove  = uniphier_aio_dai_remove,
221 		.suspend = uniphier_aio_dai_suspend,
222 		.resume  = uniphier_aio_dai_resume,
223 		.playback = {
224 			.stream_name = AUD_NAME_PCMOUT1,
225 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
226 			.rates       = SNDRV_PCM_RATE_48000,
227 			.channels_min = 2,
228 			.channels_max = 2,
229 		},
230 		.capture = {
231 			.stream_name = AUD_NAME_PCMIN1,
232 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
233 			.rates       = SNDRV_PCM_RATE_48000 |
234 				SNDRV_PCM_RATE_44100 |
235 				SNDRV_PCM_RATE_32000,
236 			.channels_min = 2,
237 			.channels_max = 2,
238 		},
239 		.ops = &uniphier_aio_i2s_ops,
240 	},
241 	{
242 		.name    = AUD_NAME_PCMIN2,
243 		.probe   = uniphier_aio_ld11_probe,
244 		.remove  = uniphier_aio_dai_remove,
245 		.suspend = uniphier_aio_dai_suspend,
246 		.resume  = uniphier_aio_dai_resume,
247 		.capture = {
248 			.stream_name = AUD_NAME_PCMIN2,
249 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
250 			.rates       = SNDRV_PCM_RATE_48000,
251 			.channels_min = 2,
252 			.channels_max = 2,
253 		},
254 		.ops = &uniphier_aio_i2s_ops,
255 	},
256 	{
257 		.name    = AUD_GNAME_LINE,
258 		.probe   = uniphier_aio_ld11_probe,
259 		.remove  = uniphier_aio_dai_remove,
260 		.suspend = uniphier_aio_dai_suspend,
261 		.resume  = uniphier_aio_dai_resume,
262 		.playback = {
263 			.stream_name = AUD_NAME_PCMOUT2,
264 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
265 			.rates       = SNDRV_PCM_RATE_48000,
266 			.channels_min = 2,
267 			.channels_max = 2,
268 		},
269 		.capture = {
270 			.stream_name = AUD_NAME_PCMIN3,
271 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
272 			.rates       = SNDRV_PCM_RATE_48000,
273 			.channels_min = 2,
274 			.channels_max = 2,
275 		},
276 		.ops = &uniphier_aio_i2s_ops,
277 	},
278 	{
279 		.name    = AUD_NAME_HPCMOUT1,
280 		.probe   = uniphier_aio_ld11_probe,
281 		.remove  = uniphier_aio_dai_remove,
282 		.suspend = uniphier_aio_dai_suspend,
283 		.resume  = uniphier_aio_dai_resume,
284 		.playback = {
285 			.stream_name = AUD_NAME_HPCMOUT1,
286 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
287 			.rates       = SNDRV_PCM_RATE_48000,
288 			.channels_min = 2,
289 			.channels_max = 8,
290 		},
291 		.ops = &uniphier_aio_i2s_ops,
292 	},
293 	{
294 		.name    = AUD_NAME_PCMOUT3,
295 		.probe   = uniphier_aio_ld11_probe,
296 		.remove  = uniphier_aio_dai_remove,
297 		.suspend = uniphier_aio_dai_suspend,
298 		.resume  = uniphier_aio_dai_resume,
299 		.playback = {
300 			.stream_name = AUD_NAME_PCMOUT3,
301 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
302 			.rates       = SNDRV_PCM_RATE_48000,
303 			.channels_min = 2,
304 			.channels_max = 2,
305 		},
306 		.ops = &uniphier_aio_i2s_ops,
307 	},
308 	{
309 		.name    = AUD_NAME_HIECOUT1,
310 		.probe   = uniphier_aio_ld11_probe,
311 		.remove  = uniphier_aio_dai_remove,
312 		.suspend = uniphier_aio_dai_suspend,
313 		.resume  = uniphier_aio_dai_resume,
314 		.playback = {
315 			.stream_name = AUD_NAME_HIECOUT1,
316 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
317 			.rates       = SNDRV_PCM_RATE_48000,
318 			.channels_min = 2,
319 			.channels_max = 2,
320 		},
321 		.ops = &uniphier_aio_spdif_ops,
322 	},
323 	{
324 		.name    = AUD_NAME_EPCMOUT2,
325 		.probe   = uniphier_aio_ld11_probe,
326 		.remove  = uniphier_aio_dai_remove,
327 		.suspend = uniphier_aio_dai_suspend,
328 		.resume  = uniphier_aio_dai_resume,
329 		.playback = {
330 			.stream_name = AUD_NAME_EPCMOUT2,
331 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
332 			.rates       = SNDRV_PCM_RATE_48000 |
333 				SNDRV_PCM_RATE_44100 |
334 				SNDRV_PCM_RATE_32000,
335 			.channels_min = 2,
336 			.channels_max = 2,
337 		},
338 		.ops = &uniphier_aio_i2s_ops,
339 	},
340 	{
341 		.name    = AUD_NAME_EPCMOUT3,
342 		.probe   = uniphier_aio_ld11_probe,
343 		.remove  = uniphier_aio_dai_remove,
344 		.suspend = uniphier_aio_dai_suspend,
345 		.resume  = uniphier_aio_dai_resume,
346 		.playback = {
347 			.stream_name = AUD_NAME_EPCMOUT3,
348 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
349 			.rates       = SNDRV_PCM_RATE_48000 |
350 				SNDRV_PCM_RATE_44100 |
351 				SNDRV_PCM_RATE_32000,
352 			.channels_min = 2,
353 			.channels_max = 2,
354 		},
355 		.ops = &uniphier_aio_i2s_ops,
356 	},
357 	{
358 		.name    = AUD_NAME_HIECCOMPOUT1,
359 		.probe   = uniphier_aio_ld11_probe,
360 		.remove  = uniphier_aio_dai_remove,
361 		.suspend = uniphier_aio_dai_suspend,
362 		.resume  = uniphier_aio_dai_resume,
363 		.compress_new = snd_soc_new_compress,
364 		.playback = {
365 			.stream_name = AUD_NAME_HIECCOMPOUT1,
366 			.channels_min = 1,
367 			.channels_max = 1,
368 		},
369 		.ops = &uniphier_aio_spdif_ops,
370 	},
371 };
372 
373 static const struct uniphier_aio_chip_spec uniphier_aio_ld11_spec = {
374 	.specs     = uniphier_aio_ld11,
375 	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
376 	.dais      = uniphier_aio_dai_ld11,
377 	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
378 	.plls      = uniphier_aio_pll_ld11,
379 	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
380 	.addr_ext  = 0,
381 };
382 
383 static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
384 	.specs     = uniphier_aio_ld11,
385 	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
386 	.dais      = uniphier_aio_dai_ld11,
387 	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
388 	.plls      = uniphier_aio_pll_ld11,
389 	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
390 	.addr_ext  = 1,
391 };
392 
393 static const struct of_device_id uniphier_aio_of_match[] = {
394 	{
395 		.compatible = "socionext,uniphier-ld11-aio",
396 		.data = &uniphier_aio_ld11_spec,
397 	},
398 	{
399 		.compatible = "socionext,uniphier-ld20-aio",
400 		.data = &uniphier_aio_ld20_spec,
401 	},
402 	{},
403 };
404 MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
405 
406 static struct platform_driver uniphier_aio_driver = {
407 	.driver = {
408 		.name = "snd-uniphier-aio-ld11",
409 		.of_match_table = of_match_ptr(uniphier_aio_of_match),
410 	},
411 	.probe    = uniphier_aio_probe,
412 	.remove   = uniphier_aio_remove,
413 };
414 module_platform_driver(uniphier_aio_driver);
415 
416 MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
417 MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
418 MODULE_LICENSE("GPL v2");
419