2 * Marvell Dove PMU Core PLL divider driver
4 * Cleaned up by substantially rewriting, and converted to DT by
5 * Russell King. Origin is not known.
7 #include <linux/clk-provider.h>
8 #include <linux/delay.h>
10 #include <linux/kernel.h>
12 #include <linux/of_address.h>
14 #include "dove-divider.h"
31 DIV_CTRL1_N_RESET_MASK
= BIT(10),
34 #define to_dove_clk(hw) container_of(hw, struct dove_clk, hw)
36 static void dove_load_divider(void __iomem
*base
, u32 val
, u32 mask
, u32 load
)
40 v
= readl_relaxed(base
+ DIV_CTRL1
) | DIV_CTRL1_N_RESET_MASK
;
41 writel_relaxed(v
, base
+ DIV_CTRL1
);
43 v
= (readl_relaxed(base
+ DIV_CTRL0
) & ~(mask
| load
)) | val
;
44 writel_relaxed(v
, base
+ DIV_CTRL0
);
45 writel_relaxed(v
| load
, base
+ DIV_CTRL0
);
47 writel_relaxed(v
, base
+ DIV_CTRL0
);
50 static unsigned int dove_get_divider(struct dove_clk
*dc
)
55 val
= readl_relaxed(dc
->base
+ DIV_CTRL0
);
56 val
>>= dc
->div_bit_start
;
58 divider
= val
& ~(~0 << dc
->div_bit_size
);
60 if (dc
->divider_table
)
61 divider
= dc
->divider_table
[divider
];
66 static int dove_calc_divider(const struct dove_clk
*dc
, unsigned long rate
,
67 unsigned long parent_rate
, bool set
)
69 unsigned int divider
, max
;
71 divider
= DIV_ROUND_CLOSEST(parent_rate
, rate
);
73 if (dc
->divider_table
) {
76 for (i
= 0; dc
->divider_table
[i
]; i
++)
77 if (divider
== dc
->divider_table
[i
]) {
82 if (!dc
->divider_table
[i
])
85 max
= 1 << dc
->div_bit_size
;
87 if (set
&& (divider
== 0 || divider
>= max
))
91 else if (divider
== 0)
98 static unsigned long dove_recalc_rate(struct clk_hw
*hw
, unsigned long parent
)
100 struct dove_clk
*dc
= to_dove_clk(hw
);
101 unsigned int divider
= dove_get_divider(dc
);
102 unsigned long rate
= DIV_ROUND_CLOSEST(parent
, divider
);
104 pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
105 __func__
, dc
->name
, divider
, parent
, rate
);
110 static long dove_round_rate(struct clk_hw
*hw
, unsigned long rate
,
111 unsigned long *parent
)
113 struct dove_clk
*dc
= to_dove_clk(hw
);
114 unsigned long parent_rate
= *parent
;
117 divider
= dove_calc_divider(dc
, rate
, parent_rate
, false);
121 rate
= DIV_ROUND_CLOSEST(parent_rate
, divider
);
123 pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
124 __func__
, dc
->name
, divider
, parent_rate
, rate
);
129 static int dove_set_clock(struct clk_hw
*hw
, unsigned long rate
,
130 unsigned long parent_rate
)
132 struct dove_clk
*dc
= to_dove_clk(hw
);
136 divider
= dove_calc_divider(dc
, rate
, parent_rate
, true);
140 pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
141 __func__
, dc
->name
, divider
, parent_rate
, rate
);
143 div
= (u32
)divider
<< dc
->div_bit_start
;
144 mask
= ~(~0 << dc
->div_bit_size
) << dc
->div_bit_start
;
145 load
= BIT(dc
->div_bit_load
);
148 dove_load_divider(dc
->base
, div
, mask
, load
);
149 spin_unlock(dc
->lock
);
154 static const struct clk_ops dove_divider_ops
= {
155 .set_rate
= dove_set_clock
,
156 .round_rate
= dove_round_rate
,
157 .recalc_rate
= dove_recalc_rate
,
160 static struct clk
*clk_register_dove_divider(struct device
*dev
,
161 struct dove_clk
*dc
, const char **parent_names
, size_t num_parents
,
165 struct clk_init_data init
= {
167 .ops
= &dove_divider_ops
,
168 .parent_names
= parent_names
,
169 .num_parents
= num_parents
,
172 strlcpy(name
, dc
->name
, sizeof(name
));
176 dc
->div_bit_size
= dc
->div_bit_end
- dc
->div_bit_start
+ 1;
178 return clk_register(dev
, &dc
->hw
);
181 static DEFINE_SPINLOCK(dove_divider_lock
);
183 static u32 axi_divider
[] = {-1, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 0};
185 static struct dove_clk dove_hw_clocks
[4] = {
188 .lock
= &dove_divider_lock
,
192 .divider_table
= axi_divider
,
195 .lock
= &dove_divider_lock
,
201 .lock
= &dove_divider_lock
,
207 .lock
= &dove_divider_lock
,
214 static const char *core_pll
[] = {
218 static int dove_divider_init(struct device
*dev
, void __iomem
*base
,
225 * Create the core PLL clock. We treat this as a fixed rate
226 * clock as we don't know any better, and documentation is sparse.
228 clk
= clk_register_fixed_rate(dev
, core_pll
[0], NULL
, 0, 2000000000UL);
232 for (i
= 0; i
< ARRAY_SIZE(dove_hw_clocks
); i
++)
233 clks
[i
] = clk_register_dove_divider(dev
, &dove_hw_clocks
[i
],
235 ARRAY_SIZE(core_pll
), base
);
240 static struct clk
*dove_divider_clocks
[4];
242 static struct clk_onecell_data dove_divider_data
= {
243 .clks
= dove_divider_clocks
,
244 .clk_num
= ARRAY_SIZE(dove_divider_clocks
),
247 void __init
dove_divider_clk_init(struct device_node
*np
)
251 base
= of_iomap(np
, 0);
255 if (WARN_ON(dove_divider_init(NULL
, base
, dove_divider_clocks
))) {
260 of_clk_add_provider(np
, of_clk_src_onecell_get
, &dove_divider_data
);