linux/sound/soc/tegra/tegra30_ahub.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * tegra30_ahub.c - Tegra30 AHUB driver
   4 *
   5 * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
   6 */
   7
   8#include <linux/clk.h>
   9#include <linux/device.h>
  10#include <linux/io.h>
  11#include <linux/module.h>
  12#include <linux/of_platform.h>
  13#include <linux/platform_device.h>
  14#include <linux/pm_runtime.h>
  15#include <linux/regmap.h>
  16#include <linux/reset.h>
  17#include <linux/slab.h>
  18#include <sound/soc.h>
  19#include "tegra30_ahub.h"
  20
  21#define DRV_NAME "tegra30-ahub"
  22
  23static struct tegra30_ahub *ahub;
  24
  25static inline void tegra30_apbif_write(u32 reg, u32 val)
  26{
  27        regmap_write(ahub->regmap_apbif, reg, val);
  28}
  29
  30static inline u32 tegra30_apbif_read(u32 reg)
  31{
  32        u32 val;
  33
  34        regmap_read(ahub->regmap_apbif, reg, &val);
  35        return val;
  36}
  37
  38static inline void tegra30_audio_write(u32 reg, u32 val)
  39{
  40        regmap_write(ahub->regmap_ahub, reg, val);
  41}
  42
  43static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev)
  44{
  45        regcache_cache_only(ahub->regmap_apbif, true);
  46        regcache_cache_only(ahub->regmap_ahub, true);
  47
  48        clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
  49
  50        return 0;
  51}
  52
  53/*
  54 * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
  55 * is read from or sent to memory. However, that's not something the rest of
  56 * the driver supports right now, so we'll just treat the two clocks as one
  57 * for now.
  58 *
  59 * These functions should not be a plain ref-count. Instead, each active stream
  60 * contributes some requirement to the minimum clock rate, so starting or
  61 * stopping streams should dynamically adjust the clock as required.  However,
  62 * this is not yet implemented.
  63 */
  64static __maybe_unused int tegra30_ahub_runtime_resume(struct device *dev)
  65{
  66        int ret;
  67
  68        ret = reset_control_bulk_assert(ahub->nresets, ahub->resets);
  69        if (ret)
  70                return ret;
  71
  72        ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
  73        if (ret)
  74                return ret;
  75
  76        usleep_range(10, 100);
  77
  78        ret = reset_control_bulk_deassert(ahub->nresets, ahub->resets);
  79        if (ret)
  80                goto disable_clocks;
  81
  82        regcache_cache_only(ahub->regmap_apbif, false);
  83        regcache_cache_only(ahub->regmap_ahub, false);
  84        regcache_mark_dirty(ahub->regmap_apbif);
  85        regcache_mark_dirty(ahub->regmap_ahub);
  86
  87        ret = regcache_sync(ahub->regmap_apbif);
  88        if (ret)
  89                goto disable_clocks;
  90
  91        ret = regcache_sync(ahub->regmap_ahub);
  92        if (ret)
  93                goto disable_clocks;
  94
  95        return 0;
  96
  97disable_clocks:
  98        clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
  99
 100        return ret;
 101}
 102
 103int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
 104                                  char *dmachan, int dmachan_len,
 105                                  dma_addr_t *fiforeg)
 106{
 107        int channel;
 108        u32 reg, val;
 109        struct tegra30_ahub_cif_conf cif_conf;
 110
 111        channel = find_first_zero_bit(ahub->rx_usage,
 112                                      TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
 113        if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
 114                return -EBUSY;
 115
 116        __set_bit(channel, ahub->rx_usage);
 117
 118        *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
 119        snprintf(dmachan, dmachan_len, "rx%d", channel);
 120        *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
 121                   (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
 122
 123        pm_runtime_get_sync(ahub->dev);
 124
 125        reg = TEGRA30_AHUB_CHANNEL_CTRL +
 126              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
 127        val = tegra30_apbif_read(reg);
 128        val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
 129                 TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
 130        val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
 131               TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
 132               TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
 133        tegra30_apbif_write(reg, val);
 134
 135        cif_conf.threshold = 0;
 136        cif_conf.audio_channels = 2;
 137        cif_conf.client_channels = 2;
 138        cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
 139        cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
 140        cif_conf.expand = 0;
 141        cif_conf.stereo_conv = 0;
 142        cif_conf.replicate = 0;
 143        cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
 144        cif_conf.truncate = 0;
 145        cif_conf.mono_conv = 0;
 146
 147        reg = TEGRA30_AHUB_CIF_RX_CTRL +
 148              (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
 149        ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
 150
 151        pm_runtime_put(ahub->dev);
 152
 153        return 0;
 154}
 155EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
 156
 157int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
 158{
 159        int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
 160        int reg, val;
 161
 162        pm_runtime_get_sync(ahub->dev);
 163
 164        reg = TEGRA30_AHUB_CHANNEL_CTRL +
 165              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
 166        val = tegra30_apbif_read(reg);
 167        val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
 168        tegra30_apbif_write(reg, val);
 169
 170        pm_runtime_put(ahub->dev);
 171
 172        return 0;
 173}
 174EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
 175
 176int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
 177{
 178        int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
 179        int reg, val;
 180
 181        pm_runtime_get_sync(ahub->dev);
 182
 183        reg = TEGRA30_AHUB_CHANNEL_CTRL +
 184              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
 185        val = tegra30_apbif_read(reg);
 186        val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
 187        tegra30_apbif_write(reg, val);
 188
 189        pm_runtime_put(ahub->dev);
 190
 191        return 0;
 192}
 193EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
 194
 195int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
 196{
 197        int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
 198
 199        __clear_bit(channel, ahub->rx_usage);
 200
 201        return 0;
 202}
 203EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
 204
 205int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
 206                                  char *dmachan, int dmachan_len,
 207                                  dma_addr_t *fiforeg)
 208{
 209        int channel;
 210        u32 reg, val;
 211        struct tegra30_ahub_cif_conf cif_conf;
 212
 213        channel = find_first_zero_bit(ahub->tx_usage,
 214                                      TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
 215        if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
 216                return -EBUSY;
 217
 218        __set_bit(channel, ahub->tx_usage);
 219
 220        *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
 221        snprintf(dmachan, dmachan_len, "tx%d", channel);
 222        *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
 223                   (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
 224
 225        pm_runtime_get_sync(ahub->dev);
 226
 227        reg = TEGRA30_AHUB_CHANNEL_CTRL +
 228              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
 229        val = tegra30_apbif_read(reg);
 230        val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
 231                 TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
 232        val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
 233               TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
 234               TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
 235        tegra30_apbif_write(reg, val);
 236
 237        cif_conf.threshold = 0;
 238        cif_conf.audio_channels = 2;
 239        cif_conf.client_channels = 2;
 240        cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
 241        cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
 242        cif_conf.expand = 0;
 243        cif_conf.stereo_conv = 0;
 244        cif_conf.replicate = 0;
 245        cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
 246        cif_conf.truncate = 0;
 247        cif_conf.mono_conv = 0;
 248
 249        reg = TEGRA30_AHUB_CIF_TX_CTRL +
 250              (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
 251        ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
 252
 253        pm_runtime_put(ahub->dev);
 254
 255        return 0;
 256}
 257EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
 258
 259int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
 260{
 261        int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
 262        int reg, val;
 263
 264        pm_runtime_get_sync(ahub->dev);
 265
 266        reg = TEGRA30_AHUB_CHANNEL_CTRL +
 267              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
 268        val = tegra30_apbif_read(reg);
 269        val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
 270        tegra30_apbif_write(reg, val);
 271
 272        pm_runtime_put(ahub->dev);
 273
 274        return 0;
 275}
 276EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
 277
 278int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
 279{
 280        int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
 281        int reg, val;
 282
 283        pm_runtime_get_sync(ahub->dev);
 284
 285        reg = TEGRA30_AHUB_CHANNEL_CTRL +
 286              (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
 287        val = tegra30_apbif_read(reg);
 288        val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
 289        tegra30_apbif_write(reg, val);
 290
 291        pm_runtime_put(ahub->dev);
 292
 293        return 0;
 294}
 295EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
 296
 297int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
 298{
 299        int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
 300
 301        __clear_bit(channel, ahub->tx_usage);
 302
 303        return 0;
 304}
 305EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
 306
 307int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
 308                                   enum tegra30_ahub_txcif txcif)
 309{
 310        int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
 311        int reg;
 312
 313        pm_runtime_get_sync(ahub->dev);
 314
 315        reg = TEGRA30_AHUB_AUDIO_RX +
 316              (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
 317        tegra30_audio_write(reg, 1 << txcif);
 318
 319        pm_runtime_put(ahub->dev);
 320
 321        return 0;
 322}
 323EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
 324
 325int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
 326{
 327        int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
 328        int reg;
 329
 330        pm_runtime_get_sync(ahub->dev);
 331
 332        reg = TEGRA30_AHUB_AUDIO_RX +
 333              (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
 334        tegra30_audio_write(reg, 0);
 335
 336        pm_runtime_put(ahub->dev);
 337
 338        return 0;
 339}
 340EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
 341
 342static const struct reset_control_bulk_data tegra30_ahub_resets_data[] = {
 343        { "d_audio" },
 344        { "apbif" },
 345        { "i2s0" },
 346        { "i2s1" },
 347        { "i2s2" },
 348        { "i2s3" },
 349        { "i2s4" },
 350        { "dam0" },
 351        { "dam1" },
 352        { "dam2" },
 353        { "spdif" },
 354        { "amx" }, /* Tegra114+ */
 355        { "adx" }, /* Tegra114+ */
 356        { "amx1" }, /* Tegra124 */
 357        { "adx1" }, /* Tegra124 */
 358        { "afc0" }, /* Tegra124 */
 359        { "afc1" }, /* Tegra124 */
 360        { "afc2" }, /* Tegra124 */
 361        { "afc3" }, /* Tegra124 */
 362        { "afc4" }, /* Tegra124 */
 363        { "afc5" }, /* Tegra124 */
 364};
 365
 366#define LAST_REG(name) \
 367        (TEGRA30_AHUB_##name + \
 368         (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
 369
 370#define REG_IN_ARRAY(reg, name) \
 371        ((reg >= TEGRA30_AHUB_##name) && \
 372         (reg <= LAST_REG(name) && \
 373         (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
 374
 375static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
 376{
 377        switch (reg) {
 378        case TEGRA30_AHUB_CONFIG_LINK_CTRL:
 379        case TEGRA30_AHUB_MISC_CTRL:
 380        case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
 381        case TEGRA30_AHUB_I2S_LIVE_STATUS:
 382        case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
 383        case TEGRA30_AHUB_I2S_INT_MASK:
 384        case TEGRA30_AHUB_DAM_INT_MASK:
 385        case TEGRA30_AHUB_SPDIF_INT_MASK:
 386        case TEGRA30_AHUB_APBIF_INT_MASK:
 387        case TEGRA30_AHUB_I2S_INT_STATUS:
 388        case TEGRA30_AHUB_DAM_INT_STATUS:
 389        case TEGRA30_AHUB_SPDIF_INT_STATUS:
 390        case TEGRA30_AHUB_APBIF_INT_STATUS:
 391        case TEGRA30_AHUB_I2S_INT_SOURCE:
 392        case TEGRA30_AHUB_DAM_INT_SOURCE:
 393        case TEGRA30_AHUB_SPDIF_INT_SOURCE:
 394        case TEGRA30_AHUB_APBIF_INT_SOURCE:
 395        case TEGRA30_AHUB_I2S_INT_SET:
 396        case TEGRA30_AHUB_DAM_INT_SET:
 397        case TEGRA30_AHUB_SPDIF_INT_SET:
 398        case TEGRA30_AHUB_APBIF_INT_SET:
 399                return true;
 400        default:
 401                break;
 402        }
 403
 404        if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
 405            REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
 406            REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
 407            REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
 408            REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
 409            REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
 410            REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
 411            REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
 412                return true;
 413
 414        return false;
 415}
 416
 417static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
 418                                            unsigned int reg)
 419{
 420        switch (reg) {
 421        case TEGRA30_AHUB_CONFIG_LINK_CTRL:
 422        case TEGRA30_AHUB_MISC_CTRL:
 423        case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
 424        case TEGRA30_AHUB_I2S_LIVE_STATUS:
 425        case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
 426        case TEGRA30_AHUB_I2S_INT_STATUS:
 427        case TEGRA30_AHUB_DAM_INT_STATUS:
 428        case TEGRA30_AHUB_SPDIF_INT_STATUS:
 429        case TEGRA30_AHUB_APBIF_INT_STATUS:
 430        case TEGRA30_AHUB_I2S_INT_SET:
 431        case TEGRA30_AHUB_DAM_INT_SET:
 432        case TEGRA30_AHUB_SPDIF_INT_SET:
 433        case TEGRA30_AHUB_APBIF_INT_SET:
 434                return true;
 435        default:
 436                break;
 437        }
 438
 439        if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
 440            REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
 441            REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
 442            REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
 443            REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
 444                return true;
 445
 446        return false;
 447}
 448
 449static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
 450                                            unsigned int reg)
 451{
 452        if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
 453            REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
 454                return true;
 455
 456        return false;
 457}
 458
 459static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
 460        .name = "apbif",
 461        .reg_bits = 32,
 462        .val_bits = 32,
 463        .reg_stride = 4,
 464        .max_register = TEGRA30_AHUB_APBIF_INT_SET,
 465        .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
 466        .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
 467        .volatile_reg = tegra30_ahub_apbif_volatile_reg,
 468        .precious_reg = tegra30_ahub_apbif_precious_reg,
 469        .cache_type = REGCACHE_FLAT,
 470};
 471
 472static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
 473{
 474        if (REG_IN_ARRAY(reg, AUDIO_RX))
 475                return true;
 476
 477        return false;
 478}
 479
 480static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
 481        .name = "ahub",
 482        .reg_bits = 32,
 483        .val_bits = 32,
 484        .reg_stride = 4,
 485        .max_register = LAST_REG(AUDIO_RX),
 486        .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
 487        .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
 488        .cache_type = REGCACHE_FLAT,
 489};
 490
 491static struct tegra30_ahub_soc_data soc_data_tegra30 = {
 492        .num_resets = 11,
 493        .set_audio_cif = tegra30_ahub_set_cif,
 494};
 495
 496static struct tegra30_ahub_soc_data soc_data_tegra114 = {
 497        .num_resets = 13,
 498        .set_audio_cif = tegra30_ahub_set_cif,
 499};
 500
 501static struct tegra30_ahub_soc_data soc_data_tegra124 = {
 502        .num_resets = 21,
 503        .set_audio_cif = tegra124_ahub_set_cif,
 504};
 505
 506static const struct of_device_id tegra30_ahub_of_match[] = {
 507        { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 },
 508        { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
 509        { .compatible = "nvidia,tegra30-ahub",  .data = &soc_data_tegra30 },
 510        {},
 511};
 512
 513static int tegra30_ahub_probe(struct platform_device *pdev)
 514{
 515        const struct tegra30_ahub_soc_data *soc_data;
 516        struct resource *res0;
 517        void __iomem *regs_apbif, *regs_ahub;
 518        int ret = 0;
 519
 520        soc_data = of_device_get_match_data(&pdev->dev);
 521        if (!soc_data)
 522                return -EINVAL;
 523
 524        ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
 525                            GFP_KERNEL);
 526        if (!ahub)
 527                return -ENOMEM;
 528        dev_set_drvdata(&pdev->dev, ahub);
 529
 530        BUILD_BUG_ON(sizeof(ahub->resets) != sizeof(tegra30_ahub_resets_data));
 531        memcpy(ahub->resets, tegra30_ahub_resets_data, sizeof(ahub->resets));
 532
 533        ahub->nresets = soc_data->num_resets;
 534        ahub->soc_data = soc_data;
 535        ahub->dev = &pdev->dev;
 536
 537        ahub->clocks[ahub->nclocks++].id = "apbif";
 538        ahub->clocks[ahub->nclocks++].id = "d_audio";
 539
 540        ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
 541        if (ret)
 542                goto err_unset_ahub;
 543
 544        ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets,
 545                                                    ahub->resets);
 546        if (ret) {
 547                dev_err(&pdev->dev, "Can't get resets: %d\n", ret);
 548                goto err_unset_ahub;
 549        }
 550
 551        regs_apbif = devm_platform_get_and_ioremap_resource(pdev, 0, &res0);
 552        if (IS_ERR(regs_apbif)) {
 553                ret = PTR_ERR(regs_apbif);
 554                goto err_unset_ahub;
 555        }
 556
 557        ahub->apbif_addr = res0->start;
 558
 559        ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
 560                                        &tegra30_ahub_apbif_regmap_config);
 561        if (IS_ERR(ahub->regmap_apbif)) {
 562                dev_err(&pdev->dev, "apbif regmap init failed\n");
 563                ret = PTR_ERR(ahub->regmap_apbif);
 564                goto err_unset_ahub;
 565        }
 566        regcache_cache_only(ahub->regmap_apbif, true);
 567
 568        regs_ahub = devm_platform_ioremap_resource(pdev, 1);
 569        if (IS_ERR(regs_ahub)) {
 570                ret = PTR_ERR(regs_ahub);
 571                goto err_unset_ahub;
 572        }
 573
 574        ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
 575                                        &tegra30_ahub_ahub_regmap_config);
 576        if (IS_ERR(ahub->regmap_ahub)) {
 577                dev_err(&pdev->dev, "ahub regmap init failed\n");
 578                ret = PTR_ERR(ahub->regmap_ahub);
 579                goto err_unset_ahub;
 580        }
 581        regcache_cache_only(ahub->regmap_ahub, true);
 582
 583        pm_runtime_enable(&pdev->dev);
 584
 585        of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 586
 587        return 0;
 588
 589err_unset_ahub:
 590        ahub = NULL;
 591
 592        return ret;
 593}
 594
 595static int tegra30_ahub_remove(struct platform_device *pdev)
 596{
 597        pm_runtime_disable(&pdev->dev);
 598
 599        ahub = NULL;
 600
 601        return 0;
 602}
 603
 604static const struct dev_pm_ops tegra30_ahub_pm_ops = {
 605        SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
 606                           tegra30_ahub_runtime_resume, NULL)
 607        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 608                                pm_runtime_force_resume)
 609};
 610
 611static struct platform_driver tegra30_ahub_driver = {
 612        .probe = tegra30_ahub_probe,
 613        .remove = tegra30_ahub_remove,
 614        .driver = {
 615                .name = DRV_NAME,
 616                .of_match_table = tegra30_ahub_of_match,
 617                .pm = &tegra30_ahub_pm_ops,
 618        },
 619};
 620module_platform_driver(tegra30_ahub_driver);
 621
 622void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
 623                          struct tegra30_ahub_cif_conf *conf)
 624{
 625        unsigned int value;
 626
 627        value = (conf->threshold <<
 628                        TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
 629                ((conf->audio_channels - 1) <<
 630                        TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
 631                ((conf->client_channels - 1) <<
 632                        TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
 633                (conf->audio_bits <<
 634                        TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
 635                (conf->client_bits <<
 636                        TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
 637                (conf->expand <<
 638                        TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
 639                (conf->stereo_conv <<
 640                        TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
 641                (conf->replicate <<
 642                        TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
 643                (conf->direction <<
 644                        TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
 645                (conf->truncate <<
 646                        TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
 647                (conf->mono_conv <<
 648                        TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
 649
 650        regmap_write(regmap, reg, value);
 651}
 652EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
 653
 654void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
 655                           struct tegra30_ahub_cif_conf *conf)
 656{
 657        unsigned int value;
 658
 659        value = (conf->threshold <<
 660                        TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
 661                ((conf->audio_channels - 1) <<
 662                        TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
 663                ((conf->client_channels - 1) <<
 664                        TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
 665                (conf->audio_bits <<
 666                        TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
 667                (conf->client_bits <<
 668                        TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
 669                (conf->expand <<
 670                        TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
 671                (conf->stereo_conv <<
 672                        TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
 673                (conf->replicate <<
 674                        TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
 675                (conf->direction <<
 676                        TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
 677                (conf->truncate <<
 678                        TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
 679                (conf->mono_conv <<
 680                        TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
 681
 682        regmap_write(regmap, reg, value);
 683}
 684EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
 685
 686MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 687MODULE_DESCRIPTION("Tegra30 AHUB driver");
 688MODULE_LICENSE("GPL v2");
 689MODULE_ALIAS("platform:" DRV_NAME);
 690MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);
 691