aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/meson/clk-mpll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/meson/clk-mpll.c')
-rw-r--r--drivers/clk/meson/clk-mpll.c125
1 files changed, 30 insertions, 95 deletions
diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c
index 5144360e2c80..0df1227b65b3 100644
--- a/drivers/clk/meson/clk-mpll.c
+++ b/drivers/clk/meson/clk-mpll.c
@@ -68,11 +68,15 @@
68#define N2_MIN 4 68#define N2_MIN 4
69#define N2_MAX 511 69#define N2_MAX 511
70 70
71#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) 71static inline struct meson_clk_mpll_data *
72meson_clk_mpll_data(struct clk_regmap *clk)
73{
74 return (struct meson_clk_mpll_data *)clk->data;
75}
72 76
73static long rate_from_params(unsigned long parent_rate, 77static long rate_from_params(unsigned long parent_rate,
74 unsigned long sdm, 78 unsigned int sdm,
75 unsigned long n2) 79 unsigned int n2)
76{ 80{
77 unsigned long divisor = (SDM_DEN * n2) + sdm; 81 unsigned long divisor = (SDM_DEN * n2) + sdm;
78 82
@@ -84,8 +88,8 @@ static long rate_from_params(unsigned long parent_rate,
84 88
85static void params_from_rate(unsigned long requested_rate, 89static void params_from_rate(unsigned long requested_rate,
86 unsigned long parent_rate, 90 unsigned long parent_rate,
87 unsigned long *sdm, 91 unsigned int *sdm,
88 unsigned long *n2) 92 unsigned int *n2)
89{ 93{
90 uint64_t div = parent_rate; 94 uint64_t div = parent_rate;
91 unsigned long rem = do_div(div, requested_rate); 95 unsigned long rem = do_div(div, requested_rate);
@@ -105,31 +109,23 @@ static void params_from_rate(unsigned long requested_rate,
105static unsigned long mpll_recalc_rate(struct clk_hw *hw, 109static unsigned long mpll_recalc_rate(struct clk_hw *hw,
106 unsigned long parent_rate) 110 unsigned long parent_rate)
107{ 111{
108 struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); 112 struct clk_regmap *clk = to_clk_regmap(hw);
109 struct parm *p; 113 struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
110 unsigned long reg, sdm, n2; 114 unsigned int sdm, n2;
111 long rate; 115 long rate;
112 116
113 p = &mpll->sdm; 117 sdm = meson_parm_read(clk->map, &mpll->sdm);
114 reg = readl(mpll->base + p->reg_off); 118 n2 = meson_parm_read(clk->map, &mpll->n2);
115 sdm = PARM_GET(p->width, p->shift, reg);
116
117 p = &mpll->n2;
118 reg = readl(mpll->base + p->reg_off);
119 n2 = PARM_GET(p->width, p->shift, reg);
120 119
121 rate = rate_from_params(parent_rate, sdm, n2); 120 rate = rate_from_params(parent_rate, sdm, n2);
122 if (rate < 0) 121 return rate < 0 ? 0 : rate;
123 return 0;
124
125 return rate;
126} 122}
127 123
128static long mpll_round_rate(struct clk_hw *hw, 124static long mpll_round_rate(struct clk_hw *hw,
129 unsigned long rate, 125 unsigned long rate,
130 unsigned long *parent_rate) 126 unsigned long *parent_rate)
131{ 127{
132 unsigned long sdm, n2; 128 unsigned int sdm, n2;
133 129
134 params_from_rate(rate, *parent_rate, &sdm, &n2); 130 params_from_rate(rate, *parent_rate, &sdm, &n2);
135 return rate_from_params(*parent_rate, sdm, n2); 131 return rate_from_params(*parent_rate, sdm, n2);
@@ -139,9 +135,9 @@ static int mpll_set_rate(struct clk_hw *hw,
139 unsigned long rate, 135 unsigned long rate,
140 unsigned long parent_rate) 136 unsigned long parent_rate)
141{ 137{
142 struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); 138 struct clk_regmap *clk = to_clk_regmap(hw);
143 struct parm *p; 139 struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
144 unsigned long reg, sdm, n2; 140 unsigned int sdm, n2;
145 unsigned long flags = 0; 141 unsigned long flags = 0;
146 142
147 params_from_rate(rate, parent_rate, &sdm, &n2); 143 params_from_rate(rate, parent_rate, &sdm, &n2);
@@ -151,97 +147,36 @@ static int mpll_set_rate(struct clk_hw *hw,
151 else 147 else
152 __acquire(mpll->lock); 148 __acquire(mpll->lock);
153 149
154 p = &mpll->sdm; 150 /* Enable and set the fractional part */
155 reg = readl(mpll->base + p->reg_off); 151 meson_parm_write(clk->map, &mpll->sdm, sdm);
156 reg = PARM_SET(p->width, p->shift, reg, sdm); 152 meson_parm_write(clk->map, &mpll->sdm_en, 1);
157 writel(reg, mpll->base + p->reg_off);
158
159 p = &mpll->sdm_en;
160 reg = readl(mpll->base + p->reg_off);
161 reg = PARM_SET(p->width, p->shift, reg, 1);
162 writel(reg, mpll->base + p->reg_off);
163
164 p = &mpll->ssen;
165 if (p->width != 0) {
166 reg = readl(mpll->base + p->reg_off);
167 reg = PARM_SET(p->width, p->shift, reg, 1);
168 writel(reg, mpll->base + p->reg_off);
169 }
170
171 p = &mpll->n2;
172 reg = readl(mpll->base + p->reg_off);
173 reg = PARM_SET(p->width, p->shift, reg, n2);
174 writel(reg, mpll->base + p->reg_off);
175
176 if (mpll->lock)
177 spin_unlock_irqrestore(mpll->lock, flags);
178 else
179 __release(mpll->lock);
180
181 return 0;
182}
183 153
184static void mpll_enable_core(struct clk_hw *hw, int enable) 154 /* Set additional fractional part enable if required */
185{ 155 if (MESON_PARM_APPLICABLE(&mpll->ssen))
186 struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); 156 meson_parm_write(clk->map, &mpll->ssen, 1);
187 struct parm *p;
188 unsigned long reg;
189 unsigned long flags = 0;
190 157
191 if (mpll->lock) 158 /* Set the integer divider part */
192 spin_lock_irqsave(mpll->lock, flags); 159 meson_parm_write(clk->map, &mpll->n2, n2);
193 else
194 __acquire(mpll->lock);
195 160
196 p = &mpll->en; 161 /* Set the magic misc bit if required */
197 reg = readl(mpll->base + p->reg_off); 162 if (MESON_PARM_APPLICABLE(&mpll->misc))
198 reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0); 163 meson_parm_write(clk->map, &mpll->misc, 1);
199 writel(reg, mpll->base + p->reg_off);
200 164
201 if (mpll->lock) 165 if (mpll->lock)
202 spin_unlock_irqrestore(mpll->lock, flags); 166 spin_unlock_irqrestore(mpll->lock, flags);
203 else 167 else
204 __release(mpll->lock); 168 __release(mpll->lock);
205}
206
207
208static int mpll_enable(struct clk_hw *hw)
209{
210 mpll_enable_core(hw, 1);
211 169
212 return 0; 170 return 0;
213} 171}
214 172
215static void mpll_disable(struct clk_hw *hw)
216{
217 mpll_enable_core(hw, 0);
218}
219
220static int mpll_is_enabled(struct clk_hw *hw)
221{
222 struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
223 struct parm *p;
224 unsigned long reg;
225 int en;
226
227 p = &mpll->en;
228 reg = readl(mpll->base + p->reg_off);
229 en = PARM_GET(p->width, p->shift, reg);
230
231 return en;
232}
233
234const struct clk_ops meson_clk_mpll_ro_ops = { 173const struct clk_ops meson_clk_mpll_ro_ops = {
235 .recalc_rate = mpll_recalc_rate, 174 .recalc_rate = mpll_recalc_rate,
236 .round_rate = mpll_round_rate, 175 .round_rate = mpll_round_rate,
237 .is_enabled = mpll_is_enabled,
238}; 176};
239 177
240const struct clk_ops meson_clk_mpll_ops = { 178const struct clk_ops meson_clk_mpll_ops = {
241 .recalc_rate = mpll_recalc_rate, 179 .recalc_rate = mpll_recalc_rate,
242 .round_rate = mpll_round_rate, 180 .round_rate = mpll_round_rate,
243 .set_rate = mpll_set_rate, 181 .set_rate = mpll_set_rate,
244 .enable = mpll_enable,
245 .disable = mpll_disable,
246 .is_enabled = mpll_is_enabled,
247}; 182};