1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 Intel Corporation.
4 * Zhu YiXin <yixin.zhu@intel.com>
5 * Rahul Tanwar <rahul.tanwar@intel.com>
8 #include <linux/clk-provider.h>
9 #include <linux/delay.h>
10 #include <linux/device.h>
11 #include <linux/iopoll.h>
16 #define to_lgm_clk_pll(_hw) container_of(_hw, struct lgm_clk_pll, hw)
17 #define PLL_REF_DIV(x) ((x) + 0x08)
21 * rate = (prate * mult + (prate * frac) / frac_div) / div
24 lgm_pll_calc_rate(unsigned long prate
, unsigned int mult
,
25 unsigned int div
, unsigned int frac
, unsigned int frac_div
)
27 u64 crate
, frate
, rate64
;
30 crate
= rate64
* mult
;
31 frate
= rate64
* frac
;
32 do_div(frate
, frac_div
);
39 static unsigned long lgm_pll_recalc_rate(struct clk_hw
*hw
, unsigned long prate
)
41 struct lgm_clk_pll
*pll
= to_lgm_clk_pll(hw
);
42 unsigned int div
, mult
, frac
;
45 spin_lock_irqsave(&pll
->lock
, flags
);
46 mult
= lgm_get_clk_val(pll
->membase
, PLL_REF_DIV(pll
->reg
), 0, 12);
47 div
= lgm_get_clk_val(pll
->membase
, PLL_REF_DIV(pll
->reg
), 18, 6);
48 frac
= lgm_get_clk_val(pll
->membase
, pll
->reg
, 2, 24);
49 spin_unlock_irqrestore(&pll
->lock
, flags
);
51 if (pll
->type
== TYPE_LJPLL
)
54 return lgm_pll_calc_rate(prate
, mult
, div
, frac
, BIT(24));
57 static int lgm_pll_is_enabled(struct clk_hw
*hw
)
59 struct lgm_clk_pll
*pll
= to_lgm_clk_pll(hw
);
63 spin_lock_irqsave(&pll
->lock
, flags
);
64 ret
= lgm_get_clk_val(pll
->membase
, pll
->reg
, 0, 1);
65 spin_unlock_irqrestore(&pll
->lock
, flags
);
70 static int lgm_pll_enable(struct clk_hw
*hw
)
72 struct lgm_clk_pll
*pll
= to_lgm_clk_pll(hw
);
77 spin_lock_irqsave(&pll
->lock
, flags
);
78 lgm_set_clk_val(pll
->membase
, pll
->reg
, 0, 1, 1);
79 ret
= readl_poll_timeout_atomic(pll
->membase
+ pll
->reg
,
80 val
, (val
& 0x1), 1, 100);
81 spin_unlock_irqrestore(&pll
->lock
, flags
);
86 static void lgm_pll_disable(struct clk_hw
*hw
)
88 struct lgm_clk_pll
*pll
= to_lgm_clk_pll(hw
);
91 spin_lock_irqsave(&pll
->lock
, flags
);
92 lgm_set_clk_val(pll
->membase
, pll
->reg
, 0, 1, 0);
93 spin_unlock_irqrestore(&pll
->lock
, flags
);
96 static const struct clk_ops lgm_pll_ops
= {
97 .recalc_rate
= lgm_pll_recalc_rate
,
98 .is_enabled
= lgm_pll_is_enabled
,
99 .enable
= lgm_pll_enable
,
100 .disable
= lgm_pll_disable
,
103 static struct clk_hw
*
104 lgm_clk_register_pll(struct lgm_clk_provider
*ctx
,
105 const struct lgm_pll_clk_data
*list
)
107 struct clk_init_data init
= {};
108 struct lgm_clk_pll
*pll
;
109 struct device
*dev
= ctx
->dev
;
113 init
.ops
= &lgm_pll_ops
;
114 init
.name
= list
->name
;
115 init
.flags
= list
->flags
;
116 init
.parent_data
= list
->parent_data
;
117 init
.num_parents
= list
->num_parents
;
119 pll
= devm_kzalloc(dev
, sizeof(*pll
), GFP_KERNEL
);
121 return ERR_PTR(-ENOMEM
);
123 pll
->membase
= ctx
->membase
;
124 pll
->lock
= ctx
->lock
;
125 pll
->reg
= list
->reg
;
126 pll
->flags
= list
->flags
;
127 pll
->type
= list
->type
;
128 pll
->hw
.init
= &init
;
131 ret
= devm_clk_hw_register(dev
, hw
);
138 int lgm_clk_register_plls(struct lgm_clk_provider
*ctx
,
139 const struct lgm_pll_clk_data
*list
,
145 for (i
= 0; i
< nr_clk
; i
++, list
++) {
146 hw
= lgm_clk_register_pll(ctx
, list
);
148 dev_err(ctx
->dev
, "failed to register pll: %s\n",
152 ctx
->clk_data
.hws
[list
->id
] = hw
;