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