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