1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for Silicon Labs Si514 Programmable Oscillator
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2015 Topic Embedded Products
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Mike Looijmans <mike.looijmans@topic.nl>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/clk-provider.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/i2c.h>
14*4882a593Smuzhiyun #include <linux/regmap.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /* I2C registers */
18*4882a593Smuzhiyun #define SI514_REG_LP 0
19*4882a593Smuzhiyun #define SI514_REG_M_FRAC1 5
20*4882a593Smuzhiyun #define SI514_REG_M_FRAC2 6
21*4882a593Smuzhiyun #define SI514_REG_M_FRAC3 7
22*4882a593Smuzhiyun #define SI514_REG_M_INT_FRAC 8
23*4882a593Smuzhiyun #define SI514_REG_M_INT 9
24*4882a593Smuzhiyun #define SI514_REG_HS_DIV 10
25*4882a593Smuzhiyun #define SI514_REG_LS_HS_DIV 11
26*4882a593Smuzhiyun #define SI514_REG_OE_STATE 14
27*4882a593Smuzhiyun #define SI514_REG_RESET 128
28*4882a593Smuzhiyun #define SI514_REG_CONTROL 132
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* Register values */
31*4882a593Smuzhiyun #define SI514_RESET_RST BIT(7)
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define SI514_CONTROL_FCAL BIT(0)
34*4882a593Smuzhiyun #define SI514_CONTROL_OE BIT(2)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define SI514_MIN_FREQ 100000U
37*4882a593Smuzhiyun #define SI514_MAX_FREQ 250000000U
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define FXO 31980000U
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define FVCO_MIN 2080000000U
42*4882a593Smuzhiyun #define FVCO_MAX 2500000000U
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define HS_DIV_MAX 1022
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct clk_si514 {
47*4882a593Smuzhiyun struct clk_hw hw;
48*4882a593Smuzhiyun struct regmap *regmap;
49*4882a593Smuzhiyun struct i2c_client *i2c_client;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun #define to_clk_si514(_hw) container_of(_hw, struct clk_si514, hw)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Multiplier/divider settings */
54*4882a593Smuzhiyun struct clk_si514_muldiv {
55*4882a593Smuzhiyun u32 m_frac; /* 29-bit Fractional part of multiplier M */
56*4882a593Smuzhiyun u8 m_int; /* Integer part of multiplier M, 65..78 */
57*4882a593Smuzhiyun u8 ls_div_bits; /* 2nd divider, as 2^x */
58*4882a593Smuzhiyun u16 hs_div; /* 1st divider, must be even and 10<=x<=1022 */
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* Enables or disables the output driver */
si514_enable_output(struct clk_si514 * data,bool enable)62*4882a593Smuzhiyun static int si514_enable_output(struct clk_si514 *data, bool enable)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun return regmap_update_bits(data->regmap, SI514_REG_CONTROL,
65*4882a593Smuzhiyun SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
si514_prepare(struct clk_hw * hw)68*4882a593Smuzhiyun static int si514_prepare(struct clk_hw *hw)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct clk_si514 *data = to_clk_si514(hw);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun return si514_enable_output(data, true);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
si514_unprepare(struct clk_hw * hw)75*4882a593Smuzhiyun static void si514_unprepare(struct clk_hw *hw)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun struct clk_si514 *data = to_clk_si514(hw);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun si514_enable_output(data, false);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
si514_is_prepared(struct clk_hw * hw)82*4882a593Smuzhiyun static int si514_is_prepared(struct clk_hw *hw)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun struct clk_si514 *data = to_clk_si514(hw);
85*4882a593Smuzhiyun unsigned int val;
86*4882a593Smuzhiyun int err;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun err = regmap_read(data->regmap, SI514_REG_CONTROL, &val);
89*4882a593Smuzhiyun if (err < 0)
90*4882a593Smuzhiyun return err;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun return !!(val & SI514_CONTROL_OE);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Retrieve clock multiplier and dividers from hardware */
si514_get_muldiv(struct clk_si514 * data,struct clk_si514_muldiv * settings)96*4882a593Smuzhiyun static int si514_get_muldiv(struct clk_si514 *data,
97*4882a593Smuzhiyun struct clk_si514_muldiv *settings)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun int err;
100*4882a593Smuzhiyun u8 reg[7];
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun err = regmap_bulk_read(data->regmap, SI514_REG_M_FRAC1,
103*4882a593Smuzhiyun reg, ARRAY_SIZE(reg));
104*4882a593Smuzhiyun if (err)
105*4882a593Smuzhiyun return err;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun settings->m_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
108*4882a593Smuzhiyun (reg[3] & 0x1F) << 24;
109*4882a593Smuzhiyun settings->m_int = (reg[4] & 0x3f) << 3 | reg[3] >> 5;
110*4882a593Smuzhiyun settings->ls_div_bits = (reg[6] >> 4) & 0x07;
111*4882a593Smuzhiyun settings->hs_div = (reg[6] & 0x03) << 8 | reg[5];
112*4882a593Smuzhiyun return 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
si514_set_muldiv(struct clk_si514 * data,struct clk_si514_muldiv * settings)115*4882a593Smuzhiyun static int si514_set_muldiv(struct clk_si514 *data,
116*4882a593Smuzhiyun struct clk_si514_muldiv *settings)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun u8 lp;
119*4882a593Smuzhiyun u8 reg[7];
120*4882a593Smuzhiyun int err;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* Calculate LP1/LP2 according to table 13 in the datasheet */
123*4882a593Smuzhiyun /* 65.259980246 */
124*4882a593Smuzhiyun if (settings->m_int < 65 ||
125*4882a593Smuzhiyun (settings->m_int == 65 && settings->m_frac <= 139575831))
126*4882a593Smuzhiyun lp = 0x22;
127*4882a593Smuzhiyun /* 67.859763463 */
128*4882a593Smuzhiyun else if (settings->m_int < 67 ||
129*4882a593Smuzhiyun (settings->m_int == 67 && settings->m_frac <= 461581994))
130*4882a593Smuzhiyun lp = 0x23;
131*4882a593Smuzhiyun /* 72.937624981 */
132*4882a593Smuzhiyun else if (settings->m_int < 72 ||
133*4882a593Smuzhiyun (settings->m_int == 72 && settings->m_frac <= 503383578))
134*4882a593Smuzhiyun lp = 0x33;
135*4882a593Smuzhiyun /* 75.843265046 */
136*4882a593Smuzhiyun else if (settings->m_int < 75 ||
137*4882a593Smuzhiyun (settings->m_int == 75 && settings->m_frac <= 452724474))
138*4882a593Smuzhiyun lp = 0x34;
139*4882a593Smuzhiyun else
140*4882a593Smuzhiyun lp = 0x44;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun err = regmap_write(data->regmap, SI514_REG_LP, lp);
143*4882a593Smuzhiyun if (err < 0)
144*4882a593Smuzhiyun return err;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun reg[0] = settings->m_frac;
147*4882a593Smuzhiyun reg[1] = settings->m_frac >> 8;
148*4882a593Smuzhiyun reg[2] = settings->m_frac >> 16;
149*4882a593Smuzhiyun reg[3] = settings->m_frac >> 24 | settings->m_int << 5;
150*4882a593Smuzhiyun reg[4] = settings->m_int >> 3;
151*4882a593Smuzhiyun reg[5] = settings->hs_div;
152*4882a593Smuzhiyun reg[6] = (settings->hs_div >> 8) | (settings->ls_div_bits << 4);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun err = regmap_bulk_write(data->regmap, SI514_REG_HS_DIV, reg + 5, 2);
155*4882a593Smuzhiyun if (err < 0)
156*4882a593Smuzhiyun return err;
157*4882a593Smuzhiyun /*
158*4882a593Smuzhiyun * Writing to SI514_REG_M_INT_FRAC triggers the clock change, so that
159*4882a593Smuzhiyun * must be written last
160*4882a593Smuzhiyun */
161*4882a593Smuzhiyun return regmap_bulk_write(data->regmap, SI514_REG_M_FRAC1, reg, 5);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* Calculate divider settings for a given frequency */
si514_calc_muldiv(struct clk_si514_muldiv * settings,unsigned long frequency)165*4882a593Smuzhiyun static int si514_calc_muldiv(struct clk_si514_muldiv *settings,
166*4882a593Smuzhiyun unsigned long frequency)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun u64 m;
169*4882a593Smuzhiyun u32 ls_freq;
170*4882a593Smuzhiyun u32 tmp;
171*4882a593Smuzhiyun u8 res;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun if ((frequency < SI514_MIN_FREQ) || (frequency > SI514_MAX_FREQ))
174*4882a593Smuzhiyun return -EINVAL;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* Determine the minimum value of LS_DIV and resulting target freq. */
177*4882a593Smuzhiyun ls_freq = frequency;
178*4882a593Smuzhiyun if (frequency >= (FVCO_MIN / HS_DIV_MAX))
179*4882a593Smuzhiyun settings->ls_div_bits = 0;
180*4882a593Smuzhiyun else {
181*4882a593Smuzhiyun res = 1;
182*4882a593Smuzhiyun tmp = 2 * HS_DIV_MAX;
183*4882a593Smuzhiyun while (tmp <= (HS_DIV_MAX * 32)) {
184*4882a593Smuzhiyun if ((frequency * tmp) >= FVCO_MIN)
185*4882a593Smuzhiyun break;
186*4882a593Smuzhiyun ++res;
187*4882a593Smuzhiyun tmp <<= 1;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun settings->ls_div_bits = res;
190*4882a593Smuzhiyun ls_freq = frequency << res;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* Determine minimum HS_DIV, round up to even number */
194*4882a593Smuzhiyun settings->hs_div = DIV_ROUND_UP(FVCO_MIN >> 1, ls_freq) << 1;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* M = LS_DIV x HS_DIV x frequency / F_XO (in fixed-point) */
197*4882a593Smuzhiyun m = ((u64)(ls_freq * settings->hs_div) << 29) + (FXO / 2);
198*4882a593Smuzhiyun do_div(m, FXO);
199*4882a593Smuzhiyun settings->m_frac = (u32)m & (BIT(29) - 1);
200*4882a593Smuzhiyun settings->m_int = (u32)(m >> 29);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun return 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* Calculate resulting frequency given the register settings */
si514_calc_rate(struct clk_si514_muldiv * settings)206*4882a593Smuzhiyun static unsigned long si514_calc_rate(struct clk_si514_muldiv *settings)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun u64 m = settings->m_frac | ((u64)settings->m_int << 29);
209*4882a593Smuzhiyun u32 d = settings->hs_div * BIT(settings->ls_div_bits);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun return ((u32)(((m * FXO) + (FXO / 2)) >> 29)) / d;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
si514_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)214*4882a593Smuzhiyun static unsigned long si514_recalc_rate(struct clk_hw *hw,
215*4882a593Smuzhiyun unsigned long parent_rate)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun struct clk_si514 *data = to_clk_si514(hw);
218*4882a593Smuzhiyun struct clk_si514_muldiv settings;
219*4882a593Smuzhiyun int err;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun err = si514_get_muldiv(data, &settings);
222*4882a593Smuzhiyun if (err) {
223*4882a593Smuzhiyun dev_err(&data->i2c_client->dev, "unable to retrieve settings\n");
224*4882a593Smuzhiyun return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return si514_calc_rate(&settings);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
si514_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)230*4882a593Smuzhiyun static long si514_round_rate(struct clk_hw *hw, unsigned long rate,
231*4882a593Smuzhiyun unsigned long *parent_rate)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct clk_si514_muldiv settings;
234*4882a593Smuzhiyun int err;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun if (!rate)
237*4882a593Smuzhiyun return 0;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun err = si514_calc_muldiv(&settings, rate);
240*4882a593Smuzhiyun if (err)
241*4882a593Smuzhiyun return err;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return si514_calc_rate(&settings);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun * Update output frequency for big frequency changes (> 1000 ppm).
248*4882a593Smuzhiyun * The chip supports <1000ppm changes "on the fly", we haven't implemented
249*4882a593Smuzhiyun * that here.
250*4882a593Smuzhiyun */
si514_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)251*4882a593Smuzhiyun static int si514_set_rate(struct clk_hw *hw, unsigned long rate,
252*4882a593Smuzhiyun unsigned long parent_rate)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun struct clk_si514 *data = to_clk_si514(hw);
255*4882a593Smuzhiyun struct clk_si514_muldiv settings;
256*4882a593Smuzhiyun unsigned int old_oe_state;
257*4882a593Smuzhiyun int err;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun err = si514_calc_muldiv(&settings, rate);
260*4882a593Smuzhiyun if (err)
261*4882a593Smuzhiyun return err;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state);
264*4882a593Smuzhiyun if (err)
265*4882a593Smuzhiyun return err;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun si514_enable_output(data, false);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun err = si514_set_muldiv(data, &settings);
270*4882a593Smuzhiyun if (err < 0)
271*4882a593Smuzhiyun return err; /* Undefined state now, best to leave disabled */
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* Trigger calibration */
274*4882a593Smuzhiyun err = regmap_write(data->regmap, SI514_REG_CONTROL, SI514_CONTROL_FCAL);
275*4882a593Smuzhiyun if (err < 0)
276*4882a593Smuzhiyun return err;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* Applying a new frequency can take up to 10ms */
279*4882a593Smuzhiyun usleep_range(10000, 12000);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (old_oe_state & SI514_CONTROL_OE)
282*4882a593Smuzhiyun si514_enable_output(data, true);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return err;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun static const struct clk_ops si514_clk_ops = {
288*4882a593Smuzhiyun .prepare = si514_prepare,
289*4882a593Smuzhiyun .unprepare = si514_unprepare,
290*4882a593Smuzhiyun .is_prepared = si514_is_prepared,
291*4882a593Smuzhiyun .recalc_rate = si514_recalc_rate,
292*4882a593Smuzhiyun .round_rate = si514_round_rate,
293*4882a593Smuzhiyun .set_rate = si514_set_rate,
294*4882a593Smuzhiyun };
295*4882a593Smuzhiyun
si514_regmap_is_volatile(struct device * dev,unsigned int reg)296*4882a593Smuzhiyun static bool si514_regmap_is_volatile(struct device *dev, unsigned int reg)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun switch (reg) {
299*4882a593Smuzhiyun case SI514_REG_CONTROL:
300*4882a593Smuzhiyun case SI514_REG_RESET:
301*4882a593Smuzhiyun return true;
302*4882a593Smuzhiyun default:
303*4882a593Smuzhiyun return false;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
si514_regmap_is_writeable(struct device * dev,unsigned int reg)307*4882a593Smuzhiyun static bool si514_regmap_is_writeable(struct device *dev, unsigned int reg)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun switch (reg) {
310*4882a593Smuzhiyun case SI514_REG_LP:
311*4882a593Smuzhiyun case SI514_REG_M_FRAC1 ... SI514_REG_LS_HS_DIV:
312*4882a593Smuzhiyun case SI514_REG_OE_STATE:
313*4882a593Smuzhiyun case SI514_REG_RESET:
314*4882a593Smuzhiyun case SI514_REG_CONTROL:
315*4882a593Smuzhiyun return true;
316*4882a593Smuzhiyun default:
317*4882a593Smuzhiyun return false;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun static const struct regmap_config si514_regmap_config = {
322*4882a593Smuzhiyun .reg_bits = 8,
323*4882a593Smuzhiyun .val_bits = 8,
324*4882a593Smuzhiyun .cache_type = REGCACHE_RBTREE,
325*4882a593Smuzhiyun .max_register = SI514_REG_CONTROL,
326*4882a593Smuzhiyun .writeable_reg = si514_regmap_is_writeable,
327*4882a593Smuzhiyun .volatile_reg = si514_regmap_is_volatile,
328*4882a593Smuzhiyun };
329*4882a593Smuzhiyun
si514_probe(struct i2c_client * client,const struct i2c_device_id * id)330*4882a593Smuzhiyun static int si514_probe(struct i2c_client *client,
331*4882a593Smuzhiyun const struct i2c_device_id *id)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun struct clk_si514 *data;
334*4882a593Smuzhiyun struct clk_init_data init;
335*4882a593Smuzhiyun int err;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
338*4882a593Smuzhiyun if (!data)
339*4882a593Smuzhiyun return -ENOMEM;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun init.ops = &si514_clk_ops;
342*4882a593Smuzhiyun init.flags = 0;
343*4882a593Smuzhiyun init.num_parents = 0;
344*4882a593Smuzhiyun data->hw.init = &init;
345*4882a593Smuzhiyun data->i2c_client = client;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (of_property_read_string(client->dev.of_node, "clock-output-names",
348*4882a593Smuzhiyun &init.name))
349*4882a593Smuzhiyun init.name = client->dev.of_node->name;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun data->regmap = devm_regmap_init_i2c(client, &si514_regmap_config);
352*4882a593Smuzhiyun if (IS_ERR(data->regmap)) {
353*4882a593Smuzhiyun dev_err(&client->dev, "failed to allocate register map\n");
354*4882a593Smuzhiyun return PTR_ERR(data->regmap);
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun i2c_set_clientdata(client, data);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun err = devm_clk_hw_register(&client->dev, &data->hw);
360*4882a593Smuzhiyun if (err) {
361*4882a593Smuzhiyun dev_err(&client->dev, "clock registration failed\n");
362*4882a593Smuzhiyun return err;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get,
365*4882a593Smuzhiyun &data->hw);
366*4882a593Smuzhiyun if (err) {
367*4882a593Smuzhiyun dev_err(&client->dev, "unable to add clk provider\n");
368*4882a593Smuzhiyun return err;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
si514_remove(struct i2c_client * client)374*4882a593Smuzhiyun static int si514_remove(struct i2c_client *client)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun of_clk_del_provider(client->dev.of_node);
377*4882a593Smuzhiyun return 0;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun static const struct i2c_device_id si514_id[] = {
381*4882a593Smuzhiyun { "si514", 0 },
382*4882a593Smuzhiyun { }
383*4882a593Smuzhiyun };
384*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, si514_id);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun static const struct of_device_id clk_si514_of_match[] = {
387*4882a593Smuzhiyun { .compatible = "silabs,si514" },
388*4882a593Smuzhiyun { },
389*4882a593Smuzhiyun };
390*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, clk_si514_of_match);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun static struct i2c_driver si514_driver = {
393*4882a593Smuzhiyun .driver = {
394*4882a593Smuzhiyun .name = "si514",
395*4882a593Smuzhiyun .of_match_table = clk_si514_of_match,
396*4882a593Smuzhiyun },
397*4882a593Smuzhiyun .probe = si514_probe,
398*4882a593Smuzhiyun .remove = si514_remove,
399*4882a593Smuzhiyun .id_table = si514_id,
400*4882a593Smuzhiyun };
401*4882a593Smuzhiyun module_i2c_driver(si514_driver);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
404*4882a593Smuzhiyun MODULE_DESCRIPTION("Si514 driver");
405*4882a593Smuzhiyun MODULE_LICENSE("GPL");
406