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 23 static struct tegra30_ahub *ahub; 24 25 static inline void tegra30_apbif_write(u32 reg, u32 val) 26 { 27 regmap_write(ahub->regmap_apbif, reg, val); 28 } 29 30 static 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 38 static inline void tegra30_audio_write(u32 reg, u32 val) 39 { 40 regmap_write(ahub->regmap_ahub, reg, val); 41 } 42 43 static __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 */ 64 static __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 97 disable_clocks: 98 clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks); 99 100 return ret; 101 } 102 103 int 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 } 155 EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo); 156 157 int 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 } 174 EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo); 175 176 int 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 } 193 EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo); 194 195 int 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 } 203 EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo); 204 205 int 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 } 257 EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo); 258 259 int 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 } 276 EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo); 277 278 int 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 } 295 EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo); 296 297 int 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 } 305 EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo); 306 307 int 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 } 323 EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source); 324 325 int 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 } 340 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); 341 342 static 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 375 static 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 417 static 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 449 static 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 459 static 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 472 static 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 480 static 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 491 static struct tegra30_ahub_soc_data soc_data_tegra30 = { 492 .num_resets = 11, 493 .set_audio_cif = tegra30_ahub_set_cif, 494 }; 495 496 static struct tegra30_ahub_soc_data soc_data_tegra114 = { 497 .num_resets = 13, 498 .set_audio_cif = tegra30_ahub_set_cif, 499 }; 500 501 static struct tegra30_ahub_soc_data soc_data_tegra124 = { 502 .num_resets = 21, 503 .set_audio_cif = tegra124_ahub_set_cif, 504 }; 505 506 static 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 513 static 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 res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 554 regs_apbif = devm_ioremap_resource(&pdev->dev, res0); 555 if (IS_ERR(regs_apbif)) { 556 ret = PTR_ERR(regs_apbif); 557 goto err_unset_ahub; 558 } 559 560 ahub->apbif_addr = res0->start; 561 562 ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif, 563 &tegra30_ahub_apbif_regmap_config); 564 if (IS_ERR(ahub->regmap_apbif)) { 565 dev_err(&pdev->dev, "apbif regmap init failed\n"); 566 ret = PTR_ERR(ahub->regmap_apbif); 567 goto err_unset_ahub; 568 } 569 regcache_cache_only(ahub->regmap_apbif, true); 570 571 regs_ahub = devm_platform_ioremap_resource(pdev, 1); 572 if (IS_ERR(regs_ahub)) { 573 ret = PTR_ERR(regs_ahub); 574 goto err_unset_ahub; 575 } 576 577 ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, 578 &tegra30_ahub_ahub_regmap_config); 579 if (IS_ERR(ahub->regmap_ahub)) { 580 dev_err(&pdev->dev, "ahub regmap init failed\n"); 581 ret = PTR_ERR(ahub->regmap_ahub); 582 goto err_unset_ahub; 583 } 584 regcache_cache_only(ahub->regmap_ahub, true); 585 586 pm_runtime_enable(&pdev->dev); 587 588 of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 589 590 return 0; 591 592 err_unset_ahub: 593 ahub = NULL; 594 595 return ret; 596 } 597 598 static int tegra30_ahub_remove(struct platform_device *pdev) 599 { 600 pm_runtime_disable(&pdev->dev); 601 602 ahub = NULL; 603 604 return 0; 605 } 606 607 static const struct dev_pm_ops tegra30_ahub_pm_ops = { 608 SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, 609 tegra30_ahub_runtime_resume, NULL) 610 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 611 pm_runtime_force_resume) 612 }; 613 614 static struct platform_driver tegra30_ahub_driver = { 615 .probe = tegra30_ahub_probe, 616 .remove = tegra30_ahub_remove, 617 .driver = { 618 .name = DRV_NAME, 619 .of_match_table = tegra30_ahub_of_match, 620 .pm = &tegra30_ahub_pm_ops, 621 }, 622 }; 623 module_platform_driver(tegra30_ahub_driver); 624 625 void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg, 626 struct tegra30_ahub_cif_conf *conf) 627 { 628 unsigned int value; 629 630 value = (conf->threshold << 631 TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | 632 ((conf->audio_channels - 1) << 633 TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | 634 ((conf->client_channels - 1) << 635 TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | 636 (conf->audio_bits << 637 TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | 638 (conf->client_bits << 639 TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | 640 (conf->expand << 641 TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | 642 (conf->stereo_conv << 643 TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | 644 (conf->replicate << 645 TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | 646 (conf->direction << 647 TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | 648 (conf->truncate << 649 TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | 650 (conf->mono_conv << 651 TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); 652 653 regmap_write(regmap, reg, value); 654 } 655 EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif); 656 657 void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, 658 struct tegra30_ahub_cif_conf *conf) 659 { 660 unsigned int value; 661 662 value = (conf->threshold << 663 TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | 664 ((conf->audio_channels - 1) << 665 TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | 666 ((conf->client_channels - 1) << 667 TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | 668 (conf->audio_bits << 669 TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | 670 (conf->client_bits << 671 TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | 672 (conf->expand << 673 TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | 674 (conf->stereo_conv << 675 TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | 676 (conf->replicate << 677 TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | 678 (conf->direction << 679 TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | 680 (conf->truncate << 681 TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | 682 (conf->mono_conv << 683 TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); 684 685 regmap_write(regmap, reg, value); 686 } 687 EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif); 688 689 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 690 MODULE_DESCRIPTION("Tegra30 AHUB driver"); 691 MODULE_LICENSE("GPL v2"); 692 MODULE_ALIAS("platform:" DRV_NAME); 693 MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match); 694