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 of_device_id *match;
 516        const struct tegra30_ahub_soc_data *soc_data;
 517        struct resource *res0;
 518        void __iomem *regs_apbif, *regs_ahub;
 519        int ret = 0;
 520
 521        match = of_match_device(tegra30_ahub_of_match, &pdev->dev);
 522        if (!match)
 523                return -EINVAL;
 524        soc_data = match->data;
 525
 526        ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
 527                            GFP_KERNEL);
 528        if (!ahub)
 529                return -ENOMEM;
 530        dev_set_drvdata(&pdev->dev, ahub);
 531
 532        BUILD_BUG_ON(sizeof(ahub->resets) != sizeof(tegra30_ahub_resets_data));
 533        memcpy(ahub->resets, tegra30_ahub_resets_data, sizeof(ahub->resets));
 534
 535        ahub->nresets = soc_data->num_resets;
 536        ahub->soc_data = soc_data;
 537        ahub->dev = &pdev->dev;
 538
 539        ahub->clocks[ahub->nclocks++].id = "apbif";
 540        ahub->clocks[ahub->nclocks++].id = "d_audio";
 541
 542        ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
 543        if (ret)
 544                goto err_unset_ahub;
 545
 546        ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets,
 547                                                    ahub->resets);
 548        if (ret) {
 549                dev_err(&pdev->dev, "Can't get resets: %d\n", ret);
 550                goto err_unset_ahub;
 551        }
 552
 553        regs_apbif = devm_platform_get_and_ioremap_resource(pdev, 0, &res0);
 554        if (IS_ERR(regs_apbif)) {
 555                ret = PTR_ERR(regs_apbif);
 556                goto err_unset_ahub;
 557        }
 558
 559        ahub->apbif_addr = res0->start;
 560
 561        ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
 562                                        &tegra30_ahub_apbif_regmap_config);
 563        if (IS_ERR(ahub->regmap_apbif)) {
 564                dev_err(&pdev->dev, "apbif regmap init failed\n");
 565                ret = PTR_ERR(ahub->regmap_apbif);
 566                goto err_unset_ahub;
 567        }
 568        regcache_cache_only(ahub->regmap_apbif, true);
 569
 570        regs_ahub = devm_platform_ioremap_resource(pdev, 1);
 571        if (IS_ERR(regs_ahub)) {
 572                ret = PTR_ERR(regs_ahub);
 573                goto err_unset_ahub;
 574        }
 575
 576        ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
 577                                        &tegra30_ahub_ahub_regmap_config);
 578        if (IS_ERR(ahub->regmap_ahub)) {
 579                dev_err(&pdev->dev, "ahub regmap init failed\n");
 580                ret = PTR_ERR(ahub->regmap_ahub);
 581                goto err_unset_ahub;
 582        }
 583        regcache_cache_only(ahub->regmap_ahub, true);
 584
 585        pm_runtime_enable(&pdev->dev);
 586
 587        of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 588
 589        return 0;
 590
 591err_unset_ahub:
 592        ahub = NULL;
 593
 594        return ret;
 595}
 596
 597static int tegra30_ahub_remove(struct platform_device *pdev)
 598{
 599        pm_runtime_disable(&pdev->dev);
 600
 601        ahub = NULL;
 602
 603        return 0;
 604}
 605
 606static const struct dev_pm_ops tegra30_ahub_pm_ops = {
 607        SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
 608                           tegra30_ahub_runtime_resume, NULL)
 609        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 610                                pm_runtime_force_resume)
 611};
 612
 613static struct platform_driver tegra30_ahub_driver = {
 614        .probe = tegra30_ahub_probe,
 615        .remove = tegra30_ahub_remove,
 616        .driver = {
 617                .name = DRV_NAME,
 618                .of_match_table = tegra30_ahub_of_match,
 619                .pm = &tegra30_ahub_pm_ops,
 620        },
 621};
 622module_platform_driver(tegra30_ahub_driver);
 623
 624void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
 625                          struct tegra30_ahub_cif_conf *conf)
 626{
 627        unsigned int value;
 628
 629        value = (conf->threshold <<
 630                        TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
 631                ((conf->audio_channels - 1) <<
 632                        TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
 633                ((conf->client_channels - 1) <<
 634                        TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
 635                (conf->audio_bits <<
 636                        TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
 637                (conf->client_bits <<
 638                        TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
 639                (conf->expand <<
 640                        TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
 641                (conf->stereo_conv <<
 642                        TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
 643                (conf->replicate <<
 644                        TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
 645                (conf->direction <<
 646                        TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
 647                (conf->truncate <<
 648                        TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
 649                (conf->mono_conv <<
 650                        TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
 651
 652        regmap_write(regmap, reg, value);
 653}
 654EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
 655
 656void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
 657                           struct tegra30_ahub_cif_conf *conf)
 658{
 659        unsigned int value;
 660
 661        value = (conf->threshold <<
 662                        TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
 663                ((conf->audio_channels - 1) <<
 664                        TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
 665                ((conf->client_channels - 1) <<
 666                        TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
 667                (conf->audio_bits <<
 668                        TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
 669                (conf->client_bits <<
 670                        TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
 671                (conf->expand <<
 672                        TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
 673                (conf->stereo_conv <<
 674                        TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
 675                (conf->replicate <<
 676                        TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
 677                (conf->direction <<
 678                        TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
 679                (conf->truncate <<
 680                        TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
 681                (conf->mono_conv <<
 682                        TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
 683
 684        regmap_write(regmap, reg, value);
 685}
 686EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
 687
 688MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 689MODULE_DESCRIPTION("Tegra30 AHUB driver");
 690MODULE_LICENSE("GPL v2");
 691MODULE_ALIAS("platform:" DRV_NAME);
 692MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);
 693