tegra30_ahub.c (18382B)
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);