Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tegra30_ahub.c - Tegra30 AHUB driver
0004  *
0005  * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/device.h>
0010 #include <linux/io.h>
0011 #include <linux/module.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pm_runtime.h>
0015 #include <linux/regmap.h>
0016 #include <linux/reset.h>
0017 #include <linux/slab.h>
0018 #include <sound/soc.h>
0019 #include "tegra30_ahub.h"
0020 
0021 #define DRV_NAME "tegra30-ahub"
0022 
0023 static struct tegra30_ahub *ahub;
0024 
0025 static inline void tegra30_apbif_write(u32 reg, u32 val)
0026 {
0027     regmap_write(ahub->regmap_apbif, reg, val);
0028 }
0029 
0030 static inline u32 tegra30_apbif_read(u32 reg)
0031 {
0032     u32 val;
0033 
0034     regmap_read(ahub->regmap_apbif, reg, &val);
0035     return val;
0036 }
0037 
0038 static inline void tegra30_audio_write(u32 reg, u32 val)
0039 {
0040     regmap_write(ahub->regmap_ahub, reg, val);
0041 }
0042 
0043 static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev)
0044 {
0045     regcache_cache_only(ahub->regmap_apbif, true);
0046     regcache_cache_only(ahub->regmap_ahub, true);
0047 
0048     clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
0049 
0050     return 0;
0051 }
0052 
0053 /*
0054  * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
0055  * is read from or sent to memory. However, that's not something the rest of
0056  * the driver supports right now, so we'll just treat the two clocks as one
0057  * for now.
0058  *
0059  * These functions should not be a plain ref-count. Instead, each active stream
0060  * contributes some requirement to the minimum clock rate, so starting or
0061  * stopping streams should dynamically adjust the clock as required.  However,
0062  * this is not yet implemented.
0063  */
0064 static __maybe_unused int tegra30_ahub_runtime_resume(struct device *dev)
0065 {
0066     int ret;
0067 
0068     ret = reset_control_bulk_assert(ahub->nresets, ahub->resets);
0069     if (ret)
0070         return ret;
0071 
0072     ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
0073     if (ret)
0074         return ret;
0075 
0076     usleep_range(10, 100);
0077 
0078     ret = reset_control_bulk_deassert(ahub->nresets, ahub->resets);
0079     if (ret)
0080         goto disable_clocks;
0081 
0082     regcache_cache_only(ahub->regmap_apbif, false);
0083     regcache_cache_only(ahub->regmap_ahub, false);
0084     regcache_mark_dirty(ahub->regmap_apbif);
0085     regcache_mark_dirty(ahub->regmap_ahub);
0086 
0087     ret = regcache_sync(ahub->regmap_apbif);
0088     if (ret)
0089         goto disable_clocks;
0090 
0091     ret = regcache_sync(ahub->regmap_ahub);
0092     if (ret)
0093         goto disable_clocks;
0094 
0095     return 0;
0096 
0097 disable_clocks:
0098     clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
0099 
0100     return ret;
0101 }
0102 
0103 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
0104                   char *dmachan, int dmachan_len,
0105                   dma_addr_t *fiforeg)
0106 {
0107     int channel;
0108     u32 reg, val;
0109     struct tegra30_ahub_cif_conf cif_conf;
0110 
0111     channel = find_first_zero_bit(ahub->rx_usage,
0112                       TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
0113     if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
0114         return -EBUSY;
0115 
0116     __set_bit(channel, ahub->rx_usage);
0117 
0118     *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
0119     snprintf(dmachan, dmachan_len, "rx%d", channel);
0120     *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
0121            (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
0122 
0123     pm_runtime_get_sync(ahub->dev);
0124 
0125     reg = TEGRA30_AHUB_CHANNEL_CTRL +
0126           (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
0127     val = tegra30_apbif_read(reg);
0128     val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
0129          TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
0130     val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
0131            TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
0132            TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
0133     tegra30_apbif_write(reg, val);
0134 
0135     cif_conf.threshold = 0;
0136     cif_conf.audio_channels = 2;
0137     cif_conf.client_channels = 2;
0138     cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
0139     cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
0140     cif_conf.expand = 0;
0141     cif_conf.stereo_conv = 0;
0142     cif_conf.replicate = 0;
0143     cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
0144     cif_conf.truncate = 0;
0145     cif_conf.mono_conv = 0;
0146 
0147     reg = TEGRA30_AHUB_CIF_RX_CTRL +
0148           (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
0149     ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
0150 
0151     pm_runtime_put(ahub->dev);
0152 
0153     return 0;
0154 }
0155 EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
0156 
0157 int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
0158 {
0159     int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
0160     int reg, val;
0161 
0162     pm_runtime_get_sync(ahub->dev);
0163 
0164     reg = TEGRA30_AHUB_CHANNEL_CTRL +
0165           (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
0166     val = tegra30_apbif_read(reg);
0167     val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
0168     tegra30_apbif_write(reg, val);
0169 
0170     pm_runtime_put(ahub->dev);
0171 
0172     return 0;
0173 }
0174 EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
0175 
0176 int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
0177 {
0178     int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
0179     int reg, val;
0180 
0181     pm_runtime_get_sync(ahub->dev);
0182 
0183     reg = TEGRA30_AHUB_CHANNEL_CTRL +
0184           (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
0185     val = tegra30_apbif_read(reg);
0186     val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
0187     tegra30_apbif_write(reg, val);
0188 
0189     pm_runtime_put(ahub->dev);
0190 
0191     return 0;
0192 }
0193 EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
0194 
0195 int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
0196 {
0197     int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
0198 
0199     __clear_bit(channel, ahub->rx_usage);
0200 
0201     return 0;
0202 }
0203 EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
0204 
0205 int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
0206                   char *dmachan, int dmachan_len,
0207                   dma_addr_t *fiforeg)
0208 {
0209     int channel;
0210     u32 reg, val;
0211     struct tegra30_ahub_cif_conf cif_conf;
0212 
0213     channel = find_first_zero_bit(ahub->tx_usage,
0214                       TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
0215     if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
0216         return -EBUSY;
0217 
0218     __set_bit(channel, ahub->tx_usage);
0219 
0220     *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
0221     snprintf(dmachan, dmachan_len, "tx%d", channel);
0222     *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
0223            (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
0224 
0225     pm_runtime_get_sync(ahub->dev);
0226 
0227     reg = TEGRA30_AHUB_CHANNEL_CTRL +
0228           (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
0229     val = tegra30_apbif_read(reg);
0230     val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
0231          TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
0232     val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
0233            TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
0234            TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
0235     tegra30_apbif_write(reg, val);
0236 
0237     cif_conf.threshold = 0;
0238     cif_conf.audio_channels = 2;
0239     cif_conf.client_channels = 2;
0240     cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
0241     cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
0242     cif_conf.expand = 0;
0243     cif_conf.stereo_conv = 0;
0244     cif_conf.replicate = 0;
0245     cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
0246     cif_conf.truncate = 0;
0247     cif_conf.mono_conv = 0;
0248 
0249     reg = TEGRA30_AHUB_CIF_TX_CTRL +
0250           (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
0251     ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
0252 
0253     pm_runtime_put(ahub->dev);
0254 
0255     return 0;
0256 }
0257 EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
0258 
0259 int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
0260 {
0261     int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
0262     int reg, val;
0263 
0264     pm_runtime_get_sync(ahub->dev);
0265 
0266     reg = TEGRA30_AHUB_CHANNEL_CTRL +
0267           (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
0268     val = tegra30_apbif_read(reg);
0269     val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
0270     tegra30_apbif_write(reg, val);
0271 
0272     pm_runtime_put(ahub->dev);
0273 
0274     return 0;
0275 }
0276 EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
0277 
0278 int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
0279 {
0280     int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
0281     int reg, val;
0282 
0283     pm_runtime_get_sync(ahub->dev);
0284 
0285     reg = TEGRA30_AHUB_CHANNEL_CTRL +
0286           (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
0287     val = tegra30_apbif_read(reg);
0288     val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
0289     tegra30_apbif_write(reg, val);
0290 
0291     pm_runtime_put(ahub->dev);
0292 
0293     return 0;
0294 }
0295 EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
0296 
0297 int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
0298 {
0299     int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
0300 
0301     __clear_bit(channel, ahub->tx_usage);
0302 
0303     return 0;
0304 }
0305 EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
0306 
0307 int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
0308                    enum tegra30_ahub_txcif txcif)
0309 {
0310     int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
0311     int reg;
0312 
0313     pm_runtime_get_sync(ahub->dev);
0314 
0315     reg = TEGRA30_AHUB_AUDIO_RX +
0316           (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
0317     tegra30_audio_write(reg, 1 << txcif);
0318 
0319     pm_runtime_put(ahub->dev);
0320 
0321     return 0;
0322 }
0323 EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
0324 
0325 int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
0326 {
0327     int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
0328     int reg;
0329 
0330     pm_runtime_get_sync(ahub->dev);
0331 
0332     reg = TEGRA30_AHUB_AUDIO_RX +
0333           (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
0334     tegra30_audio_write(reg, 0);
0335 
0336     pm_runtime_put(ahub->dev);
0337 
0338     return 0;
0339 }
0340 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
0341 
0342 static const struct reset_control_bulk_data tegra30_ahub_resets_data[] = {
0343     { "d_audio" },
0344     { "apbif" },
0345     { "i2s0" },
0346     { "i2s1" },
0347     { "i2s2" },
0348     { "i2s3" },
0349     { "i2s4" },
0350     { "dam0" },
0351     { "dam1" },
0352     { "dam2" },
0353     { "spdif" },
0354     { "amx" }, /* Tegra114+ */
0355     { "adx" }, /* Tegra114+ */
0356     { "amx1" }, /* Tegra124 */
0357     { "adx1" }, /* Tegra124 */
0358     { "afc0" }, /* Tegra124 */
0359     { "afc1" }, /* Tegra124 */
0360     { "afc2" }, /* Tegra124 */
0361     { "afc3" }, /* Tegra124 */
0362     { "afc4" }, /* Tegra124 */
0363     { "afc5" }, /* Tegra124 */
0364 };
0365 
0366 #define LAST_REG(name) \
0367     (TEGRA30_AHUB_##name + \
0368      (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
0369 
0370 #define REG_IN_ARRAY(reg, name) \
0371     ((reg >= TEGRA30_AHUB_##name) && \
0372      (reg <= LAST_REG(name) && \
0373      (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
0374 
0375 static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
0376 {
0377     switch (reg) {
0378     case TEGRA30_AHUB_CONFIG_LINK_CTRL:
0379     case TEGRA30_AHUB_MISC_CTRL:
0380     case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
0381     case TEGRA30_AHUB_I2S_LIVE_STATUS:
0382     case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
0383     case TEGRA30_AHUB_I2S_INT_MASK:
0384     case TEGRA30_AHUB_DAM_INT_MASK:
0385     case TEGRA30_AHUB_SPDIF_INT_MASK:
0386     case TEGRA30_AHUB_APBIF_INT_MASK:
0387     case TEGRA30_AHUB_I2S_INT_STATUS:
0388     case TEGRA30_AHUB_DAM_INT_STATUS:
0389     case TEGRA30_AHUB_SPDIF_INT_STATUS:
0390     case TEGRA30_AHUB_APBIF_INT_STATUS:
0391     case TEGRA30_AHUB_I2S_INT_SOURCE:
0392     case TEGRA30_AHUB_DAM_INT_SOURCE:
0393     case TEGRA30_AHUB_SPDIF_INT_SOURCE:
0394     case TEGRA30_AHUB_APBIF_INT_SOURCE:
0395     case TEGRA30_AHUB_I2S_INT_SET:
0396     case TEGRA30_AHUB_DAM_INT_SET:
0397     case TEGRA30_AHUB_SPDIF_INT_SET:
0398     case TEGRA30_AHUB_APBIF_INT_SET:
0399         return true;
0400     default:
0401         break;
0402     }
0403 
0404     if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
0405         REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
0406         REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
0407         REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
0408         REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
0409         REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
0410         REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
0411         REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
0412         return true;
0413 
0414     return false;
0415 }
0416 
0417 static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
0418                         unsigned int reg)
0419 {
0420     switch (reg) {
0421     case TEGRA30_AHUB_CONFIG_LINK_CTRL:
0422     case TEGRA30_AHUB_MISC_CTRL:
0423     case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
0424     case TEGRA30_AHUB_I2S_LIVE_STATUS:
0425     case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
0426     case TEGRA30_AHUB_I2S_INT_STATUS:
0427     case TEGRA30_AHUB_DAM_INT_STATUS:
0428     case TEGRA30_AHUB_SPDIF_INT_STATUS:
0429     case TEGRA30_AHUB_APBIF_INT_STATUS:
0430     case TEGRA30_AHUB_I2S_INT_SET:
0431     case TEGRA30_AHUB_DAM_INT_SET:
0432     case TEGRA30_AHUB_SPDIF_INT_SET:
0433     case TEGRA30_AHUB_APBIF_INT_SET:
0434         return true;
0435     default:
0436         break;
0437     }
0438 
0439     if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
0440         REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
0441         REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
0442         REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
0443         REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
0444         return true;
0445 
0446     return false;
0447 }
0448 
0449 static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
0450                         unsigned int reg)
0451 {
0452     if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
0453         REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
0454         return true;
0455 
0456     return false;
0457 }
0458 
0459 static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
0460     .name = "apbif",
0461     .reg_bits = 32,
0462     .val_bits = 32,
0463     .reg_stride = 4,
0464     .max_register = TEGRA30_AHUB_APBIF_INT_SET,
0465     .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
0466     .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
0467     .volatile_reg = tegra30_ahub_apbif_volatile_reg,
0468     .precious_reg = tegra30_ahub_apbif_precious_reg,
0469     .cache_type = REGCACHE_FLAT,
0470 };
0471 
0472 static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
0473 {
0474     if (REG_IN_ARRAY(reg, AUDIO_RX))
0475         return true;
0476 
0477     return false;
0478 }
0479 
0480 static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
0481     .name = "ahub",
0482     .reg_bits = 32,
0483     .val_bits = 32,
0484     .reg_stride = 4,
0485     .max_register = LAST_REG(AUDIO_RX),
0486     .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
0487     .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
0488     .cache_type = REGCACHE_FLAT,
0489 };
0490 
0491 static struct tegra30_ahub_soc_data soc_data_tegra30 = {
0492     .num_resets = 11,
0493     .set_audio_cif = tegra30_ahub_set_cif,
0494 };
0495 
0496 static struct tegra30_ahub_soc_data soc_data_tegra114 = {
0497     .num_resets = 13,
0498     .set_audio_cif = tegra30_ahub_set_cif,
0499 };
0500 
0501 static struct tegra30_ahub_soc_data soc_data_tegra124 = {
0502     .num_resets = 21,
0503     .set_audio_cif = tegra124_ahub_set_cif,
0504 };
0505 
0506 static const struct of_device_id tegra30_ahub_of_match[] = {
0507     { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 },
0508     { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
0509     { .compatible = "nvidia,tegra30-ahub",  .data = &soc_data_tegra30 },
0510     {},
0511 };
0512 
0513 static int tegra30_ahub_probe(struct platform_device *pdev)
0514 {
0515     const struct tegra30_ahub_soc_data *soc_data;
0516     struct resource *res0;
0517     void __iomem *regs_apbif, *regs_ahub;
0518     int ret = 0;
0519 
0520     soc_data = of_device_get_match_data(&pdev->dev);
0521     if (!soc_data)
0522         return -EINVAL;
0523 
0524     ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
0525                 GFP_KERNEL);
0526     if (!ahub)
0527         return -ENOMEM;
0528     dev_set_drvdata(&pdev->dev, ahub);
0529 
0530     BUILD_BUG_ON(sizeof(ahub->resets) != sizeof(tegra30_ahub_resets_data));
0531     memcpy(ahub->resets, tegra30_ahub_resets_data, sizeof(ahub->resets));
0532 
0533     ahub->nresets = soc_data->num_resets;
0534     ahub->soc_data = soc_data;
0535     ahub->dev = &pdev->dev;
0536 
0537     ahub->clocks[ahub->nclocks++].id = "apbif";
0538     ahub->clocks[ahub->nclocks++].id = "d_audio";
0539 
0540     ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
0541     if (ret)
0542         goto err_unset_ahub;
0543 
0544     ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets,
0545                             ahub->resets);
0546     if (ret) {
0547         dev_err(&pdev->dev, "Can't get resets: %d\n", ret);
0548         goto err_unset_ahub;
0549     }
0550 
0551     regs_apbif = devm_platform_get_and_ioremap_resource(pdev, 0, &res0);
0552     if (IS_ERR(regs_apbif)) {
0553         ret = PTR_ERR(regs_apbif);
0554         goto err_unset_ahub;
0555     }
0556 
0557     ahub->apbif_addr = res0->start;
0558 
0559     ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
0560                     &tegra30_ahub_apbif_regmap_config);
0561     if (IS_ERR(ahub->regmap_apbif)) {
0562         dev_err(&pdev->dev, "apbif regmap init failed\n");
0563         ret = PTR_ERR(ahub->regmap_apbif);
0564         goto err_unset_ahub;
0565     }
0566     regcache_cache_only(ahub->regmap_apbif, true);
0567 
0568     regs_ahub = devm_platform_ioremap_resource(pdev, 1);
0569     if (IS_ERR(regs_ahub)) {
0570         ret = PTR_ERR(regs_ahub);
0571         goto err_unset_ahub;
0572     }
0573 
0574     ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
0575                     &tegra30_ahub_ahub_regmap_config);
0576     if (IS_ERR(ahub->regmap_ahub)) {
0577         dev_err(&pdev->dev, "ahub regmap init failed\n");
0578         ret = PTR_ERR(ahub->regmap_ahub);
0579         goto err_unset_ahub;
0580     }
0581     regcache_cache_only(ahub->regmap_ahub, true);
0582 
0583     pm_runtime_enable(&pdev->dev);
0584 
0585     of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
0586 
0587     return 0;
0588 
0589 err_unset_ahub:
0590     ahub = NULL;
0591 
0592     return ret;
0593 }
0594 
0595 static int tegra30_ahub_remove(struct platform_device *pdev)
0596 {
0597     pm_runtime_disable(&pdev->dev);
0598 
0599     ahub = NULL;
0600 
0601     return 0;
0602 }
0603 
0604 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
0605     SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
0606                tegra30_ahub_runtime_resume, NULL)
0607     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0608                 pm_runtime_force_resume)
0609 };
0610 
0611 static struct platform_driver tegra30_ahub_driver = {
0612     .probe = tegra30_ahub_probe,
0613     .remove = tegra30_ahub_remove,
0614     .driver = {
0615         .name = DRV_NAME,
0616         .of_match_table = tegra30_ahub_of_match,
0617         .pm = &tegra30_ahub_pm_ops,
0618     },
0619 };
0620 module_platform_driver(tegra30_ahub_driver);
0621 
0622 void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
0623               struct tegra30_ahub_cif_conf *conf)
0624 {
0625     unsigned int value;
0626 
0627     value = (conf->threshold <<
0628             TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
0629         ((conf->audio_channels - 1) <<
0630             TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
0631         ((conf->client_channels - 1) <<
0632             TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
0633         (conf->audio_bits <<
0634             TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
0635         (conf->client_bits <<
0636             TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
0637         (conf->expand <<
0638             TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
0639         (conf->stereo_conv <<
0640             TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
0641         (conf->replicate <<
0642             TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
0643         (conf->direction <<
0644             TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
0645         (conf->truncate <<
0646             TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
0647         (conf->mono_conv <<
0648             TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
0649 
0650     regmap_write(regmap, reg, value);
0651 }
0652 EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
0653 
0654 void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
0655                struct tegra30_ahub_cif_conf *conf)
0656 {
0657     unsigned int value;
0658 
0659     value = (conf->threshold <<
0660             TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
0661         ((conf->audio_channels - 1) <<
0662             TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
0663         ((conf->client_channels - 1) <<
0664             TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
0665         (conf->audio_bits <<
0666             TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
0667         (conf->client_bits <<
0668             TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
0669         (conf->expand <<
0670             TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
0671         (conf->stereo_conv <<
0672             TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
0673         (conf->replicate <<
0674             TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
0675         (conf->direction <<
0676             TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
0677         (conf->truncate <<
0678             TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
0679         (conf->mono_conv <<
0680             TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
0681 
0682     regmap_write(regmap, reg, value);
0683 }
0684 EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
0685 
0686 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
0687 MODULE_DESCRIPTION("Tegra30 AHUB driver");
0688 MODULE_LICENSE("GPL v2");
0689 MODULE_ALIAS("platform:" DRV_NAME);
0690 MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);