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