diff options
author | Heiko Stuebner <heiko@sntech.de> | 2014-02-24 19:50:43 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2014-04-14 13:11:36 -0400 |
commit | ea5d6a8d3ee606086118d3b4d4b3a49693e92960 (patch) | |
tree | 7de9a8a5d1a1b6b771271f9519396395340f267b | |
parent | 42637c59f36198a58069f94676007c62477321b7 (diff) |
clk: samsung: add plls used by the early s3c24xx cpus
The manuals do not give them explicit names like in later socs, so more
generic names with a s3c2410-prefix were used for them.
As it was common to do so in the previous implementation, functionality
to change the pll rate is already included.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Mike Turquette <mturquette@linaro.org>
Acked-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r-- | drivers/clk/samsung/clk-pll.c | 182 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-pll.h | 3 |
2 files changed, 185 insertions, 0 deletions
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 8c9c015a4538..7fb0a28e65d5 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/hrtimer.h> | 13 | #include <linux/hrtimer.h> |
14 | #include <linux/delay.h> | ||
14 | #include "clk.h" | 15 | #include "clk.h" |
15 | #include "clk-pll.h" | 16 | #include "clk-pll.h" |
16 | 17 | ||
@@ -701,6 +702,169 @@ static const struct clk_ops samsung_pll6553_clk_ops = { | |||
701 | }; | 702 | }; |
702 | 703 | ||
703 | /* | 704 | /* |
705 | * PLL Clock Type of S3C24XX before S3C2443 | ||
706 | */ | ||
707 | |||
708 | #define PLLS3C2410_MDIV_MASK (0xff) | ||
709 | #define PLLS3C2410_PDIV_MASK (0x1f) | ||
710 | #define PLLS3C2410_SDIV_MASK (0x3) | ||
711 | #define PLLS3C2410_MDIV_SHIFT (12) | ||
712 | #define PLLS3C2410_PDIV_SHIFT (4) | ||
713 | #define PLLS3C2410_SDIV_SHIFT (0) | ||
714 | |||
715 | #define PLLS3C2410_ENABLE_REG_OFFSET 0x10 | ||
716 | |||
717 | static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw, | ||
718 | unsigned long parent_rate) | ||
719 | { | ||
720 | struct samsung_clk_pll *pll = to_clk_pll(hw); | ||
721 | u32 pll_con, mdiv, pdiv, sdiv; | ||
722 | u64 fvco = parent_rate; | ||
723 | |||
724 | pll_con = __raw_readl(pll->con_reg); | ||
725 | mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; | ||
726 | pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; | ||
727 | sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; | ||
728 | |||
729 | fvco *= (mdiv + 8); | ||
730 | do_div(fvco, (pdiv + 2) << sdiv); | ||
731 | |||
732 | return (unsigned int)fvco; | ||
733 | } | ||
734 | |||
735 | static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw, | ||
736 | unsigned long parent_rate) | ||
737 | { | ||
738 | struct samsung_clk_pll *pll = to_clk_pll(hw); | ||
739 | u32 pll_con, mdiv, pdiv, sdiv; | ||
740 | u64 fvco = parent_rate; | ||
741 | |||
742 | pll_con = __raw_readl(pll->con_reg); | ||
743 | mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; | ||
744 | pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; | ||
745 | sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; | ||
746 | |||
747 | fvco *= (2 * (mdiv + 8)); | ||
748 | do_div(fvco, (pdiv + 2) << sdiv); | ||
749 | |||
750 | return (unsigned int)fvco; | ||
751 | } | ||
752 | |||
753 | static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate, | ||
754 | unsigned long prate) | ||
755 | { | ||
756 | struct samsung_clk_pll *pll = to_clk_pll(hw); | ||
757 | const struct samsung_pll_rate_table *rate; | ||
758 | u32 tmp; | ||
759 | |||
760 | /* Get required rate settings from table */ | ||
761 | rate = samsung_get_pll_settings(pll, drate); | ||
762 | if (!rate) { | ||
763 | pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, | ||
764 | drate, __clk_get_name(hw->clk)); | ||
765 | return -EINVAL; | ||
766 | } | ||
767 | |||
768 | tmp = __raw_readl(pll->con_reg); | ||
769 | |||
770 | /* Change PLL PMS values */ | ||
771 | tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) | | ||
772 | (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) | | ||
773 | (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT)); | ||
774 | tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) | | ||
775 | (rate->pdiv << PLLS3C2410_PDIV_SHIFT) | | ||
776 | (rate->sdiv << PLLS3C2410_SDIV_SHIFT); | ||
777 | __raw_writel(tmp, pll->con_reg); | ||
778 | |||
779 | /* Time to settle according to the manual */ | ||
780 | udelay(300); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable) | ||
786 | { | ||
787 | struct samsung_clk_pll *pll = to_clk_pll(hw); | ||
788 | u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); | ||
789 | u32 pll_en_orig = pll_en; | ||
790 | |||
791 | if (enable) | ||
792 | pll_en &= ~BIT(bit); | ||
793 | else | ||
794 | pll_en |= BIT(bit); | ||
795 | |||
796 | __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); | ||
797 | |||
798 | /* if we started the UPLL, then allow to settle */ | ||
799 | if (enable && (pll_en_orig & BIT(bit))) | ||
800 | udelay(300); | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int samsung_s3c2410_mpll_enable(struct clk_hw *hw) | ||
806 | { | ||
807 | return samsung_s3c2410_pll_enable(hw, 5, true); | ||
808 | } | ||
809 | |||
810 | static void samsung_s3c2410_mpll_disable(struct clk_hw *hw) | ||
811 | { | ||
812 | samsung_s3c2410_pll_enable(hw, 5, false); | ||
813 | } | ||
814 | |||
815 | static int samsung_s3c2410_upll_enable(struct clk_hw *hw) | ||
816 | { | ||
817 | return samsung_s3c2410_pll_enable(hw, 7, true); | ||
818 | } | ||
819 | |||
820 | static void samsung_s3c2410_upll_disable(struct clk_hw *hw) | ||
821 | { | ||
822 | samsung_s3c2410_pll_enable(hw, 7, false); | ||
823 | } | ||
824 | |||
825 | static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = { | ||
826 | .recalc_rate = samsung_s3c2410_pll_recalc_rate, | ||
827 | .enable = samsung_s3c2410_mpll_enable, | ||
828 | .disable = samsung_s3c2410_mpll_disable, | ||
829 | }; | ||
830 | |||
831 | static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = { | ||
832 | .recalc_rate = samsung_s3c2410_pll_recalc_rate, | ||
833 | .enable = samsung_s3c2410_upll_enable, | ||
834 | .disable = samsung_s3c2410_upll_disable, | ||
835 | }; | ||
836 | |||
837 | static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = { | ||
838 | .recalc_rate = samsung_s3c2440_mpll_recalc_rate, | ||
839 | .enable = samsung_s3c2410_mpll_enable, | ||
840 | .disable = samsung_s3c2410_mpll_disable, | ||
841 | }; | ||
842 | |||
843 | static const struct clk_ops samsung_s3c2410_mpll_clk_ops = { | ||
844 | .recalc_rate = samsung_s3c2410_pll_recalc_rate, | ||
845 | .enable = samsung_s3c2410_mpll_enable, | ||
846 | .disable = samsung_s3c2410_mpll_disable, | ||
847 | .round_rate = samsung_pll_round_rate, | ||
848 | .set_rate = samsung_s3c2410_pll_set_rate, | ||
849 | }; | ||
850 | |||
851 | static const struct clk_ops samsung_s3c2410_upll_clk_ops = { | ||
852 | .recalc_rate = samsung_s3c2410_pll_recalc_rate, | ||
853 | .enable = samsung_s3c2410_upll_enable, | ||
854 | .disable = samsung_s3c2410_upll_disable, | ||
855 | .round_rate = samsung_pll_round_rate, | ||
856 | .set_rate = samsung_s3c2410_pll_set_rate, | ||
857 | }; | ||
858 | |||
859 | static const struct clk_ops samsung_s3c2440_mpll_clk_ops = { | ||
860 | .recalc_rate = samsung_s3c2440_mpll_recalc_rate, | ||
861 | .enable = samsung_s3c2410_mpll_enable, | ||
862 | .disable = samsung_s3c2410_mpll_disable, | ||
863 | .round_rate = samsung_pll_round_rate, | ||
864 | .set_rate = samsung_s3c2410_pll_set_rate, | ||
865 | }; | ||
866 | |||
867 | /* | ||
704 | * PLL2550x Clock Type | 868 | * PLL2550x Clock Type |
705 | */ | 869 | */ |
706 | 870 | ||
@@ -866,6 +1030,24 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, | |||
866 | else | 1030 | else |
867 | init.ops = &samsung_pll46xx_clk_ops; | 1031 | init.ops = &samsung_pll46xx_clk_ops; |
868 | break; | 1032 | break; |
1033 | case pll_s3c2410_mpll: | ||
1034 | if (!pll->rate_table) | ||
1035 | init.ops = &samsung_s3c2410_mpll_clk_min_ops; | ||
1036 | else | ||
1037 | init.ops = &samsung_s3c2410_mpll_clk_ops; | ||
1038 | break; | ||
1039 | case pll_s3c2410_upll: | ||
1040 | if (!pll->rate_table) | ||
1041 | init.ops = &samsung_s3c2410_upll_clk_min_ops; | ||
1042 | else | ||
1043 | init.ops = &samsung_s3c2410_upll_clk_ops; | ||
1044 | break; | ||
1045 | case pll_s3c2440_mpll: | ||
1046 | if (!pll->rate_table) | ||
1047 | init.ops = &samsung_s3c2440_mpll_clk_min_ops; | ||
1048 | else | ||
1049 | init.ops = &samsung_s3c2440_mpll_clk_ops; | ||
1050 | break; | ||
869 | default: | 1051 | default: |
870 | pr_warn("%s: Unknown pll type for pll clk %s\n", | 1052 | pr_warn("%s: Unknown pll type for pll clk %s\n", |
871 | __func__, pll_clk->name); | 1053 | __func__, pll_clk->name); |
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 5b64bdbb0906..6428bcc6df6f 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h | |||
@@ -28,6 +28,9 @@ enum samsung_pll_type { | |||
28 | pll_6552, | 28 | pll_6552, |
29 | pll_6552_s3c2416, | 29 | pll_6552_s3c2416, |
30 | pll_6553, | 30 | pll_6553, |
31 | pll_s3c2410_mpll, | ||
32 | pll_s3c2410_upll, | ||
33 | pll_s3c2440_mpll, | ||
31 | }; | 34 | }; |
32 | 35 | ||
33 | #define PLL_35XX_RATE(_rate, _m, _p, _s) \ | 36 | #define PLL_35XX_RATE(_rate, _m, _p, _s) \ |