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
tegra_ahub_get_value_enum(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * uctl)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
tegra_ahub_put_value_enum(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * uctl)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
tegra_ahub_runtime_suspend(struct device * dev)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
tegra_ahub_runtime_resume(struct device * dev)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
tegra_ahub_probe(struct platform_device * pdev)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
tegra_ahub_remove(struct platform_device * pdev)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