Skip to content

Commit bc4d25f

Browse files
prabhakarladgeertu
authored andcommitted
clk: renesas: rzv2h: Add support for dynamic switching divider clocks
Add support for dynamic switching divider clocks. Signed-off-by: Lad Prabhakar <[email protected]> Reviewed-by: Geert Uytterhoeven <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Geert Uytterhoeven <[email protected]>
1 parent f0fe60c commit bc4d25f

File tree

2 files changed

+201
-3
lines changed

2 files changed

+201
-3
lines changed

drivers/clk/renesas/rzv2h-cpg.c

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,19 @@
4545
#define PDIV(val) FIELD_GET(GENMASK(5, 0), (val))
4646
#define SDIV(val) FIELD_GET(GENMASK(2, 0), (val))
4747

48+
#define DDIV_DIVCTL_WEN(shift) BIT((shift) + 16)
49+
4850
#define GET_MOD_CLK_ID(base, index, bit) \
4951
((base) + ((((index) * (16))) + (bit)))
5052

53+
#define CPG_CLKSTATUS0 (0x700)
54+
5155
/**
5256
* struct rzv2h_cpg_priv - Clock Pulse Generator Private Data
5357
*
5458
* @dev: CPG device
5559
* @base: CPG register block base address
60+
* @rmw_lock: protects register accesses
5661
* @clks: Array containing all Core and Module Clocks
5762
* @num_core_clks: Number of Core Clocks in clks[]
5863
* @num_mod_clks: Number of Module Clocks in clks[]
@@ -64,6 +69,7 @@
6469
struct rzv2h_cpg_priv {
6570
struct device *dev;
6671
void __iomem *base;
72+
spinlock_t rmw_lock;
6773

6874
struct clk **clks;
6975
unsigned int num_core_clks;
@@ -108,6 +114,21 @@ struct mod_clock {
108114

109115
#define to_mod_clock(_hw) container_of(_hw, struct mod_clock, hw)
110116

117+
/**
118+
* struct ddiv_clk - DDIV clock
119+
*
120+
* @priv: CPG private data
121+
* @div: divider clk
122+
* @mon: monitor bit in CPG_CLKSTATUS0 register
123+
*/
124+
struct ddiv_clk {
125+
struct rzv2h_cpg_priv *priv;
126+
struct clk_divider div;
127+
u8 mon;
128+
};
129+
130+
#define to_ddiv_clock(_div) container_of(_div, struct ddiv_clk, div)
131+
111132
static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
112133
unsigned long parent_rate)
113134
{
@@ -161,7 +182,7 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
161182
init.num_parents = 1;
162183

163184
pll_clk->hw.init = &init;
164-
pll_clk->conf = core->conf;
185+
pll_clk->conf = core->cfg.conf;
165186
pll_clk->base = base;
166187
pll_clk->priv = priv;
167188
pll_clk->type = core->type;
@@ -173,6 +194,143 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
173194
return pll_clk->hw.clk;
174195
}
175196

