xref: /OK3568_Linux_fs/kernel/drivers/clk/clk-cs2000-cp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * CS2000  --  CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2015 Renesas Electronics Corporation
6*4882a593Smuzhiyun  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/clk-provider.h>
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/i2c.h>
12*4882a593Smuzhiyun #include <linux/of_device.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #define CH_MAX 4
16*4882a593Smuzhiyun #define RATIO_REG_SIZE 4
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define DEVICE_ID	0x1
19*4882a593Smuzhiyun #define DEVICE_CTRL	0x2
20*4882a593Smuzhiyun #define DEVICE_CFG1	0x3
21*4882a593Smuzhiyun #define DEVICE_CFG2	0x4
22*4882a593Smuzhiyun #define GLOBAL_CFG	0x5
23*4882a593Smuzhiyun #define Ratio_Add(x, nth)	(6 + (x * 4) + (nth))
24*4882a593Smuzhiyun #define Ratio_Val(x, nth)	((x >> (24 - (8 * nth))) & 0xFF)
25*4882a593Smuzhiyun #define Val_Ratio(x, nth)	((x & 0xFF) << (24 - (8 * nth)))
26*4882a593Smuzhiyun #define FUNC_CFG1	0x16
27*4882a593Smuzhiyun #define FUNC_CFG2	0x17
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /* DEVICE_ID */
30*4882a593Smuzhiyun #define REVISION_MASK	(0x7)
31*4882a593Smuzhiyun #define REVISION_B2_B3	(0x4)
32*4882a593Smuzhiyun #define REVISION_C1	(0x6)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* DEVICE_CTRL */
35*4882a593Smuzhiyun #define PLL_UNLOCK	(1 << 7)
36*4882a593Smuzhiyun #define AUXOUTDIS	(1 << 1)
37*4882a593Smuzhiyun #define CLKOUTDIS	(1 << 0)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun /* DEVICE_CFG1 */
40*4882a593Smuzhiyun #define RSEL(x)		(((x) & 0x3) << 3)
41*4882a593Smuzhiyun #define RSEL_MASK	RSEL(0x3)
42*4882a593Smuzhiyun #define ENDEV1		(0x1)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /* DEVICE_CFG2 */
45*4882a593Smuzhiyun #define AUTORMOD	(1 << 3)
46*4882a593Smuzhiyun #define LOCKCLK(x)	(((x) & 0x3) << 1)
47*4882a593Smuzhiyun #define LOCKCLK_MASK	LOCKCLK(0x3)
48*4882a593Smuzhiyun #define FRACNSRC_MASK	(1 << 0)
49*4882a593Smuzhiyun #define FRACNSRC_STATIC		(0 << 0)
50*4882a593Smuzhiyun #define FRACNSRC_DYNAMIC	(1 << 1)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /* GLOBAL_CFG */
53*4882a593Smuzhiyun #define ENDEV2		(0x1)
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* FUNC_CFG1 */
56*4882a593Smuzhiyun #define CLKSKIPEN	(1 << 7)
57*4882a593Smuzhiyun #define REFCLKDIV(x)	(((x) & 0x3) << 3)
58*4882a593Smuzhiyun #define REFCLKDIV_MASK	REFCLKDIV(0x3)
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /* FUNC_CFG2 */
61*4882a593Smuzhiyun #define LFRATIO_MASK	(1 << 3)
62*4882a593Smuzhiyun #define LFRATIO_20_12	(0 << 3)
63*4882a593Smuzhiyun #define LFRATIO_12_20	(1 << 3)
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define CH_SIZE_ERR(ch)		((ch < 0) || (ch >= CH_MAX))
66*4882a593Smuzhiyun #define hw_to_priv(_hw)		container_of(_hw, struct cs2000_priv, hw)
67*4882a593Smuzhiyun #define priv_to_client(priv)	(priv->client)
68*4882a593Smuzhiyun #define priv_to_dev(priv)	(&(priv_to_client(priv)->dev))
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define CLK_IN	0
71*4882a593Smuzhiyun #define REF_CLK	1
72*4882a593Smuzhiyun #define CLK_MAX 2
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun struct cs2000_priv {
75*4882a593Smuzhiyun 	struct clk_hw hw;
76*4882a593Smuzhiyun 	struct i2c_client *client;
77*4882a593Smuzhiyun 	struct clk *clk_in;
78*4882a593Smuzhiyun 	struct clk *ref_clk;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/* suspend/resume */
81*4882a593Smuzhiyun 	unsigned long saved_rate;
82*4882a593Smuzhiyun 	unsigned long saved_parent_rate;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static const struct of_device_id cs2000_of_match[] = {
86*4882a593Smuzhiyun 	{ .compatible = "cirrus,cs2000-cp", },
87*4882a593Smuzhiyun 	{},
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, cs2000_of_match);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static const struct i2c_device_id cs2000_id[] = {
92*4882a593Smuzhiyun 	{ "cs2000-cp", },
93*4882a593Smuzhiyun 	{}
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, cs2000_id);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun #define cs2000_read(priv, addr) \
98*4882a593Smuzhiyun 	i2c_smbus_read_byte_data(priv_to_client(priv), addr)
99*4882a593Smuzhiyun #define cs2000_write(priv, addr, val) \
100*4882a593Smuzhiyun 	i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
101*4882a593Smuzhiyun 
cs2000_bset(struct cs2000_priv * priv,u8 addr,u8 mask,u8 val)102*4882a593Smuzhiyun static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	s32 data;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	data = cs2000_read(priv, addr);
107*4882a593Smuzhiyun 	if (data < 0)
108*4882a593Smuzhiyun 		return data;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	data &= ~mask;
111*4882a593Smuzhiyun 	data |= (val & mask);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	return cs2000_write(priv, addr, data);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
cs2000_enable_dev_config(struct cs2000_priv * priv,bool enable)116*4882a593Smuzhiyun static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	int ret;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
121*4882a593Smuzhiyun 			  enable ? ENDEV1 : 0);
122*4882a593Smuzhiyun 	if (ret < 0)
123*4882a593Smuzhiyun 		return ret;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	ret = cs2000_bset(priv, GLOBAL_CFG,  ENDEV2,
126*4882a593Smuzhiyun 			  enable ? ENDEV2 : 0);
127*4882a593Smuzhiyun 	if (ret < 0)
128*4882a593Smuzhiyun 		return ret;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN,
131*4882a593Smuzhiyun 			  enable ? CLKSKIPEN : 0);
132*4882a593Smuzhiyun 	if (ret < 0)
133*4882a593Smuzhiyun 		return ret;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* FIXME: for Static ratio mode */
136*4882a593Smuzhiyun 	ret = cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK,
137*4882a593Smuzhiyun 			  LFRATIO_12_20);
138*4882a593Smuzhiyun 	if (ret < 0)
139*4882a593Smuzhiyun 		return ret;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
cs2000_clk_in_bound_rate(struct cs2000_priv * priv,u32 rate_in)144*4882a593Smuzhiyun static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
145*4882a593Smuzhiyun 				    u32 rate_in)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	u32 val;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (rate_in >= 32000000 && rate_in < 56000000)
150*4882a593Smuzhiyun 		val = 0x0;
151*4882a593Smuzhiyun 	else if (rate_in >= 16000000 && rate_in < 28000000)
152*4882a593Smuzhiyun 		val = 0x1;
153*4882a593Smuzhiyun 	else if (rate_in >= 8000000 && rate_in < 14000000)
154*4882a593Smuzhiyun 		val = 0x2;
155*4882a593Smuzhiyun 	else
156*4882a593Smuzhiyun 		return -EINVAL;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	return cs2000_bset(priv, FUNC_CFG1,
159*4882a593Smuzhiyun 			   REFCLKDIV_MASK,
160*4882a593Smuzhiyun 			   REFCLKDIV(val));
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
cs2000_wait_pll_lock(struct cs2000_priv * priv)163*4882a593Smuzhiyun static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	struct device *dev = priv_to_dev(priv);
166*4882a593Smuzhiyun 	s32 val;
167*4882a593Smuzhiyun 	unsigned int i;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	for (i = 0; i < 256; i++) {
170*4882a593Smuzhiyun 		val = cs2000_read(priv, DEVICE_CTRL);
171*4882a593Smuzhiyun 		if (val < 0)
172*4882a593Smuzhiyun 			return val;
173*4882a593Smuzhiyun 		if (!(val & PLL_UNLOCK))
174*4882a593Smuzhiyun 			return 0;
175*4882a593Smuzhiyun 		udelay(1);
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	dev_err(dev, "pll lock failed\n");
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	return -ETIMEDOUT;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
cs2000_clk_out_enable(struct cs2000_priv * priv,bool enable)183*4882a593Smuzhiyun static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	/* enable both AUX_OUT, CLK_OUT */
186*4882a593Smuzhiyun 	return cs2000_bset(priv, DEVICE_CTRL,
187*4882a593Smuzhiyun 			   (AUXOUTDIS | CLKOUTDIS),
188*4882a593Smuzhiyun 			   enable ? 0 :
189*4882a593Smuzhiyun 			   (AUXOUTDIS | CLKOUTDIS));
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
cs2000_rate_to_ratio(u32 rate_in,u32 rate_out)192*4882a593Smuzhiyun static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	u64 ratio;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/*
197*4882a593Smuzhiyun 	 * ratio = rate_out / rate_in * 2^20
198*4882a593Smuzhiyun 	 *
199*4882a593Smuzhiyun 	 * To avoid over flow, rate_out is u64.
200*4882a593Smuzhiyun 	 * The result should be u32.
201*4882a593Smuzhiyun 	 */
202*4882a593Smuzhiyun 	ratio = (u64)rate_out << 20;
203*4882a593Smuzhiyun 	do_div(ratio, rate_in);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return ratio;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
cs2000_ratio_to_rate(u32 ratio,u32 rate_in)208*4882a593Smuzhiyun static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	u64 rate_out;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	/*
213*4882a593Smuzhiyun 	 * ratio = rate_out / rate_in * 2^20
214*4882a593Smuzhiyun 	 *
215*4882a593Smuzhiyun 	 * To avoid over flow, rate_out is u64.
216*4882a593Smuzhiyun 	 * The result should be u32 or unsigned long.
217*4882a593Smuzhiyun 	 */
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	rate_out = (u64)ratio * rate_in;
220*4882a593Smuzhiyun 	return rate_out >> 20;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
cs2000_ratio_set(struct cs2000_priv * priv,int ch,u32 rate_in,u32 rate_out)223*4882a593Smuzhiyun static int cs2000_ratio_set(struct cs2000_priv *priv,
224*4882a593Smuzhiyun 			    int ch, u32 rate_in, u32 rate_out)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	u32 val;
227*4882a593Smuzhiyun 	unsigned int i;
228*4882a593Smuzhiyun 	int ret;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (CH_SIZE_ERR(ch))
231*4882a593Smuzhiyun 		return -EINVAL;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	val = cs2000_rate_to_ratio(rate_in, rate_out);
234*4882a593Smuzhiyun 	for (i = 0; i < RATIO_REG_SIZE; i++) {
235*4882a593Smuzhiyun 		ret = cs2000_write(priv,
236*4882a593Smuzhiyun 				   Ratio_Add(ch, i),
237*4882a593Smuzhiyun 				   Ratio_Val(val, i));
238*4882a593Smuzhiyun 		if (ret < 0)
239*4882a593Smuzhiyun 			return ret;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	return 0;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
cs2000_ratio_get(struct cs2000_priv * priv,int ch)245*4882a593Smuzhiyun static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	s32 tmp;
248*4882a593Smuzhiyun 	u32 val;
249*4882a593Smuzhiyun 	unsigned int i;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	val = 0;
252*4882a593Smuzhiyun 	for (i = 0; i < RATIO_REG_SIZE; i++) {
253*4882a593Smuzhiyun 		tmp = cs2000_read(priv, Ratio_Add(ch, i));
254*4882a593Smuzhiyun 		if (tmp < 0)
255*4882a593Smuzhiyun 			return 0;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		val |= Val_Ratio(tmp, i);
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	return val;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
cs2000_ratio_select(struct cs2000_priv * priv,int ch)263*4882a593Smuzhiyun static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	int ret;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (CH_SIZE_ERR(ch))
268*4882a593Smuzhiyun 		return -EINVAL;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/*
271*4882a593Smuzhiyun 	 * FIXME
272*4882a593Smuzhiyun 	 *
273*4882a593Smuzhiyun 	 * this driver supports static ratio mode only at this point.
274*4882a593Smuzhiyun 	 */
275*4882a593Smuzhiyun 	ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
276*4882a593Smuzhiyun 	if (ret < 0)
277*4882a593Smuzhiyun 		return ret;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	ret = cs2000_bset(priv, DEVICE_CFG2,
280*4882a593Smuzhiyun 			  (AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK),
281*4882a593Smuzhiyun 			  (LOCKCLK(ch) | FRACNSRC_STATIC));
282*4882a593Smuzhiyun 	if (ret < 0)
283*4882a593Smuzhiyun 		return ret;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
cs2000_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)288*4882a593Smuzhiyun static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
289*4882a593Smuzhiyun 					unsigned long parent_rate)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	struct cs2000_priv *priv = hw_to_priv(hw);
292*4882a593Smuzhiyun 	int ch = 0; /* it uses ch0 only at this point */
293*4882a593Smuzhiyun 	u32 ratio;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	ratio = cs2000_ratio_get(priv, ch);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return cs2000_ratio_to_rate(ratio, parent_rate);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
cs2000_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)300*4882a593Smuzhiyun static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate,
301*4882a593Smuzhiyun 			      unsigned long *parent_rate)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	u32 ratio;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	ratio = cs2000_rate_to_ratio(*parent_rate, rate);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	return cs2000_ratio_to_rate(ratio, *parent_rate);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
__cs2000_set_rate(struct cs2000_priv * priv,int ch,unsigned long rate,unsigned long parent_rate)310*4882a593Smuzhiyun static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
311*4882a593Smuzhiyun 			     unsigned long rate, unsigned long parent_rate)
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	int ret;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	ret = cs2000_clk_in_bound_rate(priv, parent_rate);
317*4882a593Smuzhiyun 	if (ret < 0)
318*4882a593Smuzhiyun 		return ret;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	ret = cs2000_ratio_set(priv, ch, parent_rate, rate);
321*4882a593Smuzhiyun 	if (ret < 0)
322*4882a593Smuzhiyun 		return ret;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	ret = cs2000_ratio_select(priv, ch);
325*4882a593Smuzhiyun 	if (ret < 0)
326*4882a593Smuzhiyun 		return ret;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	priv->saved_rate	= rate;
329*4882a593Smuzhiyun 	priv->saved_parent_rate	= parent_rate;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	return 0;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
cs2000_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)334*4882a593Smuzhiyun static int cs2000_set_rate(struct clk_hw *hw,
335*4882a593Smuzhiyun 			   unsigned long rate, unsigned long parent_rate)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	struct cs2000_priv *priv = hw_to_priv(hw);
338*4882a593Smuzhiyun 	int ch = 0; /* it uses ch0 only at this point */
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return __cs2000_set_rate(priv, ch, rate, parent_rate);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
cs2000_set_saved_rate(struct cs2000_priv * priv)343*4882a593Smuzhiyun static int cs2000_set_saved_rate(struct cs2000_priv *priv)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	int ch = 0; /* it uses ch0 only at this point */
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return __cs2000_set_rate(priv, ch,
348*4882a593Smuzhiyun 				 priv->saved_rate,
349*4882a593Smuzhiyun 				 priv->saved_parent_rate);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
cs2000_enable(struct clk_hw * hw)352*4882a593Smuzhiyun static int cs2000_enable(struct clk_hw *hw)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun 	struct cs2000_priv *priv = hw_to_priv(hw);
355*4882a593Smuzhiyun 	int ret;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	ret = cs2000_enable_dev_config(priv, true);
358*4882a593Smuzhiyun 	if (ret < 0)
359*4882a593Smuzhiyun 		return ret;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	ret = cs2000_clk_out_enable(priv, true);
362*4882a593Smuzhiyun 	if (ret < 0)
363*4882a593Smuzhiyun 		return ret;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	ret = cs2000_wait_pll_lock(priv);
366*4882a593Smuzhiyun 	if (ret < 0)
367*4882a593Smuzhiyun 		return ret;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	return ret;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
cs2000_disable(struct clk_hw * hw)372*4882a593Smuzhiyun static void cs2000_disable(struct clk_hw *hw)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	struct cs2000_priv *priv = hw_to_priv(hw);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	cs2000_enable_dev_config(priv, false);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	cs2000_clk_out_enable(priv, false);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
cs2000_get_parent(struct clk_hw * hw)381*4882a593Smuzhiyun static u8 cs2000_get_parent(struct clk_hw *hw)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	/* always return REF_CLK */
384*4882a593Smuzhiyun 	return REF_CLK;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun static const struct clk_ops cs2000_ops = {
388*4882a593Smuzhiyun 	.get_parent	= cs2000_get_parent,
389*4882a593Smuzhiyun 	.recalc_rate	= cs2000_recalc_rate,
390*4882a593Smuzhiyun 	.round_rate	= cs2000_round_rate,
391*4882a593Smuzhiyun 	.set_rate	= cs2000_set_rate,
392*4882a593Smuzhiyun 	.prepare	= cs2000_enable,
393*4882a593Smuzhiyun 	.unprepare	= cs2000_disable,
394*4882a593Smuzhiyun };
395*4882a593Smuzhiyun 
cs2000_clk_get(struct cs2000_priv * priv)396*4882a593Smuzhiyun static int cs2000_clk_get(struct cs2000_priv *priv)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct device *dev = priv_to_dev(priv);
399*4882a593Smuzhiyun 	struct clk *clk_in, *ref_clk;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	clk_in = devm_clk_get(dev, "clk_in");
402*4882a593Smuzhiyun 	/* not yet provided */
403*4882a593Smuzhiyun 	if (IS_ERR(clk_in))
404*4882a593Smuzhiyun 		return -EPROBE_DEFER;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	ref_clk = devm_clk_get(dev, "ref_clk");
407*4882a593Smuzhiyun 	/* not yet provided */
408*4882a593Smuzhiyun 	if (IS_ERR(ref_clk))
409*4882a593Smuzhiyun 		return -EPROBE_DEFER;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	priv->clk_in	= clk_in;
412*4882a593Smuzhiyun 	priv->ref_clk	= ref_clk;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
cs2000_clk_register(struct cs2000_priv * priv)417*4882a593Smuzhiyun static int cs2000_clk_register(struct cs2000_priv *priv)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct device *dev = priv_to_dev(priv);
420*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
421*4882a593Smuzhiyun 	struct clk_init_data init;
422*4882a593Smuzhiyun 	const char *name = np->name;
423*4882a593Smuzhiyun 	static const char *parent_names[CLK_MAX];
424*4882a593Smuzhiyun 	int ch = 0; /* it uses ch0 only at this point */
425*4882a593Smuzhiyun 	int rate;
426*4882a593Smuzhiyun 	int ret;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	of_property_read_string(np, "clock-output-names", &name);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	/*
431*4882a593Smuzhiyun 	 * set default rate as 1/1.
432*4882a593Smuzhiyun 	 * otherwise .set_rate which setup ratio
433*4882a593Smuzhiyun 	 * is never called if user requests 1/1 rate
434*4882a593Smuzhiyun 	 */
435*4882a593Smuzhiyun 	rate = clk_get_rate(priv->ref_clk);
436*4882a593Smuzhiyun 	ret = __cs2000_set_rate(priv, ch, rate, rate);
437*4882a593Smuzhiyun 	if (ret < 0)
438*4882a593Smuzhiyun 		return ret;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	parent_names[CLK_IN]	= __clk_get_name(priv->clk_in);
441*4882a593Smuzhiyun 	parent_names[REF_CLK]	= __clk_get_name(priv->ref_clk);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	init.name		= name;
444*4882a593Smuzhiyun 	init.ops		= &cs2000_ops;
445*4882a593Smuzhiyun 	init.flags		= CLK_SET_RATE_GATE;
446*4882a593Smuzhiyun 	init.parent_names	= parent_names;
447*4882a593Smuzhiyun 	init.num_parents	= ARRAY_SIZE(parent_names);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	priv->hw.init = &init;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	ret = clk_hw_register(dev, &priv->hw);
452*4882a593Smuzhiyun 	if (ret)
453*4882a593Smuzhiyun 		return ret;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
456*4882a593Smuzhiyun 	if (ret < 0) {
457*4882a593Smuzhiyun 		clk_hw_unregister(&priv->hw);
458*4882a593Smuzhiyun 		return ret;
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	return 0;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
cs2000_version_print(struct cs2000_priv * priv)464*4882a593Smuzhiyun static int cs2000_version_print(struct cs2000_priv *priv)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun 	struct device *dev = priv_to_dev(priv);
467*4882a593Smuzhiyun 	s32 val;
468*4882a593Smuzhiyun 	const char *revision;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	val = cs2000_read(priv, DEVICE_ID);
471*4882a593Smuzhiyun 	if (val < 0)
472*4882a593Smuzhiyun 		return val;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	/* CS2000 should be 0x0 */
475*4882a593Smuzhiyun 	if (val >> 3)
476*4882a593Smuzhiyun 		return -EIO;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	switch (val & REVISION_MASK) {
479*4882a593Smuzhiyun 	case REVISION_B2_B3:
480*4882a593Smuzhiyun 		revision = "B2 / B3";
481*4882a593Smuzhiyun 		break;
482*4882a593Smuzhiyun 	case REVISION_C1:
483*4882a593Smuzhiyun 		revision = "C1";
484*4882a593Smuzhiyun 		break;
485*4882a593Smuzhiyun 	default:
486*4882a593Smuzhiyun 		return -EIO;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	dev_info(dev, "revision - %s\n", revision);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	return 0;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
cs2000_remove(struct i2c_client * client)494*4882a593Smuzhiyun static int cs2000_remove(struct i2c_client *client)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	struct cs2000_priv *priv = i2c_get_clientdata(client);
497*4882a593Smuzhiyun 	struct device *dev = priv_to_dev(priv);
498*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	of_clk_del_provider(np);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	clk_hw_unregister(&priv->hw);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	return 0;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
cs2000_probe(struct i2c_client * client,const struct i2c_device_id * id)507*4882a593Smuzhiyun static int cs2000_probe(struct i2c_client *client,
508*4882a593Smuzhiyun 			const struct i2c_device_id *id)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	struct cs2000_priv *priv;
511*4882a593Smuzhiyun 	struct device *dev = &client->dev;
512*4882a593Smuzhiyun 	int ret;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
515*4882a593Smuzhiyun 	if (!priv)
516*4882a593Smuzhiyun 		return -ENOMEM;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	priv->client = client;
519*4882a593Smuzhiyun 	i2c_set_clientdata(client, priv);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	ret = cs2000_clk_get(priv);
522*4882a593Smuzhiyun 	if (ret < 0)
523*4882a593Smuzhiyun 		return ret;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	ret = cs2000_clk_register(priv);
526*4882a593Smuzhiyun 	if (ret < 0)
527*4882a593Smuzhiyun 		return ret;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	ret = cs2000_version_print(priv);
530*4882a593Smuzhiyun 	if (ret < 0)
531*4882a593Smuzhiyun 		goto probe_err;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	return 0;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun probe_err:
536*4882a593Smuzhiyun 	cs2000_remove(client);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	return ret;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
cs2000_resume(struct device * dev)541*4882a593Smuzhiyun static int __maybe_unused cs2000_resume(struct device *dev)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	struct cs2000_priv *priv = dev_get_drvdata(dev);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	return cs2000_set_saved_rate(priv);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun static const struct dev_pm_ops cs2000_pm_ops = {
549*4882a593Smuzhiyun 	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, cs2000_resume)
550*4882a593Smuzhiyun };
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun static struct i2c_driver cs2000_driver = {
553*4882a593Smuzhiyun 	.driver = {
554*4882a593Smuzhiyun 		.name = "cs2000-cp",
555*4882a593Smuzhiyun 		.pm	= &cs2000_pm_ops,
556*4882a593Smuzhiyun 		.of_match_table = cs2000_of_match,
557*4882a593Smuzhiyun 	},
558*4882a593Smuzhiyun 	.probe		= cs2000_probe,
559*4882a593Smuzhiyun 	.remove		= cs2000_remove,
560*4882a593Smuzhiyun 	.id_table	= cs2000_id,
561*4882a593Smuzhiyun };
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun module_i2c_driver(cs2000_driver);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun MODULE_DESCRIPTION("CS2000-CP driver");
566*4882a593Smuzhiyun MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
567*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
568