1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
4 * Copyright 2017~2018 NXP
6 * Author: Dong Aisheng <aisheng.dong@nxp.com>
10 #include <linux/clk-provider.h>
11 #include <linux/err.h>
13 #include <linux/iopoll.h>
14 #include <linux/slab.h>
19 * struct clk_pfdv2 - IMX PFD clock
21 * @reg: PFD register address
22 * @gate_bit: Gate bit offset
23 * @vld_bit: Valid bit offset
24 * @frac_off: PLL Fractional Divider offset
35 #define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw)
37 #define CLK_PFDV2_FRAC_MASK 0x3f
39 #define LOCK_TIMEOUT_US USEC_PER_MSEC
41 static DEFINE_SPINLOCK(pfd_lock
);
43 static int clk_pfdv2_wait(struct clk_pfdv2
*pfd
)
47 return readl_poll_timeout(pfd
->reg
, val
, val
& (1 << pfd
->vld_bit
),
51 static int clk_pfdv2_enable(struct clk_hw
*hw
)
53 struct clk_pfdv2
*pfd
= to_clk_pfdv2(hw
);
57 spin_lock_irqsave(&pfd_lock
, flags
);
58 val
= readl_relaxed(pfd
->reg
);
59 val
&= ~(1 << pfd
->gate_bit
);
60 writel_relaxed(val
, pfd
->reg
);
61 spin_unlock_irqrestore(&pfd_lock
, flags
);
63 return clk_pfdv2_wait(pfd
);
66 static void clk_pfdv2_disable(struct clk_hw
*hw
)
68 struct clk_pfdv2
*pfd
= to_clk_pfdv2(hw
);
72 spin_lock_irqsave(&pfd_lock
, flags
);
73 val
= readl_relaxed(pfd
->reg
);
74 val
|= (1 << pfd
->gate_bit
);
75 writel_relaxed(val
, pfd
->reg
);
76 spin_unlock_irqrestore(&pfd_lock
, flags
);
79 static unsigned long clk_pfdv2_recalc_rate(struct clk_hw
*hw
,
80 unsigned long parent_rate
)
82 struct clk_pfdv2
*pfd
= to_clk_pfdv2(hw
);
83 u64 tmp
= parent_rate
;
86 frac
= (readl_relaxed(pfd
->reg
) >> pfd
->frac_off
)
87 & CLK_PFDV2_FRAC_MASK
;
90 pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n",
101 static int clk_pfdv2_determine_rate(struct clk_hw
*hw
,
102 struct clk_rate_request
*req
)
104 unsigned long parent_rates
[] = {
107 req
->best_parent_rate
109 unsigned long best_rate
= -1UL, rate
= req
->rate
;
110 unsigned long best_parent_rate
= req
->best_parent_rate
;
115 for (i
= 0; i
< ARRAY_SIZE(parent_rates
); i
++) {
116 tmp
= parent_rates
[i
];
117 tmp
= tmp
* 18 + rate
/ 2;
126 tmp
= parent_rates
[i
];
130 if (abs(tmp
- req
->rate
) < abs(best_rate
- req
->rate
)) {
132 best_parent_rate
= parent_rates
[i
];
136 req
->best_parent_rate
= best_parent_rate
;
137 req
->rate
= best_rate
;
142 static int clk_pfdv2_is_enabled(struct clk_hw
*hw
)
144 struct clk_pfdv2
*pfd
= to_clk_pfdv2(hw
);
146 if (readl_relaxed(pfd
->reg
) & (1 << pfd
->gate_bit
))
152 static int clk_pfdv2_set_rate(struct clk_hw
*hw
, unsigned long rate
,
153 unsigned long parent_rate
)
155 struct clk_pfdv2
*pfd
= to_clk_pfdv2(hw
);
157 u64 tmp
= parent_rate
;
164 /* PFD can NOT change rate without gating */
165 WARN_ON(clk_pfdv2_is_enabled(hw
));
167 tmp
= tmp
* 18 + rate
/ 2;
175 spin_lock_irqsave(&pfd_lock
, flags
);
176 val
= readl_relaxed(pfd
->reg
);
177 val
&= ~(CLK_PFDV2_FRAC_MASK
<< pfd
->frac_off
);
178 val
|= frac
<< pfd
->frac_off
;
179 writel_relaxed(val
, pfd
->reg
);
180 spin_unlock_irqrestore(&pfd_lock
, flags
);
185 static const struct clk_ops clk_pfdv2_ops
= {
186 .enable
= clk_pfdv2_enable
,
187 .disable
= clk_pfdv2_disable
,
188 .recalc_rate
= clk_pfdv2_recalc_rate
,
189 .determine_rate
= clk_pfdv2_determine_rate
,
190 .set_rate
= clk_pfdv2_set_rate
,
191 .is_enabled
= clk_pfdv2_is_enabled
,
194 struct clk_hw
*imx_clk_hw_pfdv2(const char *name
, const char *parent_name
,
195 void __iomem
*reg
, u8 idx
)
197 struct clk_init_data init
;
198 struct clk_pfdv2
*pfd
;
204 pfd
= kzalloc(sizeof(*pfd
), GFP_KERNEL
);
206 return ERR_PTR(-ENOMEM
);
209 pfd
->gate_bit
= (idx
+ 1) * 8 - 1;
210 pfd
->vld_bit
= pfd
->gate_bit
- 1;
211 pfd
->frac_off
= idx
* 8;
214 init
.ops
= &clk_pfdv2_ops
;
215 init
.parent_names
= &parent_name
;
216 init
.num_parents
= 1;
217 init
.flags
= CLK_SET_RATE_GATE
| CLK_SET_RATE_PARENT
;
219 pfd
->hw
.init
= &init
;
222 ret
= clk_hw_register(NULL
, hw
);