|
6 | 6 | */
|
7 | 7 |
|
8 | 8 | #include <linux/clk.h>
|
| 9 | +#include <linux/clk/tegra.h> |
9 | 10 | #include <linux/completion.h>
|
10 | 11 | #include <linux/err.h>
|
11 | 12 | #include <linux/interrupt.h>
|
@@ -421,6 +422,44 @@ static int emc_setup_hw(struct tegra_emc *emc)
|
421 | 422 | return 0;
|
422 | 423 | }
|
423 | 424 |
|
| 425 | +static long emc_round_rate(unsigned long rate, |
| 426 | + unsigned long min_rate, |
| 427 | + unsigned long max_rate, |
| 428 | + void *arg) |
| 429 | +{ |
| 430 | + struct emc_timing *timing = NULL; |
| 431 | + struct tegra_emc *emc = arg; |
| 432 | + unsigned int i; |
| 433 | + |
| 434 | + min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate); |
| 435 | + |
| 436 | + for (i = 0; i < emc->num_timings; i++) { |
| 437 | + if (emc->timings[i].rate < rate && i != emc->num_timings - 1) |
| 438 | + continue; |
| 439 | + |
| 440 | + if (emc->timings[i].rate > max_rate) { |
| 441 | + i = max(i, 1u) - 1; |
| 442 | + |
| 443 | + if (emc->timings[i].rate < min_rate) |
| 444 | + break; |
| 445 | + } |
| 446 | + |
| 447 | + if (emc->timings[i].rate < min_rate) |
| 448 | + continue; |
| 449 | + |
| 450 | + timing = &emc->timings[i]; |
| 451 | + break; |
| 452 | + } |
| 453 | + |
| 454 | + if (!timing) { |
| 455 | + dev_err(emc->dev, "no timing for rate %lu min %lu max %lu\n", |
| 456 | + rate, min_rate, max_rate); |
| 457 | + return -EINVAL; |
| 458 | + } |
| 459 | + |
| 460 | + return timing->rate; |
| 461 | +} |
| 462 | + |
424 | 463 | static int tegra_emc_probe(struct platform_device *pdev)
|
425 | 464 | {
|
426 | 465 | struct device_node *np;
|
@@ -477,21 +516,28 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
477 | 516 | return err;
|
478 | 517 | }
|
479 | 518 |
|
| 519 | + tegra20_clk_set_emc_round_callback(emc_round_rate, emc); |
| 520 | + |
480 | 521 | emc->clk = devm_clk_get(&pdev->dev, "emc");
|
481 | 522 | if (IS_ERR(emc->clk)) {
|
482 | 523 | err = PTR_ERR(emc->clk);
|
483 | 524 | dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
|
484 |
| - return err; |
| 525 | + goto unset_cb; |
485 | 526 | }
|
486 | 527 |
|
487 | 528 | err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
488 | 529 | if (err) {
|
489 | 530 | dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
|
490 | 531 | err);
|
491 |
| - return err; |
| 532 | + goto unset_cb; |
492 | 533 | }
|
493 | 534 |
|
494 | 535 | return 0;
|
| 536 | + |
| 537 | +unset_cb: |
| 538 | + tegra20_clk_set_emc_round_callback(NULL, NULL); |
| 539 | + |
| 540 | + return err; |
495 | 541 | }
|
496 | 542 |
|
497 | 543 | static const struct of_device_id tegra_emc_of_match[] = {
|
|
0 commit comments