0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk-provider.h>
0009 #include <linux/io.h>
0010 #include <linux/kernel.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/slab.h>
0014 #include <asm/div64.h>
0015
0016 #include "berlin2-div.h"
0017 #include "berlin2-pll.h"
0018
0019 struct berlin2_pll {
0020 struct clk_hw hw;
0021 void __iomem *base;
0022 struct berlin2_pll_map map;
0023 };
0024
0025 #define to_berlin2_pll(hw) container_of(hw, struct berlin2_pll, hw)
0026
0027 #define SPLL_CTRL0 0x00
0028 #define SPLL_CTRL1 0x04
0029 #define SPLL_CTRL2 0x08
0030 #define SPLL_CTRL3 0x0c
0031 #define SPLL_CTRL4 0x10
0032
0033 #define FBDIV_MASK 0x1ff
0034 #define RFDIV_MASK 0x1f
0035 #define DIVSEL_MASK 0xf
0036
0037
0038
0039
0040
0041 static unsigned long
0042 berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
0043 {
0044 struct berlin2_pll *pll = to_berlin2_pll(hw);
0045 struct berlin2_pll_map *map = &pll->map;
0046 u32 val, fbdiv, rfdiv, vcodivsel, vcodiv;
0047 u64 rate = parent_rate;
0048
0049 val = readl_relaxed(pll->base + SPLL_CTRL0);
0050 fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
0051 rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
0052 if (rfdiv == 0) {
0053 pr_warn("%s has zero rfdiv\n", clk_hw_get_name(hw));
0054 rfdiv = 1;
0055 }
0056
0057 val = readl_relaxed(pll->base + SPLL_CTRL1);
0058 vcodivsel = (val >> map->divsel_shift) & DIVSEL_MASK;
0059 vcodiv = map->vcodiv[vcodivsel];
0060 if (vcodiv == 0) {
0061 pr_warn("%s has zero vcodiv (index %d)\n",
0062 clk_hw_get_name(hw), vcodivsel);
0063 vcodiv = 1;
0064 }
0065
0066 rate *= fbdiv * map->mult;
0067 do_div(rate, rfdiv * vcodiv);
0068
0069 return (unsigned long)rate;
0070 }
0071
0072 static const struct clk_ops berlin2_pll_ops = {
0073 .recalc_rate = berlin2_pll_recalc_rate,
0074 };
0075
0076 int __init
0077 berlin2_pll_register(const struct berlin2_pll_map *map,
0078 void __iomem *base, const char *name,
0079 const char *parent_name, unsigned long flags)
0080 {
0081 struct clk_init_data init;
0082 struct berlin2_pll *pll;
0083
0084 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
0085 if (!pll)
0086 return -ENOMEM;
0087
0088
0089 memcpy(&pll->map, map, sizeof(*map));
0090 pll->base = base;
0091 pll->hw.init = &init;
0092 init.name = name;
0093 init.ops = &berlin2_pll_ops;
0094 init.parent_names = &parent_name;
0095 init.num_parents = 1;
0096 init.flags = flags;
0097
0098 return clk_hw_register(NULL, &pll->hw);
0099 }