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
11static 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
180static 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
191static 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
216static 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
355static 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
365static 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
375static const struct of_device_id uniphier_aio_of_match[] = {
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};
386MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
387
388static 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};
396module_platform_driver(uniphier_aio_driver);
397
398MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
399MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
400MODULE_LICENSE("GPL v2");
401