197+
static unsigned long rzv2h_ddiv_recalc_rate(struct clk_hw *hw,
198+
unsigned long parent_rate)
199+
{
200+
struct clk_divider *divider = to_clk_divider(hw);
201+
unsigned int val;
202+
203+
val = readl(divider->reg) >> divider->shift;
204+
val &= clk_div_mask(divider->width);
205+
206+
return divider_recalc_rate(hw, parent_rate, val, divider->table,
207+
divider->flags, divider->width);
208+
}
209+
210+
static long rzv2h_ddiv_round_rate(struct clk_hw *hw, unsigned long rate,
211+
unsigned long *prate)
212+
{
213+
struct clk_divider *divider = to_clk_divider(hw);
214+
215+
return divider_round_rate(hw, rate, prate, divider->table,
216+
divider->width, divider->flags);
217+
}
218+
219+
static int rzv2h_ddiv_determine_rate(struct clk_hw *hw,
220+
struct clk_rate_request *req)
221+
{
222+
struct clk_divider *divider = to_clk_divider(hw);
223+
224+
return divider_determine_rate(hw, req, divider->table, divider->width,
225+
divider->flags);
226+
}
227+
228+
static inline int rzv2h_cpg_wait_ddiv_clk_update_done(void __iomem *base, u8 mon)
229+
{
230+
u32 bitmask = BIT(mon);
231+
u32 val;
232+
233+
return readl_poll_timeout_atomic(base + CPG_CLKSTATUS0, val, !(val & bitmask), 10, 200);
234+
}
235+
236+
static int rzv2h_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
237+
unsigned long parent_rate)
238+
{
239+
struct clk_divider *divider = to_clk_divider(hw);
240+
struct ddiv_clk *ddiv = to_ddiv_clock(divider);
241+
struct rzv2h_cpg_priv *priv = ddiv->priv;
242+
unsigned long flags = 0;
243+
int value;
244+
u32 val;
245+
int ret;
246+
247+
value = divider_get_val(rate, parent_rate, divider->table,
248+
divider->width, divider->flags);
249+
if (value < 0)
250+
return value;
251+
252+
spin_lock_irqsave(divider->lock, flags);
253+
254+
ret = rzv2h_cpg_wait_ddiv_clk_update_done(priv->base, ddiv->mon);
255+
if (ret)
256+
goto ddiv_timeout;
257+
258+
val = readl(divider->reg) | DDIV_DIVCTL_WEN(divider->shift);
259+
val &= ~(clk_div_mask(divider->width) << divider->shift);
260+
val |= (u32)value << divider->shift;
261+
writel(val, divider->reg);
262+
263+
ret = rzv2h_cpg_wait_ddiv_clk_update_done(priv->base, ddiv->mon);
264+
if (ret)
265+
goto ddiv_timeout;
266+
267+
spin_unlock_irqrestore(divider->lock, flags);
268+
269+
return 0;
270+
271+
ddiv_timeout:
272+
spin_unlock_irqrestore(divider->lock, flags);
273+
return ret;
274+
}
275+
276+
static const struct clk_ops rzv2h_ddiv_clk_divider_ops = {
277+
.recalc_rate = rzv2h_ddiv_recalc_rate,
278+
.round_rate = rzv2h_ddiv_round_rate,
279+
.determine_rate = rzv2h_ddiv_determine_rate,
280+
.set_rate = rzv2h_ddiv_set_rate,
281+
};
282+
283+
static struct clk * __init
284+
rzv2h_cpg_ddiv_clk_register(const struct cpg_core_clk *core,
285+
struct rzv2h_cpg_priv *priv)
286+
{
287+
struct ddiv cfg_ddiv = core->cfg.ddiv;
288+
struct clk_init_data init = {};
289+
struct device *dev = priv->dev;
290+
u8 shift = cfg_ddiv.shift;
291+
u8 width = cfg_ddiv.width;
292+
const struct clk *parent;
293+
const char *parent_name;
294+
struct clk_divider *div;
295+
struct ddiv_clk *ddiv;
296+
int ret;
297+
298+
parent = priv->clks[core->parent];
299+
if (IS_ERR(parent))
300+
return ERR_CAST(parent);
301+
302+
parent_name = __clk_get_name(parent);
303+
304+
if ((shift + width) > 16)
305+
return ERR_PTR(-EINVAL);
306+
307+
ddiv = devm_kzalloc(priv->dev, sizeof(*ddiv), GFP_KERNEL);
308+
if (!ddiv)
309+
return ERR_PTR(-ENOMEM);
310+
311+
init.name = core->name;
312+
init.ops = &rzv2h_ddiv_clk_divider_ops;
313+
init.parent_names = &parent_name;
314+
init.num_parents = 1;
315+
316+
ddiv->priv = priv;
317+
ddiv->mon = cfg_ddiv.monbit;
318+
div = &ddiv->div;
319+
div->reg = priv->base + cfg_ddiv.offset;
320+
div->shift = shift;
321+
div->width = width;
322+
div->flags = core->flag;
323+
div->lock = &priv->rmw_lock;
324+
div->hw.init = &init;
325+
div->table = core->dtable;
326+
327+
ret = devm_clk_hw_register(dev, &div->hw);
328+
if (ret)
329+
return ERR_PTR(ret);
330+
331+
return div->hw.clk;
332+
}
333+
176334
static struct clk
177335
*rzv2h_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec,
178336
void *data)
@@ -254,6 +412,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
254412
case CLK_TYPE_PLL:
255413
clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops);
256414
break;
415+
case CLK_TYPE_DDIV:
416+
clk = rzv2h_cpg_ddiv_clk_register(core, priv);
417+
break;
257418
default:
258419
goto fail;
259420
}
@@ -612,6 +773,8 @@ static int __init rzv2h_cpg_probe(struct platform_device *pdev)
612773
if (!priv)
613774
return -ENOMEM;
614775

