xref: /linux/drivers/clk/clk-wm831x.c (revision f05259a6ffa40097b5565f25c3fcf833a9d3ecf5)
1*f05259a6SMark Brown /*
2*f05259a6SMark Brown  * WM831x clock control
3*f05259a6SMark Brown  *
4*f05259a6SMark Brown  * Copyright 2011-2 Wolfson Microelectronics PLC.
5*f05259a6SMark Brown  *
6*f05259a6SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7*f05259a6SMark Brown  *
8*f05259a6SMark Brown  *  This program is free software; you can redistribute  it and/or modify it
9*f05259a6SMark Brown  *  under  the terms of  the GNU General  Public License as published by the
10*f05259a6SMark Brown  *  Free Software Foundation;  either version 2 of the  License, or (at your
11*f05259a6SMark Brown  *  option) any later version.
12*f05259a6SMark Brown  *
13*f05259a6SMark Brown  */
14*f05259a6SMark Brown 
15*f05259a6SMark Brown #include <linux/clk.h>
16*f05259a6SMark Brown #include <linux/clk-provider.h>
17*f05259a6SMark Brown #include <linux/delay.h>
18*f05259a6SMark Brown #include <linux/module.h>
19*f05259a6SMark Brown #include <linux/slab.h>
20*f05259a6SMark Brown #include <linux/platform_device.h>
21*f05259a6SMark Brown #include <linux/mfd/wm831x/core.h>
22*f05259a6SMark Brown 
23*f05259a6SMark Brown struct wm831x_clk {
24*f05259a6SMark Brown 	struct wm831x *wm831x;
25*f05259a6SMark Brown 	struct clk_hw xtal_hw;
26*f05259a6SMark Brown 	struct clk_hw fll_hw;
27*f05259a6SMark Brown 	struct clk_hw clkout_hw;
28*f05259a6SMark Brown 	struct clk *xtal;
29*f05259a6SMark Brown 	struct clk *fll;
30*f05259a6SMark Brown 	struct clk *clkout;
31*f05259a6SMark Brown 	bool xtal_ena;
32*f05259a6SMark Brown };
33*f05259a6SMark Brown 
34*f05259a6SMark Brown static int wm831x_xtal_is_enabled(struct clk_hw *hw)
35*f05259a6SMark Brown {
36*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
37*f05259a6SMark Brown 						  xtal_hw);
38*f05259a6SMark Brown 
39*f05259a6SMark Brown 	return clkdata->xtal_ena;
40*f05259a6SMark Brown }
41*f05259a6SMark Brown 
42*f05259a6SMark Brown static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw,
43*f05259a6SMark Brown 					     unsigned long parent_rate)
44*f05259a6SMark Brown {
45*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
46*f05259a6SMark Brown 						  xtal_hw);
47*f05259a6SMark Brown 
48*f05259a6SMark Brown 	if (clkdata->xtal_ena)
49*f05259a6SMark Brown 		return 32768;
50*f05259a6SMark Brown 	else
51*f05259a6SMark Brown 		return 0;
52*f05259a6SMark Brown }
53*f05259a6SMark Brown 
54*f05259a6SMark Brown static const struct clk_ops wm831x_xtal_ops = {
55*f05259a6SMark Brown 	.is_enabled = wm831x_xtal_is_enabled,
56*f05259a6SMark Brown 	.recalc_rate = wm831x_xtal_recalc_rate,
57*f05259a6SMark Brown };
58*f05259a6SMark Brown 
59*f05259a6SMark Brown static struct clk_init_data wm831x_xtal_init = {
60*f05259a6SMark Brown 	.name = "xtal",
61*f05259a6SMark Brown 	.ops = &wm831x_xtal_ops,
62*f05259a6SMark Brown 	.flags = CLK_IS_ROOT,
63*f05259a6SMark Brown };
64*f05259a6SMark Brown 
65*f05259a6SMark Brown static const unsigned long wm831x_fll_auto_rates[] = {
66*f05259a6SMark Brown 	 2048000,
67*f05259a6SMark Brown 	11289600,
68*f05259a6SMark Brown 	12000000,
69*f05259a6SMark Brown 	12288000,
70*f05259a6SMark Brown 	19200000,
71*f05259a6SMark Brown 	22579600,
72*f05259a6SMark Brown 	24000000,
73*f05259a6SMark Brown 	24576000,
74*f05259a6SMark Brown };
75*f05259a6SMark Brown 
76*f05259a6SMark Brown static int wm831x_fll_is_enabled(struct clk_hw *hw)
77*f05259a6SMark Brown {
78*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
79*f05259a6SMark Brown 						  fll_hw);
80*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
81*f05259a6SMark Brown 	int ret;
82*f05259a6SMark Brown 
83*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_1);
84*f05259a6SMark Brown 	if (ret < 0) {
85*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read FLL_CONTROL_1: %d\n",
86*f05259a6SMark Brown 			ret);
87*f05259a6SMark Brown 		return true;
88*f05259a6SMark Brown 	}
89*f05259a6SMark Brown 
90*f05259a6SMark Brown 	return (ret & WM831X_FLL_ENA) != 0;
91*f05259a6SMark Brown }
92*f05259a6SMark Brown 
93*f05259a6SMark Brown static int wm831x_fll_prepare(struct clk_hw *hw)
94*f05259a6SMark Brown {
95*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
96*f05259a6SMark Brown 						  fll_hw);
97*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
98*f05259a6SMark Brown 	int ret;
99*f05259a6SMark Brown 
100*f05259a6SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2,
101*f05259a6SMark Brown 			      WM831X_FLL_ENA, WM831X_FLL_ENA);
102*f05259a6SMark Brown 	if (ret != 0)
103*f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret);
104*f05259a6SMark Brown 
105*f05259a6SMark Brown 	usleep_range(2000, 2000);
106*f05259a6SMark Brown 
107*f05259a6SMark Brown 	return ret;
108*f05259a6SMark Brown }
109*f05259a6SMark Brown 
110*f05259a6SMark Brown static void wm831x_fll_unprepare(struct clk_hw *hw)
111*f05259a6SMark Brown {
112*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
113*f05259a6SMark Brown 						  fll_hw);
114*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
115*f05259a6SMark Brown 	int ret;
116*f05259a6SMark Brown 
117*f05259a6SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, WM831X_FLL_ENA, 0);
118*f05259a6SMark Brown 	if (ret != 0)
119*f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to disaable FLL: %d\n", ret);
120*f05259a6SMark Brown }
121*f05259a6SMark Brown 
122*f05259a6SMark Brown static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
123*f05259a6SMark Brown 					    unsigned long parent_rate)
124*f05259a6SMark Brown {
125*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
126*f05259a6SMark Brown 						  fll_hw);
127*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
128*f05259a6SMark Brown 	int ret;
129*f05259a6SMark Brown 
130*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
131*f05259a6SMark Brown 	if (ret < 0) {
132*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
133*f05259a6SMark Brown 			ret);
134*f05259a6SMark Brown 		return 0;
135*f05259a6SMark Brown 	}
136*f05259a6SMark Brown 
137*f05259a6SMark Brown 	if (ret & WM831X_FLL_AUTO)
138*f05259a6SMark Brown 		return wm831x_fll_auto_rates[ret & WM831X_FLL_AUTO_FREQ_MASK];
139*f05259a6SMark Brown 
140*f05259a6SMark Brown 	dev_err(wm831x->dev, "FLL only supported in AUTO mode\n");
141*f05259a6SMark Brown 
142*f05259a6SMark Brown 	return 0;
143*f05259a6SMark Brown }
144*f05259a6SMark Brown 
145*f05259a6SMark Brown static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate,
146*f05259a6SMark Brown 				  unsigned long *unused)
147*f05259a6SMark Brown {
148*f05259a6SMark Brown 	int best = 0;
149*f05259a6SMark Brown 	int i;
150*f05259a6SMark Brown 
151*f05259a6SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
152*f05259a6SMark Brown 		if (abs(wm831x_fll_auto_rates[i] - rate) <
153*f05259a6SMark Brown 		    abs(wm831x_fll_auto_rates[best] - rate))
154*f05259a6SMark Brown 			best = i;
155*f05259a6SMark Brown 
156*f05259a6SMark Brown 	return wm831x_fll_auto_rates[best];
157*f05259a6SMark Brown }
158*f05259a6SMark Brown 
159*f05259a6SMark Brown static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
160*f05259a6SMark Brown 			       unsigned long parent_rate)
161*f05259a6SMark Brown {
162*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
163*f05259a6SMark Brown 						  fll_hw);
164*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
165*f05259a6SMark Brown 	int i;
166*f05259a6SMark Brown 
167*f05259a6SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
168*f05259a6SMark Brown 		if (wm831x_fll_auto_rates[i] == rate)
169*f05259a6SMark Brown 			break;
170*f05259a6SMark Brown 	if (i == ARRAY_SIZE(wm831x_fll_auto_rates))
171*f05259a6SMark Brown 		return -EINVAL;
172*f05259a6SMark Brown 
173*f05259a6SMark Brown 	if (wm831x_fll_is_enabled(hw))
174*f05259a6SMark Brown 		return -EPERM;
175*f05259a6SMark Brown 
176*f05259a6SMark Brown 	return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2,
177*f05259a6SMark Brown 			       WM831X_FLL_AUTO_FREQ_MASK, i);
178*f05259a6SMark Brown }
179*f05259a6SMark Brown 
180*f05259a6SMark Brown static const char *wm831x_fll_parents[] = {
181*f05259a6SMark Brown 	"xtal",
182*f05259a6SMark Brown 	"clkin",
183*f05259a6SMark Brown };
184*f05259a6SMark Brown 
185*f05259a6SMark Brown static u8 wm831x_fll_get_parent(struct clk_hw *hw)
186*f05259a6SMark Brown {
187*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
188*f05259a6SMark Brown 						  fll_hw);
189*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
190*f05259a6SMark Brown 	int ret;
191*f05259a6SMark Brown 
192*f05259a6SMark Brown 	/* AUTO mode is always clocked from the crystal */
193*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
194*f05259a6SMark Brown 	if (ret < 0) {
195*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
196*f05259a6SMark Brown 			ret);
197*f05259a6SMark Brown 		return 0;
198*f05259a6SMark Brown 	}
199*f05259a6SMark Brown 
200*f05259a6SMark Brown 	if (ret & WM831X_FLL_AUTO)
201*f05259a6SMark Brown 		return 0;
202*f05259a6SMark Brown 
203*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_5);
204*f05259a6SMark Brown 	if (ret < 0) {
205*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read FLL_CONTROL_5: %d\n",
206*f05259a6SMark Brown 			ret);
207*f05259a6SMark Brown 		return 0;
208*f05259a6SMark Brown 	}
209*f05259a6SMark Brown 
210*f05259a6SMark Brown 	switch (ret & WM831X_FLL_CLK_SRC_MASK) {
211*f05259a6SMark Brown 	case 0:
212*f05259a6SMark Brown 		return 0;
213*f05259a6SMark Brown 	case 1:
214*f05259a6SMark Brown 		return 1;
215*f05259a6SMark Brown 	default:
216*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unsupported FLL clock source %d\n",
217*f05259a6SMark Brown 			ret & WM831X_FLL_CLK_SRC_MASK);
218*f05259a6SMark Brown 		return 0;
219*f05259a6SMark Brown 	}
220*f05259a6SMark Brown }
221*f05259a6SMark Brown 
222*f05259a6SMark Brown static const struct clk_ops wm831x_fll_ops = {
223*f05259a6SMark Brown 	.is_enabled = wm831x_fll_is_enabled,
224*f05259a6SMark Brown 	.prepare = wm831x_fll_prepare,
225*f05259a6SMark Brown 	.unprepare = wm831x_fll_unprepare,
226*f05259a6SMark Brown 	.round_rate = wm831x_fll_round_rate,
227*f05259a6SMark Brown 	.recalc_rate = wm831x_fll_recalc_rate,
228*f05259a6SMark Brown 	.set_rate = wm831x_fll_set_rate,
229*f05259a6SMark Brown 	.get_parent = wm831x_fll_get_parent,
230*f05259a6SMark Brown };
231*f05259a6SMark Brown 
232*f05259a6SMark Brown static struct clk_init_data wm831x_fll_init = {
233*f05259a6SMark Brown 	.name = "fll",
234*f05259a6SMark Brown 	.ops = &wm831x_fll_ops,
235*f05259a6SMark Brown 	.parent_names = wm831x_fll_parents,
236*f05259a6SMark Brown 	.num_parents = ARRAY_SIZE(wm831x_fll_parents),
237*f05259a6SMark Brown 	.flags = CLK_SET_RATE_GATE,
238*f05259a6SMark Brown };
239*f05259a6SMark Brown 
240*f05259a6SMark Brown static int wm831x_clkout_is_enabled(struct clk_hw *hw)
241*f05259a6SMark Brown {
242*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
243*f05259a6SMark Brown 						  clkout_hw);
244*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
245*f05259a6SMark Brown 	int ret;
246*f05259a6SMark Brown 
247*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
248*f05259a6SMark Brown 	if (ret < 0) {
249*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
250*f05259a6SMark Brown 			ret);
251*f05259a6SMark Brown 		return true;
252*f05259a6SMark Brown 	}
253*f05259a6SMark Brown 
254*f05259a6SMark Brown 	return (ret & WM831X_CLKOUT_ENA) != 0;
255*f05259a6SMark Brown }
256*f05259a6SMark Brown 
257*f05259a6SMark Brown static int wm831x_clkout_prepare(struct clk_hw *hw)
258*f05259a6SMark Brown {
259*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
260*f05259a6SMark Brown 						  clkout_hw);
261*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
262*f05259a6SMark Brown 	int ret;
263*f05259a6SMark Brown 
264*f05259a6SMark Brown 	ret = wm831x_reg_unlock(wm831x);
265*f05259a6SMark Brown 	if (ret != 0) {
266*f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
267*f05259a6SMark Brown 		return ret;
268*f05259a6SMark Brown 	}
269*f05259a6SMark Brown 
270*f05259a6SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
271*f05259a6SMark Brown 			      WM831X_CLKOUT_ENA, WM831X_CLKOUT_ENA);
272*f05259a6SMark Brown 	if (ret != 0)
273*f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to enable CLKOUT: %d\n", ret);
274*f05259a6SMark Brown 
275*f05259a6SMark Brown 	wm831x_reg_lock(wm831x);
276*f05259a6SMark Brown 
277*f05259a6SMark Brown 	return ret;
278*f05259a6SMark Brown }
279*f05259a6SMark Brown 
280*f05259a6SMark Brown static void wm831x_clkout_unprepare(struct clk_hw *hw)
281*f05259a6SMark Brown {
282*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
283*f05259a6SMark Brown 						  clkout_hw);
284*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
285*f05259a6SMark Brown 	int ret;
286*f05259a6SMark Brown 
287*f05259a6SMark Brown 	ret = wm831x_reg_unlock(wm831x);
288*f05259a6SMark Brown 	if (ret != 0) {
289*f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
290*f05259a6SMark Brown 		return;
291*f05259a6SMark Brown 	}
292*f05259a6SMark Brown 
293*f05259a6SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
294*f05259a6SMark Brown 			      WM831X_CLKOUT_ENA, 0);
295*f05259a6SMark Brown 	if (ret != 0)
296*f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to disable CLKOUT: %d\n", ret);
297*f05259a6SMark Brown 
298*f05259a6SMark Brown 	wm831x_reg_lock(wm831x);
299*f05259a6SMark Brown }
300*f05259a6SMark Brown 
301*f05259a6SMark Brown static const char *wm831x_clkout_parents[] = {
302*f05259a6SMark Brown 	"xtal",
303*f05259a6SMark Brown 	"fll",
304*f05259a6SMark Brown };
305*f05259a6SMark Brown 
306*f05259a6SMark Brown static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
307*f05259a6SMark Brown {
308*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
309*f05259a6SMark Brown 						  clkout_hw);
310*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
311*f05259a6SMark Brown 	int ret;
312*f05259a6SMark Brown 
313*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
314*f05259a6SMark Brown 	if (ret < 0) {
315*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
316*f05259a6SMark Brown 			ret);
317*f05259a6SMark Brown 		return 0;
318*f05259a6SMark Brown 	}
319*f05259a6SMark Brown 
320*f05259a6SMark Brown 	if (ret & WM831X_CLKOUT_SRC)
321*f05259a6SMark Brown 		return 0;
322*f05259a6SMark Brown 	else
323*f05259a6SMark Brown 		return 1;
324*f05259a6SMark Brown }
325*f05259a6SMark Brown 
326*f05259a6SMark Brown static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
327*f05259a6SMark Brown {
328*f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
329*f05259a6SMark Brown 						  clkout_hw);
330*f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
331*f05259a6SMark Brown 
332*f05259a6SMark Brown 	return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
333*f05259a6SMark Brown 			       WM831X_CLKOUT_SRC,
334*f05259a6SMark Brown 			       parent << WM831X_CLKOUT_SRC_SHIFT);
335*f05259a6SMark Brown }
336*f05259a6SMark Brown 
337*f05259a6SMark Brown static const struct clk_ops wm831x_clkout_ops = {
338*f05259a6SMark Brown 	.is_enabled = wm831x_clkout_is_enabled,
339*f05259a6SMark Brown 	.prepare = wm831x_clkout_prepare,
340*f05259a6SMark Brown 	.unprepare = wm831x_clkout_unprepare,
341*f05259a6SMark Brown 	.get_parent = wm831x_clkout_get_parent,
342*f05259a6SMark Brown 	.set_parent = wm831x_clkout_set_parent,
343*f05259a6SMark Brown };
344*f05259a6SMark Brown 
345*f05259a6SMark Brown static struct clk_init_data wm831x_clkout_init = {
346*f05259a6SMark Brown 	.name = "clkout",
347*f05259a6SMark Brown 	.ops = &wm831x_clkout_ops,
348*f05259a6SMark Brown 	.parent_names = wm831x_clkout_parents,
349*f05259a6SMark Brown 	.num_parents = ARRAY_SIZE(wm831x_clkout_parents),
350*f05259a6SMark Brown 	.flags = CLK_SET_RATE_PARENT,
351*f05259a6SMark Brown };
352*f05259a6SMark Brown 
353*f05259a6SMark Brown static __devinit int wm831x_clk_probe(struct platform_device *pdev)
354*f05259a6SMark Brown {
355*f05259a6SMark Brown 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
356*f05259a6SMark Brown 	struct wm831x_clk *clkdata;
357*f05259a6SMark Brown 	int ret;
358*f05259a6SMark Brown 
359*f05259a6SMark Brown 	clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
360*f05259a6SMark Brown 	if (!clkdata)
361*f05259a6SMark Brown 		return -ENOMEM;
362*f05259a6SMark Brown 
363*f05259a6SMark Brown 	/* XTAL_ENA can only be set via OTP/InstantConfig so just read once */
364*f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
365*f05259a6SMark Brown 	if (ret < 0) {
366*f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
367*f05259a6SMark Brown 			ret);
368*f05259a6SMark Brown 		return ret;
369*f05259a6SMark Brown 	}
370*f05259a6SMark Brown 	clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
371*f05259a6SMark Brown 
372*f05259a6SMark Brown 	clkdata->xtal_hw.init = &wm831x_xtal_init;
373*f05259a6SMark Brown 	clkdata->xtal = clk_register(&pdev->dev, &clkdata->xtal_hw);
374*f05259a6SMark Brown 	if (!clkdata->xtal)
375*f05259a6SMark Brown 		return -EINVAL;
376*f05259a6SMark Brown 
377*f05259a6SMark Brown 	clkdata->fll_hw.init = &wm831x_fll_init;
378*f05259a6SMark Brown 	clkdata->fll = clk_register(&pdev->dev, &clkdata->fll_hw);
379*f05259a6SMark Brown 	if (!clkdata->fll) {
380*f05259a6SMark Brown 		ret = -EINVAL;
381*f05259a6SMark Brown 		goto err_xtal;
382*f05259a6SMark Brown 	}
383*f05259a6SMark Brown 
384*f05259a6SMark Brown 	clkdata->clkout_hw.init = &wm831x_clkout_init;
385*f05259a6SMark Brown 	clkdata->clkout = clk_register(&pdev->dev, &clkdata->clkout_hw);
386*f05259a6SMark Brown 	if (!clkdata->clkout) {
387*f05259a6SMark Brown 		ret = -EINVAL;
388*f05259a6SMark Brown 		goto err_fll;
389*f05259a6SMark Brown 	}
390*f05259a6SMark Brown 
391*f05259a6SMark Brown 	dev_set_drvdata(&pdev->dev, clkdata);
392*f05259a6SMark Brown 
393*f05259a6SMark Brown 	return 0;
394*f05259a6SMark Brown 
395*f05259a6SMark Brown err_fll:
396*f05259a6SMark Brown 	clk_unregister(clkdata->fll);
397*f05259a6SMark Brown err_xtal:
398*f05259a6SMark Brown 	clk_unregister(clkdata->xtal);
399*f05259a6SMark Brown 	return ret;
400*f05259a6SMark Brown }
401*f05259a6SMark Brown 
402*f05259a6SMark Brown static int __devexit wm831x_clk_remove(struct platform_device *pdev)
403*f05259a6SMark Brown {
404*f05259a6SMark Brown 	struct wm831x_clk *clkdata = dev_get_drvdata(&pdev->dev);
405*f05259a6SMark Brown 
406*f05259a6SMark Brown 	clk_unregister(clkdata->clkout);
407*f05259a6SMark Brown 	clk_unregister(clkdata->fll);
408*f05259a6SMark Brown 	clk_unregister(clkdata->xtal);
409*f05259a6SMark Brown 
410*f05259a6SMark Brown 	return 0;
411*f05259a6SMark Brown }
412*f05259a6SMark Brown 
413*f05259a6SMark Brown static struct platform_driver wm831x_clk_driver = {
414*f05259a6SMark Brown 	.probe = wm831x_clk_probe,
415*f05259a6SMark Brown 	.remove = __devexit_p(wm831x_clk_remove),
416*f05259a6SMark Brown 	.driver		= {
417*f05259a6SMark Brown 		.name	= "wm831x-clk",
418*f05259a6SMark Brown 		.owner	= THIS_MODULE,
419*f05259a6SMark Brown 	},
420*f05259a6SMark Brown };
421*f05259a6SMark Brown 
422*f05259a6SMark Brown module_platform_driver(wm831x_clk_driver);
423*f05259a6SMark Brown 
424*f05259a6SMark Brown /* Module information */
425*f05259a6SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
426*f05259a6SMark Brown MODULE_DESCRIPTION("WM831x clock driver");
427*f05259a6SMark Brown MODULE_LICENSE("GPL");
428*f05259a6SMark Brown MODULE_ALIAS("platform:wm831x-clk");
429