xref: /linux/drivers/clk/clk-wm831x.c (revision 20979202ee6e4c68dab7bcf408787225a656d18e)
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 
55f05259a6SMark Brown static 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 
100f05259a6SMark Brown 	usleep_range(2000, 2000);
101f05259a6SMark Brown 
102f05259a6SMark Brown 	return ret;
103f05259a6SMark Brown }
104f05259a6SMark Brown 
105f05259a6SMark Brown static void wm831x_fll_unprepare(struct clk_hw *hw)
106f05259a6SMark Brown {
107f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
108f05259a6SMark Brown 						  fll_hw);
109f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
110f05259a6SMark Brown 	int ret;
111f05259a6SMark Brown 
1126f8b3145SAxel Lin 	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0);
113f05259a6SMark Brown 	if (ret != 0)
1146f8b3145SAxel Lin 		dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret);
115f05259a6SMark Brown }
116f05259a6SMark Brown 
117f05259a6SMark Brown static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
118f05259a6SMark Brown 					    unsigned long parent_rate)
119f05259a6SMark Brown {
120f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
121f05259a6SMark Brown 						  fll_hw);
122f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
123f05259a6SMark Brown 	int ret;
124f05259a6SMark Brown 
125f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
126f05259a6SMark Brown 	if (ret < 0) {
127f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
128f05259a6SMark Brown 			ret);
129f05259a6SMark Brown 		return 0;
130f05259a6SMark Brown 	}
131f05259a6SMark Brown 
132f05259a6SMark Brown 	if (ret & WM831X_FLL_AUTO)
133f05259a6SMark Brown 		return wm831x_fll_auto_rates[ret & WM831X_FLL_AUTO_FREQ_MASK];
134f05259a6SMark Brown 
135f05259a6SMark Brown 	dev_err(wm831x->dev, "FLL only supported in AUTO mode\n");
136f05259a6SMark Brown 
137f05259a6SMark Brown 	return 0;
138f05259a6SMark Brown }
139f05259a6SMark Brown 
140f05259a6SMark Brown static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate,
141f05259a6SMark Brown 				  unsigned long *unused)
142f05259a6SMark Brown {
143f05259a6SMark Brown 	int best = 0;
144f05259a6SMark Brown 	int i;
145f05259a6SMark Brown 
146f05259a6SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
147f05259a6SMark Brown 		if (abs(wm831x_fll_auto_rates[i] - rate) <
148f05259a6SMark Brown 		    abs(wm831x_fll_auto_rates[best] - rate))
149f05259a6SMark Brown 			best = i;
150f05259a6SMark Brown 
151f05259a6SMark Brown 	return wm831x_fll_auto_rates[best];
152f05259a6SMark Brown }
153f05259a6SMark Brown 
154f05259a6SMark Brown static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
155f05259a6SMark Brown 			       unsigned long parent_rate)
156f05259a6SMark Brown {
157f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
158f05259a6SMark Brown 						  fll_hw);
159f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
160f05259a6SMark Brown 	int i;
161f05259a6SMark Brown 
162f05259a6SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
163f05259a6SMark Brown 		if (wm831x_fll_auto_rates[i] == rate)
164f05259a6SMark Brown 			break;
165f05259a6SMark Brown 	if (i == ARRAY_SIZE(wm831x_fll_auto_rates))
166f05259a6SMark Brown 		return -EINVAL;
167f05259a6SMark Brown 
168a5828a6cSMark Brown 	if (wm831x_fll_is_prepared(hw))
169f05259a6SMark Brown 		return -EPERM;
170f05259a6SMark Brown 
171f05259a6SMark Brown 	return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2,
172f05259a6SMark Brown 			       WM831X_FLL_AUTO_FREQ_MASK, i);
173f05259a6SMark Brown }
174f05259a6SMark Brown 
175f05259a6SMark Brown static const char *wm831x_fll_parents[] = {
176f05259a6SMark Brown 	"xtal",
177f05259a6SMark Brown 	"clkin",
178f05259a6SMark Brown };
179f05259a6SMark Brown 
180f05259a6SMark Brown static u8 wm831x_fll_get_parent(struct clk_hw *hw)
181f05259a6SMark Brown {
182f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
183f05259a6SMark Brown 						  fll_hw);
184f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
185f05259a6SMark Brown 	int ret;
186f05259a6SMark Brown 
187f05259a6SMark Brown 	/* AUTO mode is always clocked from the crystal */
188f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
189f05259a6SMark Brown 	if (ret < 0) {
190f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
191f05259a6SMark Brown 			ret);
192f05259a6SMark Brown 		return 0;
193f05259a6SMark Brown 	}
194f05259a6SMark Brown 
195f05259a6SMark Brown 	if (ret & WM831X_FLL_AUTO)
196f05259a6SMark Brown 		return 0;
197f05259a6SMark Brown 
198f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_5);
199f05259a6SMark Brown 	if (ret < 0) {
200f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read FLL_CONTROL_5: %d\n",
201f05259a6SMark Brown 			ret);
202f05259a6SMark Brown 		return 0;
203f05259a6SMark Brown 	}
204f05259a6SMark Brown 
205f05259a6SMark Brown 	switch (ret & WM831X_FLL_CLK_SRC_MASK) {
206f05259a6SMark Brown 	case 0:
207f05259a6SMark Brown 		return 0;
208f05259a6SMark Brown 	case 1:
209f05259a6SMark Brown 		return 1;
210f05259a6SMark Brown 	default:
211f05259a6SMark Brown 		dev_err(wm831x->dev, "Unsupported FLL clock source %d\n",
212f05259a6SMark Brown 			ret & WM831X_FLL_CLK_SRC_MASK);
213f05259a6SMark Brown 		return 0;
214f05259a6SMark Brown 	}
215f05259a6SMark Brown }
216f05259a6SMark Brown 
217f05259a6SMark Brown static const struct clk_ops wm831x_fll_ops = {
218a5828a6cSMark Brown 	.is_prepared = wm831x_fll_is_prepared,
219f05259a6SMark Brown 	.prepare = wm831x_fll_prepare,
220f05259a6SMark Brown 	.unprepare = wm831x_fll_unprepare,
221f05259a6SMark Brown 	.round_rate = wm831x_fll_round_rate,
222f05259a6SMark Brown 	.recalc_rate = wm831x_fll_recalc_rate,
223f05259a6SMark Brown 	.set_rate = wm831x_fll_set_rate,
224f05259a6SMark Brown 	.get_parent = wm831x_fll_get_parent,
225f05259a6SMark Brown };
226f05259a6SMark Brown 
227f05259a6SMark Brown static struct clk_init_data wm831x_fll_init = {
228f05259a6SMark Brown 	.name = "fll",
229f05259a6SMark Brown 	.ops = &wm831x_fll_ops,
230f05259a6SMark Brown 	.parent_names = wm831x_fll_parents,
231f05259a6SMark Brown 	.num_parents = ARRAY_SIZE(wm831x_fll_parents),
232f05259a6SMark Brown 	.flags = CLK_SET_RATE_GATE,
233f05259a6SMark Brown };
234f05259a6SMark Brown 
235a5828a6cSMark Brown static int wm831x_clkout_is_prepared(struct clk_hw *hw)
236f05259a6SMark Brown {
237f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
238f05259a6SMark Brown 						  clkout_hw);
239f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
240f05259a6SMark Brown 	int ret;
241f05259a6SMark Brown 
242f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
243f05259a6SMark Brown 	if (ret < 0) {
244f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
245f05259a6SMark Brown 			ret);
246*20979202SPan Bian 		return false;
247f05259a6SMark Brown 	}
248f05259a6SMark Brown 
249f05259a6SMark Brown 	return (ret & WM831X_CLKOUT_ENA) != 0;
250f05259a6SMark Brown }
251f05259a6SMark Brown 
252f05259a6SMark Brown static int wm831x_clkout_prepare(struct clk_hw *hw)
253f05259a6SMark Brown {
254f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
255f05259a6SMark Brown 						  clkout_hw);
256f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
257f05259a6SMark Brown 	int ret;
258f05259a6SMark Brown 
259f05259a6SMark Brown 	ret = wm831x_reg_unlock(wm831x);
260f05259a6SMark Brown 	if (ret != 0) {
261f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
262f05259a6SMark Brown 		return ret;
263f05259a6SMark Brown 	}
264f05259a6SMark Brown 
265f05259a6SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
266f05259a6SMark Brown 			      WM831X_CLKOUT_ENA, WM831X_CLKOUT_ENA);
267f05259a6SMark Brown 	if (ret != 0)
268f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to enable CLKOUT: %d\n", ret);
269f05259a6SMark Brown 
270f05259a6SMark Brown 	wm831x_reg_lock(wm831x);
271f05259a6SMark Brown 
272f05259a6SMark Brown 	return ret;
273f05259a6SMark Brown }
274f05259a6SMark Brown 
275f05259a6SMark Brown static void wm831x_clkout_unprepare(struct clk_hw *hw)
276f05259a6SMark Brown {
277f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
278f05259a6SMark Brown 						  clkout_hw);
279f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
280f05259a6SMark Brown 	int ret;
281f05259a6SMark Brown 
282f05259a6SMark Brown 	ret = wm831x_reg_unlock(wm831x);
283f05259a6SMark Brown 	if (ret != 0) {
284f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
285f05259a6SMark Brown 		return;
286f05259a6SMark Brown 	}
287f05259a6SMark Brown 
288f05259a6SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
289f05259a6SMark Brown 			      WM831X_CLKOUT_ENA, 0);
290f05259a6SMark Brown 	if (ret != 0)
291f05259a6SMark Brown 		dev_crit(wm831x->dev, "Failed to disable CLKOUT: %d\n", ret);
292f05259a6SMark Brown 
293f05259a6SMark Brown 	wm831x_reg_lock(wm831x);
294f05259a6SMark Brown }
295f05259a6SMark Brown 
296f05259a6SMark Brown static const char *wm831x_clkout_parents[] = {
297f05259a6SMark Brown 	"fll",
298bcc7fd20SAxel Lin 	"xtal",
299f05259a6SMark Brown };
300f05259a6SMark Brown 
301f05259a6SMark Brown static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
302f05259a6SMark Brown {
303f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
304f05259a6SMark Brown 						  clkout_hw);
305f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
306f05259a6SMark Brown 	int ret;
307f05259a6SMark Brown 
308f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
309f05259a6SMark Brown 	if (ret < 0) {
310f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
311f05259a6SMark Brown 			ret);
312f05259a6SMark Brown 		return 0;
313f05259a6SMark Brown 	}
314f05259a6SMark Brown 
315f05259a6SMark Brown 	if (ret & WM831X_CLKOUT_SRC)
316f05259a6SMark Brown 		return 1;
317bcc7fd20SAxel Lin 	else
318bcc7fd20SAxel Lin 		return 0;
319f05259a6SMark Brown }
320f05259a6SMark Brown 
321f05259a6SMark Brown static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
322f05259a6SMark Brown {
323f05259a6SMark Brown 	struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
324f05259a6SMark Brown 						  clkout_hw);
325f05259a6SMark Brown 	struct wm831x *wm831x = clkdata->wm831x;
326f05259a6SMark Brown 
327f05259a6SMark Brown 	return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
328f05259a6SMark Brown 			       WM831X_CLKOUT_SRC,
329f05259a6SMark Brown 			       parent << WM831X_CLKOUT_SRC_SHIFT);
330f05259a6SMark Brown }
331f05259a6SMark Brown 
332f05259a6SMark Brown static const struct clk_ops wm831x_clkout_ops = {
333a5828a6cSMark Brown 	.is_prepared = wm831x_clkout_is_prepared,
334f05259a6SMark Brown 	.prepare = wm831x_clkout_prepare,
335f05259a6SMark Brown 	.unprepare = wm831x_clkout_unprepare,
336f05259a6SMark Brown 	.get_parent = wm831x_clkout_get_parent,
337f05259a6SMark Brown 	.set_parent = wm831x_clkout_set_parent,
338f05259a6SMark Brown };
339f05259a6SMark Brown 
340f05259a6SMark Brown static struct clk_init_data wm831x_clkout_init = {
341f05259a6SMark Brown 	.name = "clkout",
342f05259a6SMark Brown 	.ops = &wm831x_clkout_ops,
343f05259a6SMark Brown 	.parent_names = wm831x_clkout_parents,
344f05259a6SMark Brown 	.num_parents = ARRAY_SIZE(wm831x_clkout_parents),
345f05259a6SMark Brown 	.flags = CLK_SET_RATE_PARENT,
346f05259a6SMark Brown };
347f05259a6SMark Brown 
348018ae93fSBill Pemberton static int wm831x_clk_probe(struct platform_device *pdev)
349f05259a6SMark Brown {
350f05259a6SMark Brown 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
351f05259a6SMark Brown 	struct wm831x_clk *clkdata;
352f05259a6SMark Brown 	int ret;
353f05259a6SMark Brown 
354f05259a6SMark Brown 	clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
355f05259a6SMark Brown 	if (!clkdata)
356f05259a6SMark Brown 		return -ENOMEM;
357f05259a6SMark Brown 
35808442ce9SMark Brown 	clkdata->wm831x = wm831x;
35908442ce9SMark Brown 
360f05259a6SMark Brown 	/* XTAL_ENA can only be set via OTP/InstantConfig so just read once */
361f05259a6SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
362f05259a6SMark Brown 	if (ret < 0) {
363f05259a6SMark Brown 		dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
364f05259a6SMark Brown 			ret);
365f05259a6SMark Brown 		return ret;
366f05259a6SMark Brown 	}
367f05259a6SMark Brown 	clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
368f05259a6SMark Brown 
369f05259a6SMark Brown 	clkdata->xtal_hw.init = &wm831x_xtal_init;
370cc671d13SStephen Boyd 	ret = devm_clk_hw_register(&pdev->dev, &clkdata->xtal_hw);
371cc671d13SStephen Boyd 	if (ret)
372cc671d13SStephen Boyd 		return ret;
373f05259a6SMark Brown 
374f05259a6SMark Brown 	clkdata->fll_hw.init = &wm831x_fll_init;
375cc671d13SStephen Boyd 	ret = devm_clk_hw_register(&pdev->dev, &clkdata->fll_hw);
376cc671d13SStephen Boyd 	if (ret)
377cc671d13SStephen Boyd 		return ret;
378f05259a6SMark Brown 
379f05259a6SMark Brown 	clkdata->clkout_hw.init = &wm831x_clkout_init;
380cc671d13SStephen Boyd 	ret = devm_clk_hw_register(&pdev->dev, &clkdata->clkout_hw);
381cc671d13SStephen Boyd 	if (ret)
382cc671d13SStephen Boyd 		return ret;
383f05259a6SMark Brown 
384c0431037SJingoo Han 	platform_set_drvdata(pdev, clkdata);
385f05259a6SMark Brown 
386f05259a6SMark Brown 	return 0;
387f05259a6SMark Brown }
388f05259a6SMark Brown 
389f05259a6SMark Brown static struct platform_driver wm831x_clk_driver = {
390f05259a6SMark Brown 	.probe = wm831x_clk_probe,
391f05259a6SMark Brown 	.driver		= {
392f05259a6SMark Brown 		.name	= "wm831x-clk",
393f05259a6SMark Brown 	},
394f05259a6SMark Brown };
395f05259a6SMark Brown 
396f05259a6SMark Brown module_platform_driver(wm831x_clk_driver);
397f05259a6SMark Brown 
398f05259a6SMark Brown /* Module information */
399f05259a6SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
400f05259a6SMark Brown MODULE_DESCRIPTION("WM831x clock driver");
401f05259a6SMark Brown MODULE_LICENSE("GPL");
402f05259a6SMark Brown MODULE_ALIAS("platform:wm831x-clk");
403