linux/sound/soc/tegra/tegra210_ahub.c
<<
>>
Prefs
   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
  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         * 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
  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                /* 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
  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/* Controls for t210 */
 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/* Controls for t186 */
 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 * 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 */
 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/* 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 */
 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