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