Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/bits.h>
0003 #include <linux/clk-provider.h>
0004 #include <linux/io.h>
0005 #include <linux/slab.h>
0006 #include <linux/kernel.h>
0007 #include <linux/err.h>
0008 
0009 #include "clk.h"
0010 
0011 #define MFN_BITS    (10)
0012 #define MFN_SIGN    (BIT(MFN_BITS - 1))
0013 #define MFN_MASK    (MFN_SIGN - 1)
0014 
0015 /**
0016  * struct clk_pllv1 - IMX PLLv1 clock descriptor
0017  *
0018  * @hw:     clock source
0019  * @base:   base address of pll registers
0020  * @type:   type of IMX_PLLV1
0021  *
0022  * PLL clock version 1, found on i.MX1/21/25/27/31/35
0023  */
0024 struct clk_pllv1 {
0025     struct clk_hw   hw;
0026     void __iomem    *base;
0027     enum imx_pllv1_type type;
0028 };
0029 
0030 #define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk))
0031 
0032 static inline bool is_imx1_pllv1(struct clk_pllv1 *pll)
0033 {
0034     return pll->type == IMX_PLLV1_IMX1;
0035 }
0036 
0037 static inline bool is_imx21_pllv1(struct clk_pllv1 *pll)
0038 {
0039     return pll->type == IMX_PLLV1_IMX21;
0040 }
0041 
0042 static inline bool is_imx27_pllv1(struct clk_pllv1 *pll)
0043 {
0044     return pll->type == IMX_PLLV1_IMX27;
0045 }
0046 
0047 static inline bool mfn_is_negative(struct clk_pllv1 *pll, unsigned int mfn)
0048 {
0049     return !is_imx1_pllv1(pll) && !is_imx21_pllv1(pll) && (mfn & MFN_SIGN);
0050 }
0051 
0052 static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
0053         unsigned long parent_rate)
0054 {
0055     struct clk_pllv1 *pll = to_clk_pllv1(hw);
0056     unsigned long long ull;
0057     int mfn_abs;
0058     unsigned int mfi, mfn, mfd, pd;
0059     u32 reg;
0060     unsigned long rate;
0061 
0062     reg = readl(pll->base);
0063 
0064     /*
0065      * Get the resulting clock rate from a PLL register value and the input
0066      * frequency. PLLs with this register layout can be found on i.MX1,
0067      * i.MX21, i.MX27 and i,MX31
0068      *
0069      *                  mfi + mfn / (mfd + 1)
0070      *  f = 2 * f_ref * --------------------
0071      *                        pd + 1
0072      */
0073 
0074     mfi = (reg >> 10) & 0xf;
0075     mfn = reg & 0x3ff;
0076     mfd = (reg >> 16) & 0x3ff;
0077     pd =  (reg >> 26) & 0xf;
0078 
0079     mfi = mfi <= 5 ? 5 : mfi;
0080 
0081     mfn_abs = mfn;
0082 
0083     /*
0084      * On all i.MXs except i.MX1 and i.MX21 mfn is a 10bit
0085      * 2's complements number.
0086      * On i.MX27 the bit 9 is the sign bit.
0087      */
0088     if (mfn_is_negative(pll, mfn)) {
0089         if (is_imx27_pllv1(pll))
0090             mfn_abs = mfn & MFN_MASK;
0091         else
0092             mfn_abs = BIT(MFN_BITS) - mfn;
0093     }
0094 
0095     rate = parent_rate * 2;
0096     rate /= pd + 1;
0097 
0098     ull = (unsigned long long)rate * mfn_abs;
0099 
0100     do_div(ull, mfd + 1);
0101 
0102     if (mfn_is_negative(pll, mfn))
0103         ull = (rate * mfi) - ull;
0104     else
0105         ull = (rate * mfi) + ull;
0106 
0107     return ull;
0108 }
0109 
0110 static const struct clk_ops clk_pllv1_ops = {
0111     .recalc_rate = clk_pllv1_recalc_rate,
0112 };
0113 
0114 struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name,
0115         const char *parent, void __iomem *base)
0116 {
0117     struct clk_pllv1 *pll;
0118     struct clk_hw *hw;
0119     struct clk_init_data init;
0120     int ret;
0121 
0122     pll = kmalloc(sizeof(*pll), GFP_KERNEL);
0123     if (!pll)
0124         return ERR_PTR(-ENOMEM);
0125 
0126     pll->base = base;
0127     pll->type = type;
0128 
0129     init.name = name;
0130     init.ops = &clk_pllv1_ops;
0131     init.flags = 0;
0132     init.parent_names = &parent;
0133     init.num_parents = 1;
0134 
0135     pll->hw.init = &init;
0136     hw = &pll->hw;
0137 
0138     ret = clk_hw_register(NULL, hw);
0139     if (ret) {
0140         kfree(pll);
0141         return ERR_PTR(ret);
0142     }
0143 
0144     return hw;
0145 }