2 * Copyright (c) 2015 Endless Mobile, Inc.
3 * Author: Carlo Caione <carlo@endlessm.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
19 * In the most basic form, a Meson PLL is composed as follows:
22 * +------------------------------+
24 * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
26 * +------------------------------+
30 * out = (in * M / N) >> OD
33 #include <linux/clk-provider.h>
34 #include <linux/delay.h>
35 #include <linux/err.h>
37 #include <linux/module.h>
38 #include <linux/of_address.h>
39 #include <linux/slab.h>
40 #include <linux/string.h>
44 #define MESON_PLL_RESET BIT(29)
45 #define MESON_PLL_LOCK BIT(31)
47 struct meson_clk_pll
{
50 struct pll_conf
*conf
;
51 unsigned int rate_count
;
54 #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
56 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw
*hw
,
57 unsigned long parent_rate
)
59 struct meson_clk_pll
*pll
= to_meson_clk_pll(hw
);
61 unsigned long parent_rate_mhz
= parent_rate
/ 1000000;
62 unsigned long rate_mhz
;
67 reg
= readl(pll
->base
+ p
->reg_off
);
68 n
= PARM_GET(p
->width
, p
->shift
, reg
);
71 reg
= readl(pll
->base
+ p
->reg_off
);
72 m
= PARM_GET(p
->width
, p
->shift
, reg
);
75 reg
= readl(pll
->base
+ p
->reg_off
);
76 od
= PARM_GET(p
->width
, p
->shift
, reg
);
78 rate_mhz
= (parent_rate_mhz
* m
/ n
) >> od
;
80 return rate_mhz
* 1000000;
83 static long meson_clk_pll_round_rate(struct clk_hw
*hw
, unsigned long rate
,
84 unsigned long *parent_rate
)
86 struct meson_clk_pll
*pll
= to_meson_clk_pll(hw
);
87 const struct pll_rate_table
*rate_table
= pll
->conf
->rate_table
;
90 for (i
= 0; i
< pll
->rate_count
; i
++) {
91 if (rate
<= rate_table
[i
].rate
)
92 return rate_table
[i
].rate
;
95 /* else return the smallest value */
96 return rate_table
[0].rate
;
99 static const struct pll_rate_table
*meson_clk_get_pll_settings(struct meson_clk_pll
*pll
,
102 const struct pll_rate_table
*rate_table
= pll
->conf
->rate_table
;
105 for (i
= 0; i
< pll
->rate_count
; i
++) {
106 if (rate
== rate_table
[i
].rate
)
107 return &rate_table
[i
];
112 static int meson_clk_pll_wait_lock(struct meson_clk_pll
*pll
,
115 int delay
= 24000000;
119 reg
= readl(pll
->base
+ p_n
->reg_off
);
121 if (reg
& MESON_PLL_LOCK
)
128 static int meson_clk_pll_set_rate(struct clk_hw
*hw
, unsigned long rate
,
129 unsigned long parent_rate
)
131 struct meson_clk_pll
*pll
= to_meson_clk_pll(hw
);
133 const struct pll_rate_table
*rate_set
;
134 unsigned long old_rate
;
138 if (parent_rate
== 0 || rate
== 0)
143 rate_set
= meson_clk_get_pll_settings(pll
, rate
);
149 reg
= readl(pll
->base
+ p
->reg_off
);
150 writel(reg
| MESON_PLL_RESET
, pll
->base
+ p
->reg_off
);
152 reg
= PARM_SET(p
->width
, p
->shift
, reg
, rate_set
->n
);
153 writel(reg
, pll
->base
+ p
->reg_off
);
156 reg
= readl(pll
->base
+ p
->reg_off
);
157 reg
= PARM_SET(p
->width
, p
->shift
, reg
, rate_set
->m
);
158 writel(reg
, pll
->base
+ p
->reg_off
);
161 reg
= readl(pll
->base
+ p
->reg_off
);
162 reg
= PARM_SET(p
->width
, p
->shift
, reg
, rate_set
->od
);
163 writel(reg
, pll
->base
+ p
->reg_off
);
166 ret
= meson_clk_pll_wait_lock(pll
, p
);
168 pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
170 meson_clk_pll_set_rate(hw
, old_rate
, parent_rate
);
176 static const struct clk_ops meson_clk_pll_ops
= {
177 .recalc_rate
= meson_clk_pll_recalc_rate
,
178 .round_rate
= meson_clk_pll_round_rate
,
179 .set_rate
= meson_clk_pll_set_rate
,
182 static const struct clk_ops meson_clk_pll_ro_ops
= {
183 .recalc_rate
= meson_clk_pll_recalc_rate
,
186 struct clk
*meson_clk_register_pll(const struct clk_conf
*clk_conf
,
187 void __iomem
*reg_base
,
191 struct meson_clk_pll
*clk_pll
;
192 struct clk_init_data init
;
194 clk_pll
= kzalloc(sizeof(*clk_pll
), GFP_KERNEL
);
196 return ERR_PTR(-ENOMEM
);
198 clk_pll
->base
= reg_base
+ clk_conf
->reg_off
;
199 clk_pll
->lock
= lock
;
200 clk_pll
->conf
= clk_conf
->conf
.pll
;
202 init
.name
= clk_conf
->clk_name
;
203 init
.flags
= clk_conf
->flags
| CLK_GET_RATE_NOCACHE
;
205 init
.parent_names
= &clk_conf
->clks_parent
[0];
206 init
.num_parents
= 1;
207 init
.ops
= &meson_clk_pll_ro_ops
;
209 /* If no rate_table is specified we assume the PLL is read-only */
210 if (clk_pll
->conf
->rate_table
) {
213 for (len
= 0; clk_pll
->conf
->rate_table
[len
].rate
!= 0; )
216 clk_pll
->rate_count
= len
;
217 init
.ops
= &meson_clk_pll_ops
;
220 clk_pll
->hw
.init
= &init
;
222 clk
= clk_register(NULL
, &clk_pll
->hw
);