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