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 
uniphier_aio_ld11_probe(struct snd_soc_dai * dai)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 		.playback = {
222 			.stream_name = AUD_NAME_PCMOUT1,
223 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
224 			.rates       = SNDRV_PCM_RATE_48000,
225 			.channels_min = 2,
226 			.channels_max = 2,
227 		},
228 		.capture = {
229 			.stream_name = AUD_NAME_PCMIN1,
230 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
231 			.rates       = SNDRV_PCM_RATE_48000 |
232 				SNDRV_PCM_RATE_44100 |
233 				SNDRV_PCM_RATE_32000,
234 			.channels_min = 2,
235 			.channels_max = 2,
236 		},
237 		.ops = &uniphier_aio_i2s_ops,
238 	},
239 	{
240 		.name    = AUD_NAME_PCMIN2,
241 		.probe   = uniphier_aio_ld11_probe,
242 		.remove  = uniphier_aio_dai_remove,
243 		.capture = {
244 			.stream_name = AUD_NAME_PCMIN2,
245 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
246 			.rates       = SNDRV_PCM_RATE_48000,
247 			.channels_min = 2,
248 			.channels_max = 2,
249 		},
250 		.ops = &uniphier_aio_i2s_ops,
251 	},
252 	{
253 		.name    = AUD_GNAME_LINE,
254 		.probe   = uniphier_aio_ld11_probe,
255 		.remove  = uniphier_aio_dai_remove,
256 		.playback = {
257 			.stream_name = AUD_NAME_PCMOUT2,
258 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
259 			.rates       = SNDRV_PCM_RATE_48000,
260 			.channels_min = 2,
261 			.channels_max = 2,
262 		},
263 		.capture = {
264 			.stream_name = AUD_NAME_PCMIN3,
265 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
266 			.rates       = SNDRV_PCM_RATE_48000,
267 			.channels_min = 2,
268 			.channels_max = 2,
269 		},
270 		.ops = &uniphier_aio_i2s_ops,
271 	},
272 	{
273 		.name    = AUD_NAME_HPCMOUT1,
274 		.probe   = uniphier_aio_ld11_probe,
275 		.remove  = uniphier_aio_dai_remove,
276 		.playback = {
277 			.stream_name = AUD_NAME_HPCMOUT1,
278 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
279 			.rates       = SNDRV_PCM_RATE_48000,
280 			.channels_min = 2,
281 			.channels_max = 8,
282 		},
283 		.ops = &uniphier_aio_i2s_ops,
284 	},
285 	{
286 		.name    = AUD_NAME_PCMOUT3,
287 		.probe   = uniphier_aio_ld11_probe,
288 		.remove  = uniphier_aio_dai_remove,
289 		.playback = {
290 			.stream_name = AUD_NAME_PCMOUT3,
291 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
292 			.rates       = SNDRV_PCM_RATE_48000,
293 			.channels_min = 2,
294 			.channels_max = 2,
295 		},
296 		.ops = &uniphier_aio_i2s_ops,
297 	},
298 	{
299 		.name    = AUD_NAME_HIECOUT1,
300 		.probe   = uniphier_aio_ld11_probe,
301 		.remove  = uniphier_aio_dai_remove,
302 		.playback = {
303 			.stream_name = AUD_NAME_HIECOUT1,
304 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
305 			.rates       = SNDRV_PCM_RATE_48000,
306 			.channels_min = 2,
307 			.channels_max = 2,
308 		},
309 		.ops = &uniphier_aio_spdif_ops,
310 	},
311 	{
312 		.name    = AUD_NAME_EPCMOUT2,
313 		.probe   = uniphier_aio_ld11_probe,
314 		.remove  = uniphier_aio_dai_remove,
315 		.playback = {
316 			.stream_name = AUD_NAME_EPCMOUT2,
317 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
318 			.rates       = SNDRV_PCM_RATE_48000 |
319 				SNDRV_PCM_RATE_44100 |
320 				SNDRV_PCM_RATE_32000,
321 			.channels_min = 2,
322 			.channels_max = 2,
323 		},
324 		.ops = &uniphier_aio_i2s_ops,
325 	},
326 	{
327 		.name    = AUD_NAME_EPCMOUT3,
328 		.probe   = uniphier_aio_ld11_probe,
329 		.remove  = uniphier_aio_dai_remove,
330 		.playback = {
331 			.stream_name = AUD_NAME_EPCMOUT3,
332 			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
333 			.rates       = SNDRV_PCM_RATE_48000 |
334 				SNDRV_PCM_RATE_44100 |
335 				SNDRV_PCM_RATE_32000,
336 			.channels_min = 2,
337 			.channels_max = 2,
338 		},
339 		.ops = &uniphier_aio_i2s_ops,
340 	},
341 	{
342 		.name    = AUD_NAME_HIECCOMPOUT1,
343 		.probe   = uniphier_aio_ld11_probe,
344 		.remove  = uniphier_aio_dai_remove,
345 		.compress_new = snd_soc_new_compress,
346 		.playback = {
347 			.stream_name = AUD_NAME_HIECCOMPOUT1,
348 			.channels_min = 1,
349 			.channels_max = 1,
350 		},
351 		.ops = &uniphier_aio_spdif_ops,
352 	},
353 };
354 
355 static const struct uniphier_aio_chip_spec uniphier_aio_ld11_spec = {
356 	.specs     = uniphier_aio_ld11,
357 	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
358 	.dais      = uniphier_aio_dai_ld11,
359 	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
360 	.plls      = uniphier_aio_pll_ld11,
361 	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
362 	.addr_ext  = 0,
363 };
364 
365 static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
366 	.specs     = uniphier_aio_ld11,
367 	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
368 	.dais      = uniphier_aio_dai_ld11,
369 	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
370 	.plls      = uniphier_aio_pll_ld11,
371 	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
372 	.addr_ext  = 1,
373 };
374 
375 static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
376 	{
377 		.compatible = "socionext,uniphier-ld11-aio",
378 		.data = &uniphier_aio_ld11_spec,
379 	},
380 	{
381 		.compatible = "socionext,uniphier-ld20-aio",
382 		.data = &uniphier_aio_ld20_spec,
383 	},
384 	{},
385 };
386 MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
387 
388 static struct platform_driver uniphier_aio_driver = {
389 	.driver = {
390 		.name = "snd-uniphier-aio-ld11",
391 		.of_match_table = of_match_ptr(uniphier_aio_of_match),
392 	},
393 	.probe    = uniphier_aio_probe,
394 	.remove   = uniphier_aio_remove,
395 };
396 module_platform_driver(uniphier_aio_driver);
397 
398 MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
399 MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
400 MODULE_LICENSE("GPL v2");
401