xref: /openbmc/linux/sound/soc/tegra/tegra210_ahub.c (revision f50dcc9d)
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 
17 static 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 
54 static 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 
100 static 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 
121 static 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 
156 static 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 
178 static 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 
212 static 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 
234 static 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 */
269 MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
270 MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
271 MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
272 MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
273 MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
274 MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
275 MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
276 MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
277 MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
278 MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
279 MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
280 MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
281 MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
282 MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
283 MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
284 
285 /* Controls for t186 */
286 MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
287 MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
288 MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
289 MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
290 MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
291 MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
292 MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
293 MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
294 MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
295 MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
296 MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
297 MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
298 MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
299 MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
300 MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
301 MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
302 MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
303 MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
304 MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
305 MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
306 MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
307 MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
308 MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
309 MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
310 MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
311 MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
312 MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
313 MUX_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  */
320 static 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 
341 static 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  */
430 static 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 
458 static 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 
509 static 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 
516 static 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 
523 static 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 
531 static 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 
539 static 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 
551 static 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 
563 static 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 };
568 MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
569 
570 static 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 
582 static 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 
599 static 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 
651 static int tegra_ahub_remove(struct platform_device *pdev)
652 {
653 	pm_runtime_disable(&pdev->dev);
654 
655 	return 0;
656 }
657 
658 static 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 
665 static 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 };
674 module_platform_driver(tegra_ahub_driver);
675 
676 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
677 MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
678 MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
679 MODULE_LICENSE("GPL v2");
680