diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
| -rw-r--r-- | arch/arm/mach-omap2/clock.c | 518 |
1 files changed, 510 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 961ac8f7e13..8b30759f8f9 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #undef DEBUG | 15 | #undef DEBUG |
| 16 | 16 | ||
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/export.h> | ||
| 18 | #include <linux/list.h> | 19 | #include <linux/list.h> |
| 19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
| 20 | #include <linux/err.h> | 21 | #include <linux/err.h> |
| @@ -25,7 +26,6 @@ | |||
| 25 | 26 | ||
| 26 | #include <asm/cpu.h> | 27 | #include <asm/cpu.h> |
| 27 | 28 | ||
| 28 | #include <plat/clock.h> | ||
| 29 | #include <plat/prcm.h> | 29 | #include <plat/prcm.h> |
| 30 | 30 | ||
| 31 | #include <trace/events/power.h> | 31 | #include <trace/events/power.h> |
| @@ -47,6 +47,10 @@ u16 cpu_mask; | |||
| 47 | */ | 47 | */ |
| 48 | static bool clkdm_control = true; | 48 | static bool clkdm_control = true; |
| 49 | 49 | ||
| 50 | static LIST_HEAD(clocks); | ||
| 51 | static DEFINE_MUTEX(clocks_mutex); | ||
| 52 | static DEFINE_SPINLOCK(clockfw_lock); | ||
| 53 | |||
| 50 | /* | 54 | /* |
| 51 | * OMAP2+ specific clock functions | 55 | * OMAP2+ specific clock functions |
| 52 | */ | 56 | */ |
| @@ -512,12 +516,510 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name, | |||
| 512 | 516 | ||
| 513 | /* Common data */ | 517 | /* Common data */ |
| 514 | 518 | ||
| 515 | struct clk_functions omap2_clk_functions = { | 519 | int clk_enable(struct clk *clk) |
| 516 | .clk_enable = omap2_clk_enable, | 520 | { |
| 517 | .clk_disable = omap2_clk_disable, | 521 | unsigned long flags; |
| 518 | .clk_round_rate = omap2_clk_round_rate, | 522 | int ret; |
| 519 | .clk_set_rate = omap2_clk_set_rate, | 523 | |
| 520 | .clk_set_parent = omap2_clk_set_parent, | 524 | if (clk == NULL || IS_ERR(clk)) |
| 521 | .clk_disable_unused = omap2_clk_disable_unused, | 525 | return -EINVAL; |
| 526 | |||
| 527 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 528 | ret = omap2_clk_enable(clk); | ||
| 529 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 530 | |||
| 531 | return ret; | ||
| 532 | } | ||
| 533 | EXPORT_SYMBOL(clk_enable); | ||
| 534 | |||
| 535 | void clk_disable(struct clk *clk) | ||
| 536 | { | ||
| 537 | unsigned long flags; | ||
| 538 | |||
| 539 | if (clk == NULL || IS_ERR(clk)) | ||
| 540 | return; | ||
| 541 | |||
| 542 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 543 | if (clk->usecount == 0) { | ||
| 544 | pr_err("Trying disable clock %s with 0 usecount\n", | ||
| 545 | clk->name); | ||
| 546 | WARN_ON(1); | ||
| 547 | goto out; | ||
| 548 | } | ||
| 549 | |||
| 550 | omap2_clk_disable(clk); | ||
| 551 | |||
| 552 | out: | ||
| 553 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 554 | } | ||
| 555 | EXPORT_SYMBOL(clk_disable); | ||
| 556 | |||
| 557 | unsigned long clk_get_rate(struct clk *clk) | ||
| 558 | { | ||
| 559 | unsigned long flags; | ||
| 560 | unsigned long ret; | ||
| 561 | |||
| 562 | if (clk == NULL || IS_ERR(clk)) | ||
| 563 | return 0; | ||
| 564 | |||
| 565 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 566 | ret = clk->rate; | ||
| 567 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 568 | |||
| 569 | return ret; | ||
| 570 | } | ||
| 571 | EXPORT_SYMBOL(clk_get_rate); | ||
| 572 | |||
| 573 | /* | ||
| 574 | * Optional clock functions defined in include/linux/clk.h | ||
| 575 | */ | ||
| 576 | |||
| 577 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
| 578 | { | ||
| 579 | unsigned long flags; | ||
| 580 | long ret; | ||
| 581 | |||
| 582 | if (clk == NULL || IS_ERR(clk)) | ||
| 583 | return 0; | ||
| 584 | |||
| 585 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 586 | ret = omap2_clk_round_rate(clk, rate); | ||
| 587 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 588 | |||
| 589 | return ret; | ||
| 590 | } | ||
| 591 | EXPORT_SYMBOL(clk_round_rate); | ||
| 592 | |||
| 593 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
| 594 | { | ||
| 595 | unsigned long flags; | ||
| 596 | int ret = -EINVAL; | ||
| 597 | |||
| 598 | if (clk == NULL || IS_ERR(clk)) | ||
| 599 | return ret; | ||
| 600 | |||
| 601 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 602 | ret = omap2_clk_set_rate(clk, rate); | ||
| 603 | if (ret == 0) | ||
| 604 | propagate_rate(clk); | ||
| 605 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 606 | |||
| 607 | return ret; | ||
| 608 | } | ||
| 609 | EXPORT_SYMBOL(clk_set_rate); | ||
| 610 | |||
| 611 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
| 612 | { | ||
| 613 | unsigned long flags; | ||
| 614 | int ret = -EINVAL; | ||
| 615 | |||
| 616 | if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) | ||
| 617 | return ret; | ||
| 618 | |||
| 619 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 620 | if (clk->usecount == 0) { | ||
| 621 | ret = omap2_clk_set_parent(clk, parent); | ||
| 622 | if (ret == 0) | ||
| 623 | propagate_rate(clk); | ||
| 624 | } else { | ||
| 625 | ret = -EBUSY; | ||
| 626 | } | ||
| 627 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 628 | |||
| 629 | return ret; | ||
| 630 | } | ||
| 631 | EXPORT_SYMBOL(clk_set_parent); | ||
| 632 | |||
| 633 | struct clk *clk_get_parent(struct clk *clk) | ||
| 634 | { | ||
| 635 | return clk->parent; | ||
| 636 | } | ||
| 637 | EXPORT_SYMBOL(clk_get_parent); | ||
| 638 | |||
| 639 | /* | ||
| 640 | * OMAP specific clock functions shared between omap1 and omap2 | ||
| 641 | */ | ||
| 642 | |||
| 643 | int __initdata mpurate; | ||
| 644 | |||
| 645 | /* | ||
| 646 | * By default we use the rate set by the bootloader. | ||
| 647 | * You can override this with mpurate= cmdline option. | ||
| 648 | */ | ||
| 649 | static int __init omap_clk_setup(char *str) | ||
| 650 | { | ||
| 651 | get_option(&str, &mpurate); | ||
| 652 | |||
| 653 | if (!mpurate) | ||
| 654 | return 1; | ||
| 655 | |||
| 656 | if (mpurate < 1000) | ||
| 657 | mpurate *= 1000000; | ||
| 658 | |||
| 659 | return 1; | ||
| 660 | } | ||
| 661 | __setup("mpurate=", omap_clk_setup); | ||
| 662 | |||
| 663 | /* Used for clocks that always have same value as the parent clock */ | ||
| 664 | unsigned long followparent_recalc(struct clk *clk) | ||
| 665 | { | ||
| 666 | return clk->parent->rate; | ||
| 667 | } | ||
| 668 | |||
| 669 | /* | ||
| 670 | * Used for clocks that have the same value as the parent clock, | ||
| 671 | * divided by some factor | ||
| 672 | */ | ||
| 673 | unsigned long omap_fixed_divisor_recalc(struct clk *clk) | ||
| 674 | { | ||
| 675 | WARN_ON(!clk->fixed_div); | ||
| 676 | |||
| 677 | return clk->parent->rate / clk->fixed_div; | ||
| 678 | } | ||
| 679 | |||
| 680 | void clk_reparent(struct clk *child, struct clk *parent) | ||
| 681 | { | ||
| 682 | list_del_init(&child->sibling); | ||
| 683 | if (parent) | ||
| 684 | list_add(&child->sibling, &parent->children); | ||
| 685 | child->parent = parent; | ||
| 686 | |||
| 687 | /* now do the debugfs renaming to reattach the child | ||
| 688 | to the proper parent */ | ||
| 689 | } | ||
| 690 | |||
| 691 | /* Propagate rate to children */ | ||
| 692 | void propagate_rate(struct clk *tclk) | ||
| 693 | { | ||
| 694 | struct clk *clkp; | ||
| 695 | |||
| 696 | list_for_each_entry(clkp, &tclk->children, sibling) { | ||
| 697 | if (clkp->recalc) | ||
| 698 | clkp->rate = clkp->recalc(clkp); | ||
| 699 | propagate_rate(clkp); | ||
| 700 | } | ||
| 701 | } | ||
| 702 | |||
| 703 | static LIST_HEAD(root_clks); | ||
| 704 | |||
| 705 | /** | ||
| 706 | * recalculate_root_clocks - recalculate and propagate all root clocks | ||
| 707 | * | ||
| 708 | * Recalculates all root clocks (clocks with no parent), which if the | ||
| 709 | * clock's .recalc is set correctly, should also propagate their rates. | ||
| 710 | * Called at init. | ||
| 711 | */ | ||
| 712 | void recalculate_root_clocks(void) | ||
| 713 | { | ||
| 714 | struct clk *clkp; | ||
| 715 | |||
| 716 | list_for_each_entry(clkp, &root_clks, sibling) { | ||
| 717 | if (clkp->recalc) | ||
| 718 | clkp->rate = clkp->recalc(clkp); | ||
| 719 | propagate_rate(clkp); | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | /** | ||
| 724 | * clk_preinit - initialize any fields in the struct clk before clk init | ||
| 725 | * @clk: struct clk * to initialize | ||
| 726 | * | ||
| 727 | * Initialize any struct clk fields needed before normal clk initialization | ||
| 728 | * can run. No return value. | ||
| 729 | */ | ||
| 730 | void clk_preinit(struct clk *clk) | ||
| 731 | { | ||
| 732 | INIT_LIST_HEAD(&clk->children); | ||
| 733 | } | ||
| 734 | |||
| 735 | int clk_register(struct clk *clk) | ||
| 736 | { | ||
| 737 | if (clk == NULL || IS_ERR(clk)) | ||
| 738 | return -EINVAL; | ||
| 739 | |||
| 740 | /* | ||
| 741 | * trap out already registered clocks | ||
| 742 | */ | ||
| 743 | if (clk->node.next || clk->node.prev) | ||
| 744 | return 0; | ||
| 745 | |||
| 746 | mutex_lock(&clocks_mutex); | ||
| 747 | if (clk->parent) | ||
| 748 | list_add(&clk->sibling, &clk->parent->children); | ||
| 749 | else | ||
| 750 | list_add(&clk->sibling, &root_clks); | ||
| 751 | |||
| 752 | list_add(&clk->node, &clocks); | ||
| 753 | if (clk->init) | ||
| 754 | clk->init(clk); | ||
| 755 | mutex_unlock(&clocks_mutex); | ||
| 756 | |||
| 757 | return 0; | ||
| 758 | } | ||
| 759 | EXPORT_SYMBOL(clk_register); | ||
| 760 | |||
| 761 | void clk_unregister(struct clk *clk) | ||
| 762 | { | ||
| 763 | if (clk == NULL || IS_ERR(clk)) | ||
| 764 | return; | ||
| 765 | |||
| 766 | mutex_lock(&clocks_mutex); | ||
| 767 | list_del(&clk->sibling); | ||
| 768 | list_del(&clk->node); | ||
| 769 | mutex_unlock(&clocks_mutex); | ||
| 770 | } | ||
| 771 | EXPORT_SYMBOL(clk_unregister); | ||
| 772 | |||
| 773 | void clk_enable_init_clocks(void) | ||
| 774 | { | ||
| 775 | struct clk *clkp; | ||
| 776 | |||
| 777 | list_for_each_entry(clkp, &clocks, node) | ||
| 778 | if (clkp->flags & ENABLE_ON_INIT) | ||
| 779 | clk_enable(clkp); | ||
| 780 | } | ||
| 781 | |||
| 782 | /** | ||
| 783 | * omap_clk_get_by_name - locate OMAP struct clk by its name | ||
| 784 | * @name: name of the struct clk to locate | ||
| 785 | * | ||
| 786 | * Locate an OMAP struct clk by its name. Assumes that struct clk | ||
| 787 | * names are unique. Returns NULL if not found or a pointer to the | ||
| 788 | * struct clk if found. | ||
| 789 | */ | ||
| 790 | struct clk *omap_clk_get_by_name(const char *name) | ||
| 791 | { | ||
| 792 | struct clk *c; | ||
| 793 | struct clk *ret = NULL; | ||
| 794 | |||
| 795 | mutex_lock(&clocks_mutex); | ||
| 796 | |||
| 797 | list_for_each_entry(c, &clocks, node) { | ||
| 798 | if (!strcmp(c->name, name)) { | ||
| 799 | ret = c; | ||
| 800 | break; | ||
| 801 | } | ||
| 802 | } | ||
| 803 | |||
| 804 | mutex_unlock(&clocks_mutex); | ||
| 805 | |||
| 806 | return ret; | ||
| 807 | } | ||
| 808 | |||
| 809 | int omap_clk_enable_autoidle_all(void) | ||
| 810 | { | ||
| 811 | struct clk *c; | ||
| 812 | unsigned long flags; | ||
| 813 | |||
| 814 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 815 | |||
| 816 | list_for_each_entry(c, &clocks, node) | ||
| 817 | if (c->ops->allow_idle) | ||
| 818 | c->ops->allow_idle(c); | ||
| 819 | |||
| 820 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 821 | |||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | |||
| 825 | int omap_clk_disable_autoidle_all(void) | ||
| 826 | { | ||
| 827 | struct clk *c; | ||
| 828 | unsigned long flags; | ||
| 829 | |||
| 830 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 831 | |||
| 832 | list_for_each_entry(c, &clocks, node) | ||
| 833 | if (c->ops->deny_idle) | ||
| 834 | c->ops->deny_idle(c); | ||
| 835 | |||
| 836 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 837 | |||
| 838 | return 0; | ||
| 839 | } | ||
| 840 | |||
| 841 | /* | ||
| 842 | * Low level helpers | ||
| 843 | */ | ||
| 844 | static int clkll_enable_null(struct clk *clk) | ||
| 845 | { | ||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | static void clkll_disable_null(struct clk *clk) | ||
| 850 | { | ||
| 851 | } | ||
| 852 | |||
| 853 | const struct clkops clkops_null = { | ||
| 854 | .enable = clkll_enable_null, | ||
| 855 | .disable = clkll_disable_null, | ||
| 856 | }; | ||
| 857 | |||
| 858 | /* | ||
| 859 | * Dummy clock | ||
| 860 | * | ||
| 861 | * Used for clock aliases that are needed on some OMAPs, but not others | ||
| 862 | */ | ||
| 863 | struct clk dummy_ck = { | ||
| 864 | .name = "dummy", | ||
| 865 | .ops = &clkops_null, | ||
| 866 | }; | ||
| 867 | |||
| 868 | /* | ||
| 869 | * | ||
| 870 | */ | ||
| 871 | |||
| 872 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
| 873 | /* | ||
| 874 | * Disable any unused clocks left on by the bootloader | ||
| 875 | */ | ||
| 876 | static int __init clk_disable_unused(void) | ||
| 877 | { | ||
| 878 | struct clk *ck; | ||
| 879 | unsigned long flags; | ||
| 880 | |||
| 881 | pr_info("clock: disabling unused clocks to save power\n"); | ||
| 882 | |||
| 883 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 884 | list_for_each_entry(ck, &clocks, node) { | ||
| 885 | if (ck->ops == &clkops_null) | ||
| 886 | continue; | ||
| 887 | |||
| 888 | if (ck->usecount > 0 || !ck->enable_reg) | ||
| 889 | continue; | ||
| 890 | |||
| 891 | omap2_clk_disable_unused(ck); | ||
| 892 | } | ||
| 893 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 894 | |||
| 895 | return 0; | ||
| 896 | } | ||
| 897 | late_initcall(clk_disable_unused); | ||
| 898 | late_initcall(omap_clk_enable_autoidle_all); | ||
| 899 | #endif | ||
| 900 | |||
| 901 | #if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) | ||
| 902 | /* | ||
| 903 | * debugfs support to trace clock tree hierarchy and attributes | ||
| 904 | */ | ||
| 905 | |||
| 906 | #include <linux/debugfs.h> | ||
| 907 | #include <linux/seq_file.h> | ||
| 908 | |||
| 909 | static struct dentry *clk_debugfs_root; | ||
| 910 | |||
| 911 | static int clk_dbg_show_summary(struct seq_file *s, void *unused) | ||
| 912 | { | ||
| 913 | struct clk *c; | ||
| 914 | struct clk *pa; | ||
| 915 | |||
| 916 | mutex_lock(&clocks_mutex); | ||
| 917 | seq_printf(s, "%-30s %-30s %-10s %s\n", | ||
| 918 | "clock-name", "parent-name", "rate", "use-count"); | ||
| 919 | |||
| 920 | list_for_each_entry(c, &clocks, node) { | ||
| 921 | pa = c->parent; | ||
| 922 | seq_printf(s, "%-30s %-30s %-10lu %d\n", | ||
| 923 | c->name, pa ? pa->name : "none", c->rate, | ||
| 924 | c->usecount); | ||
| 925 | } | ||
| 926 | mutex_unlock(&clocks_mutex); | ||
| 927 | |||
| 928 | return 0; | ||
| 929 | } | ||
| 930 | |||
| 931 | static int clk_dbg_open(struct inode *inode, struct file *file) | ||
| 932 | { | ||
| 933 | return single_open(file, clk_dbg_show_summary, inode->i_private); | ||
| 934 | } | ||
| 935 | |||
| 936 | static const struct file_operations debug_clock_fops = { | ||
| 937 | .open = clk_dbg_open, | ||
| 938 | .read = seq_read, | ||
| 939 | .llseek = seq_lseek, | ||
| 940 | .release = single_release, | ||
| 522 | }; | 941 | }; |
| 523 | 942 | ||
| 943 | static int clk_debugfs_register_one(struct clk *c) | ||
| 944 | { | ||
| 945 | int err; | ||
| 946 | struct dentry *d; | ||
| 947 | struct clk *pa = c->parent; | ||
| 948 | |||
| 949 | d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root); | ||
| 950 | if (!d) | ||
| 951 | return -ENOMEM; | ||
| 952 | c->dent = d; | ||
| 953 | |||
| 954 | d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount); | ||
| 955 | if (!d) { | ||
| 956 | err = -ENOMEM; | ||
| 957 | goto err_out; | ||
| 958 | } | ||
| 959 | d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); | ||
| 960 | if (!d) { | ||
| 961 | err = -ENOMEM; | ||
| 962 | goto err_out; | ||
| 963 | } | ||
| 964 | d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); | ||
| 965 | if (!d) { | ||
| 966 | err = -ENOMEM; | ||
| 967 | goto err_out; | ||
| 968 | } | ||
| 969 | return 0; | ||
| 970 | |||
| 971 | err_out: | ||
| 972 | debugfs_remove_recursive(c->dent); | ||
| 973 | return err; | ||
| 974 | } | ||
| 975 | |||
| 976 | static int clk_debugfs_register(struct clk *c) | ||
| 977 | { | ||
| 978 | int err; | ||
| 979 | struct clk *pa = c->parent; | ||
| 980 | |||
| 981 | if (pa && !pa->dent) { | ||
| 982 | err = clk_debugfs_register(pa); | ||
| 983 | if (err) | ||
| 984 | return err; | ||
| 985 | } | ||
| 986 | |||
| 987 | if (!c->dent) { | ||
| 988 | err = clk_debugfs_register_one(c); | ||
| 989 | if (err) | ||
| 990 | return err; | ||
| 991 | } | ||
| 992 | return 0; | ||
| 993 | } | ||
| 994 | |||
| 995 | static int __init clk_debugfs_init(void) | ||
| 996 | { | ||
| 997 | struct clk *c; | ||
| 998 | struct dentry *d; | ||
| 999 | int err; | ||
| 1000 | |||
| 1001 | d = debugfs_create_dir("clock", NULL); | ||
| 1002 | if (!d) | ||
| 1003 | return -ENOMEM; | ||
| 1004 | clk_debugfs_root = d; | ||
| 1005 | |||
| 1006 | list_for_each_entry(c, &clocks, node) { | ||
| 1007 | err = clk_debugfs_register(c); | ||
| 1008 | if (err) | ||
| 1009 | goto err_out; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | d = debugfs_create_file("summary", S_IRUGO, | ||
| 1013 | d, NULL, &debug_clock_fops); | ||
| 1014 | if (!d) | ||
| 1015 | return -ENOMEM; | ||
| 1016 | |||
| 1017 | return 0; | ||
| 1018 | err_out: | ||
| 1019 | debugfs_remove_recursive(clk_debugfs_root); | ||
| 1020 | return err; | ||
| 1021 | } | ||
| 1022 | late_initcall(clk_debugfs_init); | ||
| 1023 | |||
| 1024 | #endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */ | ||
| 1025 | |||
