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 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 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