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 struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
192	{
193		.name    = AUD_GNAME_HDMI,
194		.playback = {
195			.stream_name = AUD_NAME_PCMOUT1,
196			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
197			.rates       = SNDRV_PCM_RATE_48000,
198			.channels_min = 2,
199			.channels_max = 2,
200		},
201		.capture = {
202			.stream_name = AUD_NAME_PCMIN1,
203			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
204			.rates       = SNDRV_PCM_RATE_48000 |
205				SNDRV_PCM_RATE_44100 |
206				SNDRV_PCM_RATE_32000,
207			.channels_min = 2,
208			.channels_max = 2,
209		},
210		.ops = &uniphier_aio_i2s_ld11_ops,
211	},
212	{
213		.name    = AUD_NAME_PCMIN2,
214		.capture = {
215			.stream_name = AUD_NAME_PCMIN2,
216			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
217			.rates       = SNDRV_PCM_RATE_48000,
218			.channels_min = 2,
219			.channels_max = 2,
220		},
221		.ops = &uniphier_aio_i2s_ld11_ops,
222	},
223	{
224		.name    = AUD_GNAME_LINE,
225		.playback = {
226			.stream_name = AUD_NAME_PCMOUT2,
227			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
228			.rates       = SNDRV_PCM_RATE_48000,
229			.channels_min = 2,
230			.channels_max = 2,
231		},
232		.capture = {
233			.stream_name = AUD_NAME_PCMIN3,
234			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
235			.rates       = SNDRV_PCM_RATE_48000,
236			.channels_min = 2,
237			.channels_max = 2,
238		},
239		.ops = &uniphier_aio_i2s_ld11_ops,
240	},
241	{
242		.name    = AUD_NAME_HPCMOUT1,
243		.playback = {
244			.stream_name = AUD_NAME_HPCMOUT1,
245			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
246			.rates       = SNDRV_PCM_RATE_48000,
247			.channels_min = 2,
248			.channels_max = 8,
249		},
250		.ops = &uniphier_aio_i2s_ld11_ops,
251	},
252	{
253		.name    = AUD_NAME_PCMOUT3,
254		.playback = {
255			.stream_name = AUD_NAME_PCMOUT3,
256			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
257			.rates       = SNDRV_PCM_RATE_48000,
258			.channels_min = 2,
259			.channels_max = 2,
260		},
261		.ops = &uniphier_aio_i2s_ld11_ops,
262	},
263	{
264		.name    = AUD_NAME_HIECOUT1,
265		.playback = {
266			.stream_name = AUD_NAME_HIECOUT1,
267			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
268			.rates       = SNDRV_PCM_RATE_48000,
269			.channels_min = 2,
270			.channels_max = 2,
271		},
272		.ops = &uniphier_aio_spdif_ld11_ops,
273	},
274	{
275		.name    = AUD_NAME_EPCMOUT2,
276		.playback = {
277			.stream_name = AUD_NAME_EPCMOUT2,
278			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
279			.rates       = SNDRV_PCM_RATE_48000 |
280				SNDRV_PCM_RATE_44100 |
281				SNDRV_PCM_RATE_32000,
282			.channels_min = 2,
283			.channels_max = 2,
284		},
285		.ops = &uniphier_aio_i2s_ld11_ops,
286	},
287	{
288		.name    = AUD_NAME_EPCMOUT3,
289		.playback = {
290			.stream_name = AUD_NAME_EPCMOUT3,
291			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
292			.rates       = SNDRV_PCM_RATE_48000 |
293				SNDRV_PCM_RATE_44100 |
294				SNDRV_PCM_RATE_32000,
295			.channels_min = 2,
296			.channels_max = 2,
297		},
298		.ops = &uniphier_aio_i2s_ld11_ops,
299	},
300	{
301		.name    = AUD_NAME_HIECCOMPOUT1,
302		.playback = {
303			.stream_name = AUD_NAME_HIECCOMPOUT1,
304			.channels_min = 1,
305			.channels_max = 1,
306		},
307		.ops = &uniphier_aio_spdif_ld11_ops2,
308	},
309};
310
311static const struct uniphier_aio_chip_spec uniphier_aio_ld11_spec = {
312	.specs     = uniphier_aio_ld11,
313	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
314	.dais      = uniphier_aio_dai_ld11,
315	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
316	.plls      = uniphier_aio_pll_ld11,
317	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
318	.addr_ext  = 0,
319};
320
321static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
322	.specs     = uniphier_aio_ld11,
323	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
324	.dais      = uniphier_aio_dai_ld11,
325	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
326	.plls      = uniphier_aio_pll_ld11,
327	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
328	.addr_ext  = 1,
329};
330
331static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
332	{
333		.compatible = "socionext,uniphier-ld11-aio",
334		.data = &uniphier_aio_ld11_spec,
335	},
336	{
337		.compatible = "socionext,uniphier-ld20-aio",
338		.data = &uniphier_aio_ld20_spec,
339	},
340	{},
341};
342MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
343
344static struct platform_driver uniphier_aio_driver = {
345	.driver = {
346		.name = "snd-uniphier-aio-ld11",
347		.of_match_table = of_match_ptr(uniphier_aio_of_match),
348	},
349	.probe    = uniphier_aio_probe,
350	.remove   = uniphier_aio_remove,
351};
352module_platform_driver(uniphier_aio_driver);
353
354MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
355MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
356MODULE_LICENSE("GPL v2");
357