1
2
3
4
5
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
27
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
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
66 if (item[0] >= e->items)
67 return -EINVAL;
68
69 if (value) {
70
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
78
79
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
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
97static 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
118static 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
153static 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
175static 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
209static 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
231static 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
266MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
267MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
268MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
269MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
270MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
271MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
272MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
273MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
274MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
275MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
276MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
277MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
278MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
279MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
280MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
281
282
283MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
284MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
285MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
286MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
287MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
288MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
289MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
290MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
291MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
292MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
293MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
294MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
295MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
296MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
297MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
298MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
299MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
300MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
301MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
302MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
303MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
304MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
305MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
306MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
307MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
308MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
309MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
310MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b);
311
312
313
314
315
316
317static 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
338static 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
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
424
425
426
427static 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
455static 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
506static 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
513static 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
520static 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
528static 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
536static 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
548static 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
560static 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};
565MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
566
567static 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
579static 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
596static 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
648static int tegra_ahub_remove(struct platform_device *pdev)
649{
650 pm_runtime_disable(&pdev->dev);
651
652 return 0;
653}
654
655static 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
662static 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};
671module_platform_driver(tegra_ahub_driver);
672
673MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
674MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
675MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
676MODULE_LICENSE("GPL v2");
677