1// SPDX-License-Identifier: GPL-2.0-only
2//
3// tegra210_ahub.c - Tegra210 AHUB driver
4//
5// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
6
7#include <linux/clk.h>
8#include <linux/device.h>
9#include <linux/module.h>
10#include <linux/of_platform.h>
11#include <linux/platform_device.h>
12#include <linux/pm_runtime.h>
13#include <linux/regmap.h>
14#include <sound/soc.h>
15#include "tegra210_ahub.h"
16
17static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
18				     struct snd_ctl_elem_value *uctl)
19{
20	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
21	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
22	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
23	unsigned int reg, i, bit_pos = 0;
24
25	/*
26	 * Find the bit position of current MUX input.
27	 * If nothing is set, position would be 0 and it corresponds to 'None'.
28	 */
29	for (i = 0; i < ahub->soc_data->reg_count; i++) {
30		unsigned int reg_val;
31
32		reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
33		reg_val = snd_soc_component_read(cmpnt, reg);
34		reg_val &= ahub->soc_data->mask[i];
35
36		if (reg_val) {
37			bit_pos = ffs(reg_val) +
38				  (8 * cmpnt->val_bytes * i);
39			break;
40		}
41	}
42
43	/* Find index related to the item in array *_ahub_mux_texts[] */
44	for (i = 0; i < e->items; i++) {
45		if (bit_pos == e->values[i]) {
46			uctl->value.enumerated.item[0] = i;
47			break;
48		}
49	}
50
51	return 0;
52}
53
54static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
55				     struct snd_ctl_elem_value *uctl)
56{
57	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
58	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
59	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctl);
60	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
61	struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
62	unsigned int *item = uctl->value.enumerated.item;
63	unsigned int value = e->values[item[0]];
64	unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
65	int change = 0;
66
67	if (item[0] >= e->items)
68		return -EINVAL;
69
70	if (value) {
71		/* Get the register index and value to set */
72		reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
73		bit_pos = (value - 1) % (8 * cmpnt->val_bytes);
74		reg_val = BIT(bit_pos);
75	}
76
77	/*
78	 * Run through all parts of a MUX register to find the state changes.
79	 * There will be an additional update if new MUX input value is from
80	 * different part of the MUX register.
81	 */
82	for (i = 0; i < ahub->soc_data->reg_count; i++) {
83		update[i].reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
84		update[i].val = (i == reg_idx) ? reg_val : 0;
85		update[i].mask = ahub->soc_data->mask[i];
86		update[i].kcontrol = kctl;
87
88		/* Update widget power if state has changed */
89		if (snd_soc_component_test_bits(cmpnt, update[i].reg,
90						update[i].mask,
91						update[i].val))
92			change |= snd_soc_dapm_mux_update_power(dapm, kctl,
93								item[0], e,
94								&update[i]);
95	}
96
97	return change;
98}
99
100static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
101	DAI(ADMAIF1),
102	DAI(ADMAIF2),
103	DAI(ADMAIF3),
104	DAI(ADMAIF4),
105	DAI(ADMAIF5),
106	DAI(ADMAIF6),
107	DAI(ADMAIF7),
108	DAI(ADMAIF8),
109	DAI(ADMAIF9),
110	DAI(ADMAIF10),
111	DAI(I2S1),
112	DAI(I2S2),
113	DAI(I2S3),
114	DAI(I2S4),
115	DAI(I2S5),
116	DAI(DMIC1),
117	DAI(DMIC2),
118	DAI(DMIC3),
119};
120
121static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
122	DAI(ADMAIF1),
123	DAI(ADMAIF2),
124	DAI(ADMAIF3),
125	DAI(ADMAIF4),
126	DAI(ADMAIF5),
127	DAI(ADMAIF6),
128	DAI(ADMAIF7),
129	DAI(ADMAIF8),
130	DAI(ADMAIF9),
131	DAI(ADMAIF10),
132	DAI(ADMAIF11),
133	DAI(ADMAIF12),
134	DAI(ADMAIF13),
135	DAI(ADMAIF14),
136	DAI(ADMAIF15),
137	DAI(ADMAIF16),
138	DAI(ADMAIF17),
139	DAI(ADMAIF18),
140	DAI(ADMAIF19),
141	DAI(ADMAIF20),
142	DAI(I2S1),
143	DAI(I2S2),
144	DAI(I2S3),
145	DAI(I2S4),
146	DAI(I2S5),
147	DAI(I2S6),
148	DAI(DMIC1),
149	DAI(DMIC2),
150	DAI(DMIC3),
151	DAI(DMIC4),
152	DAI(DSPK1),
153	DAI(DSPK2),
154};
155
156static const char * const tegra210_ahub_mux_texts[] = {
157	"None",
158	"ADMAIF1",
159	"ADMAIF2",
160	"ADMAIF3",
161	"ADMAIF4",
162	"ADMAIF5",
163	"ADMAIF6",
164	"ADMAIF7",
165	"ADMAIF8",
166	"ADMAIF9",
167	"ADMAIF10",
168	"I2S1",
169	"I2S2",
170	"I2S3",
171	"I2S4",
172	"I2S5",
173	"DMIC1",
174	"DMIC2",
175	"DMIC3",
176};
177
178static const char * const tegra186_ahub_mux_texts[] = {
179	"None",
180	"ADMAIF1",
181	"ADMAIF2",
182	"ADMAIF3",
183	"ADMAIF4",
184	"ADMAIF5",
185	"ADMAIF6",
186	"ADMAIF7",
187	"ADMAIF8",
188	"ADMAIF9",
189	"ADMAIF10",
190	"ADMAIF11",
191	"ADMAIF12",
192	"ADMAIF13",
193	"ADMAIF14",
194	"ADMAIF15",
195	"ADMAIF16",
196	"I2S1",
197	"I2S2",
198	"I2S3",
199	"I2S4",
200	"I2S5",
201	"I2S6",
202	"ADMAIF17",
203	"ADMAIF18",
204	"ADMAIF19",
205	"ADMAIF20",
206	"DMIC1",
207	"DMIC2",
208	"DMIC3",
209	"DMIC4",
210};
211
212static const unsigned int tegra210_ahub_mux_values[] = {
213	0,
214	MUX_VALUE(0, 0),
215	MUX_VALUE(0, 1),
216	MUX_VALUE(0, 2),
217	MUX_VALUE(0, 3),
218	MUX_VALUE(0, 4),
219	MUX_VALUE(0, 5),
220	MUX_VALUE(0, 6),
221	MUX_VALUE(0, 7),
222	MUX_VALUE(0, 8),
223	MUX_VALUE(0, 9),
224	MUX_VALUE(0, 16),
225	MUX_VALUE(0, 17),
226	MUX_VALUE(0, 18),
227	MUX_VALUE(0, 19),
228	MUX_VALUE(0, 20),
229	MUX_VALUE(2, 18),
230	MUX_VALUE(2, 19),
231	MUX_VALUE(2, 20),
232};
233
234static const unsigned int tegra186_ahub_mux_values[] = {
235	0,
236	MUX_VALUE(0, 0),
237	MUX_VALUE(0, 1),
238	MUX_VALUE(0, 2),
239	MUX_VALUE(0, 3),
240	MUX_VALUE(0, 4),
241	MUX_VALUE(0, 5),
242	MUX_VALUE(0, 6),
243	MUX_VALUE(0, 7),
244	MUX_VALUE(0, 8),
245	MUX_VALUE(0, 9),
246	MUX_VALUE(0, 10),
247	MUX_VALUE(0, 11),
248	MUX_VALUE(0, 12),
249	MUX_VALUE(0, 13),
250	MUX_VALUE(0, 14),
251	MUX_VALUE(0, 15),
252	MUX_VALUE(0, 16),
253	MUX_VALUE(0, 17),
254	MUX_VALUE(0, 18),
255	MUX_VALUE(0, 19),
256	MUX_VALUE(0, 20),
257	MUX_VALUE(0, 21),
258	MUX_VALUE(3, 16),
259	MUX_VALUE(3, 17),
260	MUX_VALUE(3, 18),
261	MUX_VALUE(3, 19),
262	MUX_VALUE(2, 18),
263	MUX_VALUE(2, 19),
264	MUX_VALUE(2, 20),
265	MUX_VALUE(2, 21),
266};
267
268/* Controls for t210 */
269MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
270MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
271MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
272MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
273MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
274MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
275MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
276MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
277MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
278MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
279MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
280MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
281MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
282MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
283MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
284
285/* Controls for t186 */
286MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
287MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
288MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
289MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
290MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
291MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
292MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
293MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
294MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
295MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
296MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
297MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
298MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
299MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
300MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
301MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
302MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
303MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
304MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
305MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
306MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
307MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
308MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
309MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
310MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
311MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
312MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
313MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b);
314
315/*
316 * The number of entries in, and order of, this array is closely tied to the
317 * calculation of tegra210_ahub_codec.num_dapm_widgets near the end of
318 * tegra210_ahub_probe()
319 */
320static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
321	WIDGETS("ADMAIF1", t210_admaif1_tx),
322	WIDGETS("ADMAIF2", t210_admaif2_tx),
323	WIDGETS("ADMAIF3", t210_admaif3_tx),
324	WIDGETS("ADMAIF4", t210_admaif4_tx),
325	WIDGETS("ADMAIF5", t210_admaif5_tx),
326	WIDGETS("ADMAIF6", t210_admaif6_tx),
327	WIDGETS("ADMAIF7", t210_admaif7_tx),
328	WIDGETS("ADMAIF8", t210_admaif8_tx),
329	WIDGETS("ADMAIF9", t210_admaif9_tx),
330	WIDGETS("ADMAIF10", t210_admaif10_tx),
331	WIDGETS("I2S1", t210_i2s1_tx),
332	WIDGETS("I2S2", t210_i2s2_tx),
333	WIDGETS("I2S3", t210_i2s3_tx),
334	WIDGETS("I2S4", t210_i2s4_tx),
335	WIDGETS("I2S5", t210_i2s5_tx),
336	TX_WIDGETS("DMIC1"),
337	TX_WIDGETS("DMIC2"),
338	TX_WIDGETS("DMIC3"),
339};
340
341static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
342	WIDGETS("ADMAIF1", t186_admaif1_tx),
343	WIDGETS("ADMAIF2", t186_admaif2_tx),
344	WIDGETS("ADMAIF3", t186_admaif3_tx),
345	WIDGETS("ADMAIF4", t186_admaif4_tx),
346	WIDGETS("ADMAIF5", t186_admaif5_tx),
347	WIDGETS("ADMAIF6", t186_admaif6_tx),
348	WIDGETS("ADMAIF7", t186_admaif7_tx),
349	WIDGETS("ADMAIF8", t186_admaif8_tx),
350	WIDGETS("ADMAIF9", t186_admaif9_tx),
351	WIDGETS("ADMAIF10", t186_admaif10_tx),
352	WIDGETS("ADMAIF11", t186_admaif11_tx),
353	WIDGETS("ADMAIF12", t186_admaif12_tx),
354	WIDGETS("ADMAIF13", t186_admaif13_tx),
355	WIDGETS("ADMAIF14", t186_admaif14_tx),
356	WIDGETS("ADMAIF15", t186_admaif15_tx),
357	WIDGETS("ADMAIF16", t186_admaif16_tx),
358	WIDGETS("ADMAIF17", t186_admaif17_tx),
359	WIDGETS("ADMAIF18", t186_admaif18_tx),
360	WIDGETS("ADMAIF19", t186_admaif19_tx),
361	WIDGETS("ADMAIF20", t186_admaif20_tx),
362	WIDGETS("I2S1", t186_i2s1_tx),
363	WIDGETS("I2S2", t186_i2s2_tx),
364	WIDGETS("I2S3", t186_i2s3_tx),
365	WIDGETS("I2S4", t186_i2s4_tx),
366	WIDGETS("I2S5", t186_i2s5_tx),
367	WIDGETS("I2S6", t186_i2s6_tx),
368	TX_WIDGETS("DMIC1"),
369	TX_WIDGETS("DMIC2"),
370	TX_WIDGETS("DMIC3"),
371	TX_WIDGETS("DMIC4"),
372	WIDGETS("DSPK1", t186_dspk1_tx),
373	WIDGETS("DSPK2", t186_dspk2_tx),
374};
375
376#define TEGRA_COMMON_MUX_ROUTES(name)					\
377	{ name " XBAR-TX",	 NULL,		name " Mux" },		\
378	{ name " Mux",		"ADMAIF1",	"ADMAIF1 XBAR-RX" },	\
379	{ name " Mux",		"ADMAIF2",	"ADMAIF2 XBAR-RX" },	\
380	{ name " Mux",		"ADMAIF3",	"ADMAIF3 XBAR-RX" },	\
381	{ name " Mux",		"ADMAIF4",	"ADMAIF4 XBAR-RX" },	\
382	{ name " Mux",		"ADMAIF5",	"ADMAIF5 XBAR-RX" },	\
383	{ name " Mux",		"ADMAIF6",	"ADMAIF6 XBAR-RX" },	\
384	{ name " Mux",		"ADMAIF7",	"ADMAIF7 XBAR-RX" },	\
385	{ name " Mux",		"ADMAIF8",	"ADMAIF8 XBAR-RX" },	\
386	{ name " Mux",		"ADMAIF9",	"ADMAIF9 XBAR-RX" },	\
387	{ name " Mux",		"ADMAIF10",	"ADMAIF10 XBAR-RX" },	\
388	{ name " Mux",		"I2S1",		"I2S1 XBAR-RX" },	\
389	{ name " Mux",		"I2S2",		"I2S2 XBAR-RX" },	\
390	{ name " Mux",		"I2S3",		"I2S3 XBAR-RX" },	\
391	{ name " Mux",		"I2S4",		"I2S4 XBAR-RX" },	\
392	{ name " Mux",		"I2S5",		"I2S5 XBAR-RX" },	\
393	{ name " Mux",		"DMIC1",	"DMIC1 XBAR-RX" },	\
394	{ name " Mux",		"DMIC2",	"DMIC2 XBAR-RX" },	\
395	{ name " Mux",		"DMIC3",	"DMIC3 XBAR-RX" },
396
397#define TEGRA186_ONLY_MUX_ROUTES(name)					\
398	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
399	{ name " Mux",		"ADMAIF12",	"ADMAIF12 XBAR-RX" },	\
400	{ name " Mux",		"ADMAIF13",	"ADMAIF13 XBAR-RX" },	\
401	{ name " Mux",		"ADMAIF14",	"ADMAIF14 XBAR-RX" },	\
402	{ name " Mux",		"ADMAIF15",	"ADMAIF15 XBAR-RX" },	\
403	{ name " Mux",		"ADMAIF16",	"ADMAIF16 XBAR-RX" },	\
404	{ name " Mux",		"ADMAIF17",	"ADMAIF17 XBAR-RX" },	\
405	{ name " Mux",		"ADMAIF18",	"ADMAIF18 XBAR-RX" },	\
406	{ name " Mux",		"ADMAIF19",	"ADMAIF19 XBAR-RX" },	\
407	{ name " Mux",		"ADMAIF20",	"ADMAIF20 XBAR-RX" },	\
408	{ name " Mux",		"I2S6",		"I2S6 XBAR-RX" },	\
409	{ name " Mux",		"DMIC4",	"DMIC4 XBAR-RX" },
410
411#define TEGRA210_MUX_ROUTES(name)						\
412	TEGRA_COMMON_MUX_ROUTES(name)
413
414#define TEGRA186_MUX_ROUTES(name)						\
415	TEGRA_COMMON_MUX_ROUTES(name)					\
416	TEGRA186_ONLY_MUX_ROUTES(name)
417
418/* Connect FEs with XBAR */
419#define TEGRA_FE_ROUTES(name) \
420	{ name " XBAR-Playback",	NULL,	name " Playback" },	\
421	{ name " XBAR-RX",		NULL,	name " XBAR-Playback"}, \
422	{ name " XBAR-Capture",		NULL,	name " XBAR-TX" },      \
423	{ name " Capture",		NULL,	name " XBAR-Capture" },
424
425/*
426 * The number of entries in, and order of, this array is closely tied to the
427 * calculation of tegra210_ahub_codec.num_dapm_routes near the end of
428 * tegra210_ahub_probe()
429 */
430static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
431	TEGRA_FE_ROUTES("ADMAIF1")
432	TEGRA_FE_ROUTES("ADMAIF2")
433	TEGRA_FE_ROUTES("ADMAIF3")
434	TEGRA_FE_ROUTES("ADMAIF4")
435	TEGRA_FE_ROUTES("ADMAIF5")
436	TEGRA_FE_ROUTES("ADMAIF6")
437	TEGRA_FE_ROUTES("ADMAIF7")
438	TEGRA_FE_ROUTES("ADMAIF8")
439	TEGRA_FE_ROUTES("ADMAIF9")
440	TEGRA_FE_ROUTES("ADMAIF10")
441	TEGRA210_MUX_ROUTES("ADMAIF1")
442	TEGRA210_MUX_ROUTES("ADMAIF2")
443	TEGRA210_MUX_ROUTES("ADMAIF3")
444	TEGRA210_MUX_ROUTES("ADMAIF4")
445	TEGRA210_MUX_ROUTES("ADMAIF5")
446	TEGRA210_MUX_ROUTES("ADMAIF6")
447	TEGRA210_MUX_ROUTES("ADMAIF7")
448	TEGRA210_MUX_ROUTES("ADMAIF8")
449	TEGRA210_MUX_ROUTES("ADMAIF9")
450	TEGRA210_MUX_ROUTES("ADMAIF10")
451	TEGRA210_MUX_ROUTES("I2S1")
452	TEGRA210_MUX_ROUTES("I2S2")
453	TEGRA210_MUX_ROUTES("I2S3")
454	TEGRA210_MUX_ROUTES("I2S4")
455	TEGRA210_MUX_ROUTES("I2S5")
456};
457
458static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
459	TEGRA_FE_ROUTES("ADMAIF1")
460	TEGRA_FE_ROUTES("ADMAIF2")
461	TEGRA_FE_ROUTES("ADMAIF3")
462	TEGRA_FE_ROUTES("ADMAIF4")
463	TEGRA_FE_ROUTES("ADMAIF5")
464	TEGRA_FE_ROUTES("ADMAIF6")
465	TEGRA_FE_ROUTES("ADMAIF7")
466	TEGRA_FE_ROUTES("ADMAIF8")
467	TEGRA_FE_ROUTES("ADMAIF9")
468	TEGRA_FE_ROUTES("ADMAIF10")
469	TEGRA_FE_ROUTES("ADMAIF11")
470	TEGRA_FE_ROUTES("ADMAIF12")
471	TEGRA_FE_ROUTES("ADMAIF13")
472	TEGRA_FE_ROUTES("ADMAIF14")
473	TEGRA_FE_ROUTES("ADMAIF15")
474	TEGRA_FE_ROUTES("ADMAIF16")
475	TEGRA_FE_ROUTES("ADMAIF17")
476	TEGRA_FE_ROUTES("ADMAIF18")
477	TEGRA_FE_ROUTES("ADMAIF19")
478	TEGRA_FE_ROUTES("ADMAIF20")
479	TEGRA186_MUX_ROUTES("ADMAIF1")
480	TEGRA186_MUX_ROUTES("ADMAIF2")
481	TEGRA186_MUX_ROUTES("ADMAIF3")
482	TEGRA186_MUX_ROUTES("ADMAIF4")
483	TEGRA186_MUX_ROUTES("ADMAIF5")
484	TEGRA186_MUX_ROUTES("ADMAIF6")
485	TEGRA186_MUX_ROUTES("ADMAIF7")
486	TEGRA186_MUX_ROUTES("ADMAIF8")
487	TEGRA186_MUX_ROUTES("ADMAIF9")
488	TEGRA186_MUX_ROUTES("ADMAIF10")
489	TEGRA186_MUX_ROUTES("ADMAIF11")
490	TEGRA186_MUX_ROUTES("ADMAIF12")
491	TEGRA186_MUX_ROUTES("ADMAIF13")
492	TEGRA186_MUX_ROUTES("ADMAIF14")
493	TEGRA186_MUX_ROUTES("ADMAIF15")
494	TEGRA186_MUX_ROUTES("ADMAIF16")
495	TEGRA186_MUX_ROUTES("ADMAIF17")
496	TEGRA186_MUX_ROUTES("ADMAIF18")
497	TEGRA186_MUX_ROUTES("ADMAIF19")
498	TEGRA186_MUX_ROUTES("ADMAIF20")
499	TEGRA186_MUX_ROUTES("I2S1")
500	TEGRA186_MUX_ROUTES("I2S2")
501	TEGRA186_MUX_ROUTES("I2S3")
502	TEGRA186_MUX_ROUTES("I2S4")
503	TEGRA186_MUX_ROUTES("I2S5")
504	TEGRA186_MUX_ROUTES("I2S6")
505	TEGRA186_MUX_ROUTES("DSPK1")
506	TEGRA186_MUX_ROUTES("DSPK2")
507};
508
509static const struct snd_soc_component_driver tegra210_ahub_component = {
510	.dapm_widgets		= tegra210_ahub_widgets,
511	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ahub_widgets),
512	.dapm_routes		= tegra210_ahub_routes,
513	.num_dapm_routes	= ARRAY_SIZE(tegra210_ahub_routes),
514};
515
516static const struct snd_soc_component_driver tegra186_ahub_component = {
517	.dapm_widgets = tegra186_ahub_widgets,
518	.num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets),
519	.dapm_routes = tegra186_ahub_routes,
520	.num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes),
521};
522
523static const struct regmap_config tegra210_ahub_regmap_config = {
524	.reg_bits		= 32,
525	.val_bits		= 32,
526	.reg_stride		= 4,
527	.max_register		= TEGRA210_MAX_REGISTER_ADDR,
528	.cache_type		= REGCACHE_FLAT,
529};
530
531static const struct regmap_config tegra186_ahub_regmap_config = {
532	.reg_bits		= 32,
533	.val_bits		= 32,
534	.reg_stride		= 4,
535	.max_register		= TEGRA186_MAX_REGISTER_ADDR,
536	.cache_type		= REGCACHE_FLAT,
537};
538
539static const struct tegra_ahub_soc_data soc_data_tegra210 = {
540	.cmpnt_drv	= &tegra210_ahub_component,
541	.dai_drv	= tegra210_ahub_dais,
542	.num_dais	= ARRAY_SIZE(tegra210_ahub_dais),
543	.regmap_config	= &tegra210_ahub_regmap_config,
544	.mask[0]	= TEGRA210_XBAR_REG_MASK_0,
545	.mask[1]	= TEGRA210_XBAR_REG_MASK_1,
546	.mask[2]	= TEGRA210_XBAR_REG_MASK_2,
547	.mask[3]	= TEGRA210_XBAR_REG_MASK_3,
548	.reg_count	= TEGRA210_XBAR_UPDATE_MAX_REG,
549};
550
551static const struct tegra_ahub_soc_data soc_data_tegra186 = {
552	.cmpnt_drv	= &tegra186_ahub_component,
553	.dai_drv	= tegra186_ahub_dais,
554	.num_dais	= ARRAY_SIZE(tegra186_ahub_dais),
555	.regmap_config	= &tegra186_ahub_regmap_config,
556	.mask[0]	= TEGRA186_XBAR_REG_MASK_0,
557	.mask[1]	= TEGRA186_XBAR_REG_MASK_1,
558	.mask[2]	= TEGRA186_XBAR_REG_MASK_2,
559	.mask[3]	= TEGRA186_XBAR_REG_MASK_3,
560	.reg_count	= TEGRA186_XBAR_UPDATE_MAX_REG,
561};
562
563static const struct of_device_id tegra_ahub_of_match[] = {
564	{ .compatible = "nvidia,tegra210-ahub", .data = &soc_data_tegra210 },
565	{ .compatible = "nvidia,tegra186-ahub", .data = &soc_data_tegra186 },
566	{},
567};
568MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
569
570static int __maybe_unused tegra_ahub_runtime_suspend(struct device *dev)
571{
572	struct tegra_ahub *ahub = dev_get_drvdata(dev);
573
574	regcache_cache_only(ahub->regmap, true);
575	regcache_mark_dirty(ahub->regmap);
576
577	clk_disable_unprepare(ahub->clk);
578
579	return 0;
580}
581
582static int __maybe_unused tegra_ahub_runtime_resume(struct device *dev)
583{
584	struct tegra_ahub *ahub = dev_get_drvdata(dev);
585	int err;
586
587	err = clk_prepare_enable(ahub->clk);
588	if (err) {
589		dev_err(dev, "failed to enable AHUB clock, err: %d\n", err);
590		return err;
591	}
592
593	regcache_cache_only(ahub->regmap, false);
594	regcache_sync(ahub->regmap);
595
596	return 0;
597}
598
599static int tegra_ahub_probe(struct platform_device *pdev)
600{
601	struct tegra_ahub *ahub;
602	void __iomem *regs;
603	int err;
604
605	ahub = devm_kzalloc(&pdev->dev, sizeof(*ahub), GFP_KERNEL);
606	if (!ahub)
607		return -ENOMEM;
608
609	ahub->soc_data = of_device_get_match_data(&pdev->dev);
610
611	platform_set_drvdata(pdev, ahub);
612
613	ahub->clk = devm_clk_get(&pdev->dev, "ahub");
614	if (IS_ERR(ahub->clk)) {
615		dev_err(&pdev->dev, "can't retrieve AHUB clock\n");
616		return PTR_ERR(ahub->clk);
617	}
618
619	regs = devm_platform_ioremap_resource(pdev, 0);
620	if (IS_ERR(regs))
621		return PTR_ERR(regs);
622
623	ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
624					     ahub->soc_data->regmap_config);
625	if (IS_ERR(ahub->regmap)) {
626		dev_err(&pdev->dev, "regmap init failed\n");
627		return PTR_ERR(ahub->regmap);
628	}
629
630	regcache_cache_only(ahub->regmap, true);
631
632	err = devm_snd_soc_register_component(&pdev->dev,
633					      ahub->soc_data->cmpnt_drv,
634					      ahub->soc_data->dai_drv,
635					      ahub->soc_data->num_dais);
636	if (err) {
637		dev_err(&pdev->dev, "can't register AHUB component, err: %d\n",
638			err);
639		return err;
640	}
641
642	err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
643	if (err)
644		return err;
645
646	pm_runtime_enable(&pdev->dev);
647
648	return 0;
649}
650
651static int tegra_ahub_remove(struct platform_device *pdev)
652{
653	pm_runtime_disable(&pdev->dev);
654
655	return 0;
656}
657
658static const struct dev_pm_ops tegra_ahub_pm_ops = {
659	SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
660			   tegra_ahub_runtime_resume, NULL)
661	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
662				pm_runtime_force_resume)
663};
664
665static struct platform_driver tegra_ahub_driver = {
666	.probe = tegra_ahub_probe,
667	.remove = tegra_ahub_remove,
668	.driver = {
669		.name = "tegra210-ahub",
670		.of_match_table = tegra_ahub_of_match,
671		.pm = &tegra_ahub_pm_ops,
672	},
673};
674module_platform_driver(tegra_ahub_driver);
675
676MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
677MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
678MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
679MODULE_LICENSE("GPL v2");
680