689 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * tegra30_ahub.c - Tegra30 AHUB driver4 *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 data55 * is read from or sent to memory. However, that's not something the rest of56 * the driver supports right now, so we'll just treat the two clocks as one57 * for now.58 *59 * These functions should not be a plain ref-count. Instead, each active stream60 * contributes some requirement to the minimum clock rate, so starting or61 * 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 void tegra30_ahub_remove(struct platform_device *pdev)596{597 pm_runtime_disable(&pdev->dev);598 599 ahub = NULL;600}601 602static const struct dev_pm_ops tegra30_ahub_pm_ops = {603 SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,604 tegra30_ahub_runtime_resume, NULL)605 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,606 pm_runtime_force_resume)607};608 609static struct platform_driver tegra30_ahub_driver = {610 .probe = tegra30_ahub_probe,611 .remove = tegra30_ahub_remove,612 .driver = {613 .name = DRV_NAME,614 .of_match_table = tegra30_ahub_of_match,615 .pm = &tegra30_ahub_pm_ops,616 },617};618module_platform_driver(tegra30_ahub_driver);619 620void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,621 struct tegra30_ahub_cif_conf *conf)622{623 unsigned int value;624 625 value = (conf->threshold <<626 TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |627 ((conf->audio_channels - 1) <<628 TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |629 ((conf->client_channels - 1) <<630 TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |631 (conf->audio_bits <<632 TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |633 (conf->client_bits <<634 TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |635 (conf->expand <<636 TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |637 (conf->stereo_conv <<638 TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |639 (conf->replicate <<640 TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |641 (conf->direction <<642 TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |643 (conf->truncate <<644 TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |645 (conf->mono_conv <<646 TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);647 648 regmap_write(regmap, reg, value);649}650EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);651 652void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,653 struct tegra30_ahub_cif_conf *conf)654{655 unsigned int value;656 657 value = (conf->threshold <<658 TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |659 ((conf->audio_channels - 1) <<660 TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |661 ((conf->client_channels - 1) <<662 TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |663 (conf->audio_bits <<664 TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |665 (conf->client_bits <<666 TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |667 (conf->expand <<668 TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |669 (conf->stereo_conv <<670 TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |671 (conf->replicate <<672 TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |673 (conf->direction <<674 TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |675 (conf->truncate <<676 TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |677 (conf->mono_conv <<678 TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);679 680 regmap_write(regmap, reg, value);681}682EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);683 684MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");685MODULE_DESCRIPTION("Tegra30 AHUB driver");686MODULE_LICENSE("GPL v2");687MODULE_ALIAS("platform:" DRV_NAME);688MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);689