xref: /linux/drivers/clk/clk-plldig.c (revision d37010a3c162f23e47a11a8f5946dbd974999c42)
1*d37010a3SWen He // SPDX-License-Identifier: GPL-2.0
2*d37010a3SWen He /*
3*d37010a3SWen He  * Copyright 2019 NXP
4*d37010a3SWen He  *
5*d37010a3SWen He  * Clock driver for LS1028A Display output interfaces(LCD, DPHY).
6*d37010a3SWen He  */
7*d37010a3SWen He 
8*d37010a3SWen He #include <linux/clk-provider.h>
9*d37010a3SWen He #include <linux/device.h>
10*d37010a3SWen He #include <linux/module.h>
11*d37010a3SWen He #include <linux/err.h>
12*d37010a3SWen He #include <linux/io.h>
13*d37010a3SWen He #include <linux/iopoll.h>
14*d37010a3SWen He #include <linux/of.h>
15*d37010a3SWen He #include <linux/of_address.h>
16*d37010a3SWen He #include <linux/of_device.h>
17*d37010a3SWen He #include <linux/platform_device.h>
18*d37010a3SWen He #include <linux/slab.h>
19*d37010a3SWen He #include <linux/bitfield.h>
20*d37010a3SWen He 
21*d37010a3SWen He /* PLLDIG register offsets and bit masks */
22*d37010a3SWen He #define PLLDIG_REG_PLLSR            0x24
23*d37010a3SWen He #define PLLDIG_LOCK_MASK            BIT(2)
24*d37010a3SWen He #define PLLDIG_REG_PLLDV            0x28
25*d37010a3SWen He #define PLLDIG_MFD_MASK             GENMASK(7, 0)
26*d37010a3SWen He #define PLLDIG_RFDPHI1_MASK         GENMASK(30, 25)
27*d37010a3SWen He #define PLLDIG_REG_PLLFM            0x2c
28*d37010a3SWen He #define PLLDIG_SSCGBYP_ENABLE       BIT(30)
29*d37010a3SWen He #define PLLDIG_REG_PLLFD            0x30
30*d37010a3SWen He #define PLLDIG_FDEN                 BIT(30)
31*d37010a3SWen He #define PLLDIG_FRAC_MASK            GENMASK(15, 0)
32*d37010a3SWen He #define PLLDIG_REG_PLLCAL1          0x38
33*d37010a3SWen He #define PLLDIG_REG_PLLCAL2          0x3c
34*d37010a3SWen He 
35*d37010a3SWen He /* Range of the VCO frequencies, in Hz */
36*d37010a3SWen He #define PLLDIG_MIN_VCO_FREQ         650000000
37*d37010a3SWen He #define PLLDIG_MAX_VCO_FREQ         1300000000
38*d37010a3SWen He 
39*d37010a3SWen He /* Range of the output frequencies, in Hz */
40*d37010a3SWen He #define PHI1_MIN_FREQ               27000000
41*d37010a3SWen He #define PHI1_MAX_FREQ               600000000
42*d37010a3SWen He 
43*d37010a3SWen He /* Maximum value of the reduced frequency divider */
44*d37010a3SWen He #define MAX_RFDPHI1          63UL
45*d37010a3SWen He 
46*d37010a3SWen He /* Best value of multiplication factor divider */
47*d37010a3SWen He #define PLLDIG_DEFAULT_MFD   44
48*d37010a3SWen He 
49*d37010a3SWen He /*
50*d37010a3SWen He  * Denominator part of the fractional part of the
51*d37010a3SWen He  * loop multiplication factor.
52*d37010a3SWen He  */
53*d37010a3SWen He #define MFDEN          20480
54*d37010a3SWen He 
55*d37010a3SWen He static const struct clk_parent_data parent_data[] = {
56*d37010a3SWen He 	{ .index = 0 },
57*d37010a3SWen He };
58*d37010a3SWen He 
59*d37010a3SWen He struct clk_plldig {
60*d37010a3SWen He 	struct clk_hw hw;
61*d37010a3SWen He 	void __iomem *regs;
62*d37010a3SWen He 	unsigned int vco_freq;
63*d37010a3SWen He };
64*d37010a3SWen He 
65*d37010a3SWen He #define to_clk_plldig(_hw)	container_of(_hw, struct clk_plldig, hw)
66*d37010a3SWen He 
67*d37010a3SWen He static int plldig_enable(struct clk_hw *hw)
68*d37010a3SWen He {
69*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
70*d37010a3SWen He 	u32 val;
71*d37010a3SWen He 
72*d37010a3SWen He 	val = readl(data->regs + PLLDIG_REG_PLLFM);
73*d37010a3SWen He 	/*
74*d37010a3SWen He 	 * Use Bypass mode with PLL off by default, the frequency overshoot
75*d37010a3SWen He 	 * detector output was disable. SSCG Bypass mode should be enable.
76*d37010a3SWen He 	 */
77*d37010a3SWen He 	val |= PLLDIG_SSCGBYP_ENABLE;
78*d37010a3SWen He 	writel(val, data->regs + PLLDIG_REG_PLLFM);
79*d37010a3SWen He 
80*d37010a3SWen He 	return 0;
81*d37010a3SWen He }
82*d37010a3SWen He 
83*d37010a3SWen He static void plldig_disable(struct clk_hw *hw)
84*d37010a3SWen He {
85*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
86*d37010a3SWen He 	u32 val;
87*d37010a3SWen He 
88*d37010a3SWen He 	val = readl(data->regs + PLLDIG_REG_PLLFM);
89*d37010a3SWen He 
90*d37010a3SWen He 	val &= ~PLLDIG_SSCGBYP_ENABLE;
91*d37010a3SWen He 	val |= FIELD_PREP(PLLDIG_SSCGBYP_ENABLE, 0x0);
92*d37010a3SWen He 
93*d37010a3SWen He 	writel(val, data->regs + PLLDIG_REG_PLLFM);
94*d37010a3SWen He }
95*d37010a3SWen He 
96*d37010a3SWen He static int plldig_is_enabled(struct clk_hw *hw)
97*d37010a3SWen He {
98*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
99*d37010a3SWen He 
100*d37010a3SWen He 	return readl(data->regs + PLLDIG_REG_PLLFM) &
101*d37010a3SWen He 			      PLLDIG_SSCGBYP_ENABLE;
102*d37010a3SWen He }
103*d37010a3SWen He 
104*d37010a3SWen He static unsigned long plldig_recalc_rate(struct clk_hw *hw,
105*d37010a3SWen He 					unsigned long parent_rate)
106*d37010a3SWen He {
107*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
108*d37010a3SWen He 	u32 val, rfdphi1;
109*d37010a3SWen He 
110*d37010a3SWen He 	val = readl(data->regs + PLLDIG_REG_PLLDV);
111*d37010a3SWen He 
112*d37010a3SWen He 	/* Check if PLL is bypassed */
113*d37010a3SWen He 	if (val & PLLDIG_SSCGBYP_ENABLE)
114*d37010a3SWen He 		return parent_rate;
115*d37010a3SWen He 
116*d37010a3SWen He 	rfdphi1 = FIELD_GET(PLLDIG_RFDPHI1_MASK, val);
117*d37010a3SWen He 
118*d37010a3SWen He 	/*
119*d37010a3SWen He 	 * If RFDPHI1 has a value of 1 the VCO frequency is also divided by
120*d37010a3SWen He 	 * one.
121*d37010a3SWen He 	 */
122*d37010a3SWen He 	if (!rfdphi1)
123*d37010a3SWen He 		rfdphi1 = 1;
124*d37010a3SWen He 
125*d37010a3SWen He 	return DIV_ROUND_UP(data->vco_freq, rfdphi1);
126*d37010a3SWen He }
127*d37010a3SWen He 
128*d37010a3SWen He static unsigned long plldig_calc_target_div(unsigned long vco_freq,
129*d37010a3SWen He 					    unsigned long target_rate)
130*d37010a3SWen He {
131*d37010a3SWen He 	unsigned long div;
132*d37010a3SWen He 
133*d37010a3SWen He 	div = DIV_ROUND_CLOSEST(vco_freq, target_rate);
134*d37010a3SWen He 	div = clamp(div, 1UL, MAX_RFDPHI1);
135*d37010a3SWen He 
136*d37010a3SWen He 	return div;
137*d37010a3SWen He }
138*d37010a3SWen He 
139*d37010a3SWen He static int plldig_determine_rate(struct clk_hw *hw,
140*d37010a3SWen He 				 struct clk_rate_request *req)
141*d37010a3SWen He {
142*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
143*d37010a3SWen He 	unsigned int div;
144*d37010a3SWen He 
145*d37010a3SWen He 	req->rate = clamp(req->rate, PHI1_MIN_FREQ, PHI1_MAX_FREQ);
146*d37010a3SWen He 	div = plldig_calc_target_div(data->vco_freq, req->rate);
147*d37010a3SWen He 	req->rate = DIV_ROUND_UP(data->vco_freq, div);
148*d37010a3SWen He 
149*d37010a3SWen He 	return 0;
150*d37010a3SWen He }
151*d37010a3SWen He 
152*d37010a3SWen He static int plldig_set_rate(struct clk_hw *hw, unsigned long rate,
153*d37010a3SWen He 		unsigned long parent_rate)
154*d37010a3SWen He {
155*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
156*d37010a3SWen He 	unsigned int val, cond;
157*d37010a3SWen He 	unsigned int rfdphi1;
158*d37010a3SWen He 
159*d37010a3SWen He 	rate = clamp(rate, PHI1_MIN_FREQ, PHI1_MAX_FREQ);
160*d37010a3SWen He 	rfdphi1 = plldig_calc_target_div(data->vco_freq, rate);
161*d37010a3SWen He 
162*d37010a3SWen He 	/* update the divider value */
163*d37010a3SWen He 	val = readl(data->regs + PLLDIG_REG_PLLDV);
164*d37010a3SWen He 	val &= ~PLLDIG_RFDPHI1_MASK;
165*d37010a3SWen He 	val |= FIELD_PREP(PLLDIG_RFDPHI1_MASK, rfdphi1);
166*d37010a3SWen He 	writel(val, data->regs + PLLDIG_REG_PLLDV);
167*d37010a3SWen He 
168*d37010a3SWen He 	/* waiting for old lock state to clear */
169*d37010a3SWen He 	udelay(200);
170*d37010a3SWen He 
171*d37010a3SWen He 	/* Wait until PLL is locked or timeout */
172*d37010a3SWen He 	return readl_poll_timeout_atomic(data->regs + PLLDIG_REG_PLLSR, cond,
173*d37010a3SWen He 					 cond & PLLDIG_LOCK_MASK, 0,
174*d37010a3SWen He 					 USEC_PER_MSEC);
175*d37010a3SWen He }
176*d37010a3SWen He 
177*d37010a3SWen He static const struct clk_ops plldig_clk_ops = {
178*d37010a3SWen He 	.enable = plldig_enable,
179*d37010a3SWen He 	.disable = plldig_disable,
180*d37010a3SWen He 	.is_enabled = plldig_is_enabled,
181*d37010a3SWen He 	.recalc_rate = plldig_recalc_rate,
182*d37010a3SWen He 	.determine_rate = plldig_determine_rate,
183*d37010a3SWen He 	.set_rate = plldig_set_rate,
184*d37010a3SWen He };
185*d37010a3SWen He 
186*d37010a3SWen He static int plldig_init(struct clk_hw *hw)
187*d37010a3SWen He {
188*d37010a3SWen He 	struct clk_plldig *data = to_clk_plldig(hw);
189*d37010a3SWen He 	struct clk_hw *parent = clk_hw_get_parent(hw);
190*d37010a3SWen He 	unsigned long parent_rate = clk_hw_get_rate(parent);
191*d37010a3SWen He 	unsigned long val;
192*d37010a3SWen He 	unsigned long long lltmp;
193*d37010a3SWen He 	unsigned int mfd, fracdiv = 0;
194*d37010a3SWen He 
195*d37010a3SWen He 	if (!parent)
196*d37010a3SWen He 		return -EINVAL;
197*d37010a3SWen He 
198*d37010a3SWen He 	if (data->vco_freq) {
199*d37010a3SWen He 		mfd = data->vco_freq / parent_rate;
200*d37010a3SWen He 		lltmp = data->vco_freq % parent_rate;
201*d37010a3SWen He 		lltmp *= MFDEN;
202*d37010a3SWen He 		do_div(lltmp, parent_rate);
203*d37010a3SWen He 		fracdiv = lltmp;
204*d37010a3SWen He 	} else {
205*d37010a3SWen He 		mfd = PLLDIG_DEFAULT_MFD;
206*d37010a3SWen He 		data->vco_freq = parent_rate * mfd;
207*d37010a3SWen He 	}
208*d37010a3SWen He 
209*d37010a3SWen He 	val = FIELD_PREP(PLLDIG_MFD_MASK, mfd);
210*d37010a3SWen He 	writel(val, data->regs + PLLDIG_REG_PLLDV);
211*d37010a3SWen He 
212*d37010a3SWen He 	/* Enable fractional divider */
213*d37010a3SWen He 	if (fracdiv) {
214*d37010a3SWen He 		val = FIELD_PREP(PLLDIG_FRAC_MASK, fracdiv);
215*d37010a3SWen He 		val |= PLLDIG_FDEN;
216*d37010a3SWen He 		writel(val, data->regs + PLLDIG_REG_PLLFD);
217*d37010a3SWen He 	}
218*d37010a3SWen He 
219*d37010a3SWen He 	return 0;
220*d37010a3SWen He }
221*d37010a3SWen He 
222*d37010a3SWen He static int plldig_clk_probe(struct platform_device *pdev)
223*d37010a3SWen He {
224*d37010a3SWen He 	struct clk_plldig *data;
225*d37010a3SWen He 	struct device *dev = &pdev->dev;
226*d37010a3SWen He 	int ret;
227*d37010a3SWen He 
228*d37010a3SWen He 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
229*d37010a3SWen He 	if (!data)
230*d37010a3SWen He 		return -ENOMEM;
231*d37010a3SWen He 
232*d37010a3SWen He 	data->regs = devm_platform_ioremap_resource(pdev, 0);
233*d37010a3SWen He 	if (IS_ERR(data->regs))
234*d37010a3SWen He 		return PTR_ERR(data->regs);
235*d37010a3SWen He 
236*d37010a3SWen He 	data->hw.init = CLK_HW_INIT_PARENTS_DATA("dpclk",
237*d37010a3SWen He 						 parent_data,
238*d37010a3SWen He 						 &plldig_clk_ops,
239*d37010a3SWen He 						 0);
240*d37010a3SWen He 
241*d37010a3SWen He 	ret = devm_clk_hw_register(dev, &data->hw);
242*d37010a3SWen He 	if (ret) {
243*d37010a3SWen He 		dev_err(dev, "failed to register %s clock\n",
244*d37010a3SWen He 						dev->of_node->name);
245*d37010a3SWen He 		return ret;
246*d37010a3SWen He 	}
247*d37010a3SWen He 
248*d37010a3SWen He 	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
249*d37010a3SWen He 					  &data->hw);
250*d37010a3SWen He 	if (ret) {
251*d37010a3SWen He 		dev_err(dev, "unable to add clk provider\n");
252*d37010a3SWen He 		return ret;
253*d37010a3SWen He 	}
254*d37010a3SWen He 
255*d37010a3SWen He 	/*
256*d37010a3SWen He 	 * The frequency of the VCO cannot be changed during runtime.
257*d37010a3SWen He 	 * Therefore, let the user specify a desired frequency.
258*d37010a3SWen He 	 */
259*d37010a3SWen He 	if (!of_property_read_u32(dev->of_node, "fsl,vco-hz",
260*d37010a3SWen He 				  &data->vco_freq)) {
261*d37010a3SWen He 		if (data->vco_freq < PLLDIG_MIN_VCO_FREQ ||
262*d37010a3SWen He 		    data->vco_freq > PLLDIG_MAX_VCO_FREQ)
263*d37010a3SWen He 			return -EINVAL;
264*d37010a3SWen He 	}
265*d37010a3SWen He 
266*d37010a3SWen He 	return plldig_init(&data->hw);
267*d37010a3SWen He }
268*d37010a3SWen He 
269*d37010a3SWen He static const struct of_device_id plldig_clk_id[] = {
270*d37010a3SWen He 	{ .compatible = "fsl,ls1028a-plldig" },
271*d37010a3SWen He 	{ }
272*d37010a3SWen He };
273*d37010a3SWen He MODULE_DEVICE_TABLE(of, plldig_clk_id);
274*d37010a3SWen He 
275*d37010a3SWen He static struct platform_driver plldig_clk_driver = {
276*d37010a3SWen He 	.driver = {
277*d37010a3SWen He 		.name = "plldig-clock",
278*d37010a3SWen He 		.of_match_table = plldig_clk_id,
279*d37010a3SWen He 	},
280*d37010a3SWen He 	.probe = plldig_clk_probe,
281*d37010a3SWen He };
282*d37010a3SWen He module_platform_driver(plldig_clk_driver);
283*d37010a3SWen He 
284*d37010a3SWen He MODULE_LICENSE("GPL v2");
285*d37010a3SWen He MODULE_AUTHOR("Wen He <wen.he_1@nxp.com>");
286*d37010a3SWen He MODULE_DESCRIPTION("LS1028A Display output interface pixel clock driver");
287