diff options
author | Kelvin Cheung <keguang.zhang@gmail.com> | 2014-10-09 23:42:51 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-11-24 01:45:09 -0500 |
commit | 3526f74fa925e44335b94ed0c9f93648e26058ef (patch) | |
tree | 047eee5f0b3c1ec52941f485b29e2e91657f52b5 /drivers/clk | |
parent | c5d58e9e79dd8d687454915fc4e845434f973175 (diff) |
clk: ls1x: Update relationship among all clocks
- Add clock lookups for APB devices.
- Update clock relationship to make it more exact and clear.
_____
_______________________| |
OSC ___/ | MUX |___ XXX CLK
\___ PLL ___ XXX DIV ___| |
|_____|
Signed-off-by: Kelvin Cheung <keguang.zhang@gmail.com>
Cc: linux-kernel@vger.kernel.org
Cc: mturquette@linaro.org
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/8026/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/clk-ls1x.c | 109 |
1 files changed, 80 insertions, 29 deletions
diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c index f20b750235f6..ca80103ac188 100644 --- a/drivers/clk/clk-ls1x.c +++ b/drivers/clk/clk-ls1x.c | |||
@@ -15,7 +15,8 @@ | |||
15 | 15 | ||
16 | #include <loongson1.h> | 16 | #include <loongson1.h> |
17 | 17 | ||
18 | #define OSC 33 | 18 | #define OSC (33 * 1000000) |
19 | #define DIV_APB 2 | ||
19 | 20 | ||
20 | static DEFINE_SPINLOCK(_lock); | 21 | static DEFINE_SPINLOCK(_lock); |
21 | 22 | ||
@@ -29,13 +30,12 @@ static void ls1x_pll_clk_disable(struct clk_hw *hw) | |||
29 | } | 30 | } |
30 | 31 | ||
31 | static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, | 32 | static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, |
32 | unsigned long parent_rate) | 33 | unsigned long parent_rate) |
33 | { | 34 | { |
34 | u32 pll, rate; | 35 | u32 pll, rate; |
35 | 36 | ||
36 | pll = __raw_readl(LS1X_CLK_PLL_FREQ); | 37 | pll = __raw_readl(LS1X_CLK_PLL_FREQ); |
37 | rate = ((12 + (pll & 0x3f)) * 1000000) + | 38 | rate = 12 + (pll & 0x3f) + (((pll >> 8) & 0x3ff) >> 10); |
38 | ((((pll >> 8) & 0x3ff) * 1000000) >> 10); | ||
39 | rate *= OSC; | 39 | rate *= OSC; |
40 | rate >>= 1; | 40 | rate >>= 1; |
41 | 41 | ||
@@ -48,8 +48,10 @@ static const struct clk_ops ls1x_pll_clk_ops = { | |||
48 | .recalc_rate = ls1x_pll_recalc_rate, | 48 | .recalc_rate = ls1x_pll_recalc_rate, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | static struct clk * __init clk_register_pll(struct device *dev, | 51 | static struct clk *__init clk_register_pll(struct device *dev, |
52 | const char *name, const char *parent_name, unsigned long flags) | 52 | const char *name, |
53 | const char *parent_name, | ||
54 | unsigned long flags) | ||
53 | { | 55 | { |
54 | struct clk_hw *hw; | 56 | struct clk_hw *hw; |
55 | struct clk *clk; | 57 | struct clk *clk; |
@@ -78,34 +80,83 @@ static struct clk * __init clk_register_pll(struct device *dev, | |||
78 | return clk; | 80 | return clk; |
79 | } | 81 | } |
80 | 82 | ||
83 | static const char const *cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; | ||
84 | static const char const *ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", }; | ||
85 | static const char const *dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; | ||
86 | |||
81 | void __init ls1x_clk_init(void) | 87 | void __init ls1x_clk_init(void) |
82 | { | 88 | { |
83 | struct clk *clk; | 89 | struct clk *clk; |
84 | 90 | ||
85 | clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT); | 91 | clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, CLK_IS_ROOT, |
86 | clk_prepare_enable(clk); | 92 | OSC); |
87 | 93 | clk_register_clkdev(clk, "osc_33m_clk", NULL); | |
88 | clk = clk_register_divider(NULL, "cpu_clk", "pll_clk", | 94 | |
89 | CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT, | 95 | /* clock derived from 33 MHz OSC clk */ |
90 | DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | 96 | clk = clk_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); |
91 | clk_prepare_enable(clk); | 97 | clk_register_clkdev(clk, "pll_clk", NULL); |
92 | clk_register_clkdev(clk, "cpu", NULL); | 98 | |
93 | 99 | /* clock derived from PLL clk */ | |
94 | clk = clk_register_divider(NULL, "dc_clk", "pll_clk", | 100 | /* _____ |
95 | CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, | 101 | * _______________________| | |
96 | DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | 102 | * OSC ___/ | MUX |___ CPU CLK |
97 | clk_prepare_enable(clk); | 103 | * \___ PLL ___ CPU DIV ___| | |
98 | clk_register_clkdev(clk, "dc", NULL); | 104 | * |_____| |
99 | 105 | */ | |
100 | clk = clk_register_divider(NULL, "ahb_clk", "pll_clk", | 106 | clk = clk_register_divider(NULL, "cpu_clk_div", "pll_clk", |
101 | CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, | 107 | CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, |
102 | DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | 108 | DIV_CPU_SHIFT, DIV_CPU_WIDTH, |
103 | clk_prepare_enable(clk); | 109 | CLK_DIVIDER_ONE_BASED | |
104 | clk_register_clkdev(clk, "ahb", NULL); | 110 | CLK_DIVIDER_ROUND_CLOSEST, &_lock); |
111 | clk_register_clkdev(clk, "cpu_clk_div", NULL); | ||
112 | clk = clk_register_mux(NULL, "cpu_clk", cpu_parents, | ||
113 | ARRAY_SIZE(cpu_parents), | ||
114 | CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, | ||
115 | BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); | ||
116 | clk_register_clkdev(clk, "cpu_clk", NULL); | ||
117 | |||
118 | /* _____ | ||
119 | * _______________________| | | ||
120 | * OSC ___/ | MUX |___ DC CLK | ||
121 | * \___ PLL ___ DC DIV ___| | | ||
122 | * |_____| | ||
123 | */ | ||
124 | clk = clk_register_divider(NULL, "dc_clk_div", "pll_clk", | ||
125 | 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, | ||
126 | DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | ||
127 | clk_register_clkdev(clk, "dc_clk_div", NULL); | ||
128 | clk = clk_register_mux(NULL, "dc_clk", dc_parents, | ||
129 | ARRAY_SIZE(dc_parents), | ||
130 | CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, | ||
131 | BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); | ||
132 | clk_register_clkdev(clk, "dc_clk", NULL); | ||
133 | |||
134 | /* _____ | ||
135 | * _______________________| | | ||
136 | * OSC ___/ | MUX |___ DDR CLK | ||
137 | * \___ PLL ___ DDR DIV ___| | | ||
138 | * |_____| | ||
139 | */ | ||
140 | clk = clk_register_divider(NULL, "ahb_clk_div", "pll_clk", | ||
141 | 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, | ||
142 | DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, | ||
143 | &_lock); | ||
144 | clk_register_clkdev(clk, "ahb_clk_div", NULL); | ||
145 | clk = clk_register_mux(NULL, "ahb_clk", ahb_parents, | ||
146 | ARRAY_SIZE(ahb_parents), | ||
147 | CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, | ||
148 | BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); | ||
149 | clk_register_clkdev(clk, "ahb_clk", NULL); | ||
105 | clk_register_clkdev(clk, "stmmaceth", NULL); | 150 | clk_register_clkdev(clk, "stmmaceth", NULL); |
106 | 151 | ||
107 | clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2); | 152 | /* clock derived from AHB clk */ |
108 | clk_prepare_enable(clk); | 153 | /* APB clk is always half of the AHB clk */ |
109 | clk_register_clkdev(clk, "apb", NULL); | 154 | clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, |
155 | DIV_APB); | ||
156 | clk_register_clkdev(clk, "apb_clk", NULL); | ||
157 | clk_register_clkdev(clk, "ls1x_i2c", NULL); | ||
158 | clk_register_clkdev(clk, "ls1x_pwmtimer", NULL); | ||
159 | clk_register_clkdev(clk, "ls1x_spi", NULL); | ||
160 | clk_register_clkdev(clk, "ls1x_wdt", NULL); | ||
110 | clk_register_clkdev(clk, "serial8250", NULL); | 161 | clk_register_clkdev(clk, "serial8250", NULL); |
111 | } | 162 | } |