Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Heiko Stuebner and committed by
Kukjin Kim
ea5d6a8d 42637c59

+185
+182
drivers/clk/samsung/clk-pll.c
··· 11 11 12 12 #include <linux/errno.h> 13 13 #include <linux/hrtimer.h> 14 + #include <linux/delay.h> 14 15 #include "clk.h" 15 16 #include "clk-pll.h" 16 17 ··· 702 701 }; 703 702 704 703 /* 704 + * PLL Clock Type of S3C24XX before S3C2443 705 + */ 706 + 707 + #define PLLS3C2410_MDIV_MASK (0xff) 708 + #define PLLS3C2410_PDIV_MASK (0x1f) 709 + #define PLLS3C2410_SDIV_MASK (0x3) 710 + #define PLLS3C2410_MDIV_SHIFT (12) 711 + #define PLLS3C2410_PDIV_SHIFT (4) 712 + #define PLLS3C2410_SDIV_SHIFT (0) 713 + 714 + #define PLLS3C2410_ENABLE_REG_OFFSET 0x10 715 + 716 + static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw, 717 + unsigned long parent_rate) 718 + { 719 + struct samsung_clk_pll *pll = to_clk_pll(hw); 720 + u32 pll_con, mdiv, pdiv, sdiv; 721 + u64 fvco = parent_rate; 722 + 723 + pll_con = __raw_readl(pll->con_reg); 724 + mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; 725 + pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; 726 + sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; 727 + 728 + fvco *= (mdiv + 8); 729 + do_div(fvco, (pdiv + 2) << sdiv); 730 + 731 + return (unsigned int)fvco; 732 + } 733 + 734 + static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw, 735 + unsigned long parent_rate) 736 + { 737 + struct samsung_clk_pll *pll = to_clk_pll(hw); 738 + u32 pll_con, mdiv, pdiv, sdiv; 739 + u64 fvco = parent_rate; 740 + 741 + pll_con = __raw_readl(pll->con_reg); 742 + mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; 743 + pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; 744 + sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; 745 + 746 + fvco *= (2 * (mdiv + 8)); 747 + do_div(fvco, (pdiv + 2) << sdiv); 748 + 749 + return (unsigned int)fvco; 750 + } 751 + 752 + static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate, 753 + unsigned long prate) 754 + { 755 + struct samsung_clk_pll *pll = to_clk_pll(hw); 756 + const struct samsung_pll_rate_table *rate; 757 + u32 tmp; 758 + 759 + /* Get required rate settings from table */ 760 + rate = samsung_get_pll_settings(pll, drate); 761 + if (!rate) { 762 + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 763 + drate, __clk_get_name(hw->clk)); 764 + return -EINVAL; 765 + } 766 + 767 + tmp = __raw_readl(pll->con_reg); 768 + 769 + /* Change PLL PMS values */ 770 + tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) | 771 + (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) | 772 + (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT)); 773 + tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) | 774 + (rate->pdiv << PLLS3C2410_PDIV_SHIFT) | 775 + (rate->sdiv << PLLS3C2410_SDIV_SHIFT); 776 + __raw_writel(tmp, pll->con_reg); 777 + 778 + /* Time to settle according to the manual */ 779 + udelay(300); 780 + 781 + return 0; 782 + } 783 + 784 + static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable) 785 + { 786 + struct samsung_clk_pll *pll = to_clk_pll(hw); 787 + u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); 788 + u32 pll_en_orig = pll_en; 789 + 790 + if (enable) 791 + pll_en &= ~BIT(bit); 792 + else 793 + pll_en |= BIT(bit); 794 + 795 + __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); 796 + 797 + /* if we started the UPLL, then allow to settle */ 798 + if (enable && (pll_en_orig & BIT(bit))) 799 + udelay(300); 800 + 801 + return 0; 802 + } 803 + 804 + static int samsung_s3c2410_mpll_enable(struct clk_hw *hw) 805 + { 806 + return samsung_s3c2410_pll_enable(hw, 5, true); 807 + } 808 + 809 + static void samsung_s3c2410_mpll_disable(struct clk_hw *hw) 810 + { 811 + samsung_s3c2410_pll_enable(hw, 5, false); 812 + } 813 + 814 + static int samsung_s3c2410_upll_enable(struct clk_hw *hw) 815 + { 816 + return samsung_s3c2410_pll_enable(hw, 7, true); 817 + } 818 + 819 + static void samsung_s3c2410_upll_disable(struct clk_hw *hw) 820 + { 821 + samsung_s3c2410_pll_enable(hw, 7, false); 822 + } 823 + 824 + static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = { 825 + .recalc_rate = samsung_s3c2410_pll_recalc_rate, 826 + .enable = samsung_s3c2410_mpll_enable, 827 + .disable = samsung_s3c2410_mpll_disable, 828 + }; 829 + 830 + static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = { 831 + .recalc_rate = samsung_s3c2410_pll_recalc_rate, 832 + .enable = samsung_s3c2410_upll_enable, 833 + .disable = samsung_s3c2410_upll_disable, 834 + }; 835 + 836 + static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = { 837 + .recalc_rate = samsung_s3c2440_mpll_recalc_rate, 838 + .enable = samsung_s3c2410_mpll_enable, 839 + .disable = samsung_s3c2410_mpll_disable, 840 + }; 841 + 842 + static const struct clk_ops samsung_s3c2410_mpll_clk_ops = { 843 + .recalc_rate = samsung_s3c2410_pll_recalc_rate, 844 + .enable = samsung_s3c2410_mpll_enable, 845 + .disable = samsung_s3c2410_mpll_disable, 846 + .round_rate = samsung_pll_round_rate, 847 + .set_rate = samsung_s3c2410_pll_set_rate, 848 + }; 849 + 850 + static const struct clk_ops samsung_s3c2410_upll_clk_ops = { 851 + .recalc_rate = samsung_s3c2410_pll_recalc_rate, 852 + .enable = samsung_s3c2410_upll_enable, 853 + .disable = samsung_s3c2410_upll_disable, 854 + .round_rate = samsung_pll_round_rate, 855 + .set_rate = samsung_s3c2410_pll_set_rate, 856 + }; 857 + 858 + static const struct clk_ops samsung_s3c2440_mpll_clk_ops = { 859 + .recalc_rate = samsung_s3c2440_mpll_recalc_rate, 860 + .enable = samsung_s3c2410_mpll_enable, 861 + .disable = samsung_s3c2410_mpll_disable, 862 + .round_rate = samsung_pll_round_rate, 863 + .set_rate = samsung_s3c2410_pll_set_rate, 864 + }; 865 + 866 + /* 705 867 * PLL2550x Clock Type 706 868 */ 707 869 ··· 1029 865 init.ops = &samsung_pll46xx_clk_min_ops; 1030 866 else 1031 867 init.ops = &samsung_pll46xx_clk_ops; 868 + break; 869 + case pll_s3c2410_mpll: 870 + if (!pll->rate_table) 871 + init.ops = &samsung_s3c2410_mpll_clk_min_ops; 872 + else 873 + init.ops = &samsung_s3c2410_mpll_clk_ops; 874 + break; 875 + case pll_s3c2410_upll: 876 + if (!pll->rate_table) 877 + init.ops = &samsung_s3c2410_upll_clk_min_ops; 878 + else 879 + init.ops = &samsung_s3c2410_upll_clk_ops; 880 + break; 881 + case pll_s3c2440_mpll: 882 + if (!pll->rate_table) 883 + init.ops = &samsung_s3c2440_mpll_clk_min_ops; 884 + else 885 + init.ops = &samsung_s3c2440_mpll_clk_ops; 1032 886 break; 1033 887 default: 1034 888 pr_warn("%s: Unknown pll type for pll clk %s\n",
+3
drivers/clk/samsung/clk-pll.h
··· 28 28 pll_6552, 29 29 pll_6552_s3c2416, 30 30 pll_6553, 31 + pll_s3c2410_mpll, 32 + pll_s3c2410_upll, 33 + pll_s3c2440_mpll, 31 34 }; 32 35 33 36 #define PLL_35XX_RATE(_rate, _m, _p, _s) \