776+
spin_lock_init(&priv->rmw_lock);
777+
615778
priv->dev = dev;
616779

617780
priv->base = devm_platform_ioremap_resource(pdev, 0);

drivers/clk/renesas/rzv2h-cpg.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,29 @@
88
#ifndef __RENESAS_RZV2H_CPG_H__
99
#define __RENESAS_RZV2H_CPG_H__
1010

11+
/**
12+
* struct ddiv - Structure for dynamic switching divider
13+
*
14+
* @offset: register offset
15+
* @shift: position of the divider bit
16+
* @width: width of the divider
17+
* @monbit: monitor bit in CPG_CLKSTATUS0 register
18+
*/
19+
struct ddiv {
20+
unsigned int offset:11;
21+
unsigned int shift:4;
22+
unsigned int width:4;
23+
unsigned int monbit:5;
24+
};
25+
26+
#define DDIV_PACK(_offset, _shift, _width, _monbit) \
27+
((struct ddiv){ \
28+
.offset = _offset, \
29+
.shift = _shift, \
30+
.width = _width, \
31+
.monbit = _monbit \
32+
})
33+
1134
/**
1235
* Definitions of CPG Core Clocks
1336
*
@@ -23,14 +46,20 @@ struct cpg_core_clk {
2346
unsigned int div;
2447
unsigned int mult;
2548
unsigned int type;
26-
unsigned int conf;
49+
union {
50+
unsigned int conf;
51+
struct ddiv ddiv;
52+
} cfg;
53+
const struct clk_div_table *dtable;
54+
u32 flag;
2755
};
2856

2957
enum clk_types {
3058
/* Generic */
3159
CLK_TYPE_IN, /* External Clock Input */
3260
CLK_TYPE_FF, /* Fixed Factor Clock */
3361
CLK_TYPE_PLL,
62+
CLK_TYPE_DDIV, /* Dynamic Switching Divider */
3463
};
3564

3665
/* BIT(31) indicates if CLK1/2 are accessible or not */
@@ -44,11 +73,17 @@ enum clk_types {
4473
#define DEF_BASE(_name, _id, _type, _parent...) \
4574
DEF_TYPE(_name, _id, _type, .parent = _parent)
4675
#define DEF_PLL(_name, _id, _parent, _conf) \
47-
DEF_TYPE(_name, _id, CLK_TYPE_PLL, .parent = _parent, .conf = _conf)
76+
DEF_TYPE(_name, _id, CLK_TYPE_PLL, .parent = _parent, .cfg.conf = _conf)
4877
#define DEF_INPUT(_name, _id) \
4978
DEF_TYPE(_name, _id, CLK_TYPE_IN)
5079
#define DEF_FIXED(_name, _id, _parent, _mult, _div) \
5180
DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
81+
#define DEF_DDIV(_name, _id, _parent, _ddiv_packed, _dtable) \
82+
DEF_TYPE(_name, _id, CLK_TYPE_DDIV, \
83+
.cfg.ddiv = _ddiv_packed, \
84+
.parent = _parent, \
85+
.dtable = _dtable, \
86+
.flag = CLK_DIVIDER_HIWORD_MASK)
5287

5388
/**
5489
* struct rzv2h_mod_clk - Module Clocks definitions

0 commit comments

Comments
 (0)