Blame view

drivers/clk/clk-axi-clkgen.c 11.4 KB
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * AXI clkgen driver
   *
   * Copyright 2012-2013 Analog Devices Inc.
   *  Author: Lars-Peter Clausen <lars@metafoo.de>
   *
   * Licensed under the GPL-2.
   *
   */
  
  #include <linux/platform_device.h>
  #include <linux/clk-provider.h>
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
13
14
15
16
17
  #include <linux/slab.h>
  #include <linux/io.h>
  #include <linux/of.h>
  #include <linux/module.h>
  #include <linux/err.h>
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
18
  #define AXI_CLKGEN_V2_REG_RESET		0x40
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
19
  #define AXI_CLKGEN_V2_REG_CLKSEL	0x44
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  #define AXI_CLKGEN_V2_REG_DRP_CNTRL	0x70
  #define AXI_CLKGEN_V2_REG_DRP_STATUS	0x74
  
  #define AXI_CLKGEN_V2_RESET_MMCM_ENABLE	BIT(1)
  #define AXI_CLKGEN_V2_RESET_ENABLE	BIT(0)
  
  #define AXI_CLKGEN_V2_DRP_CNTRL_SEL	BIT(29)
  #define AXI_CLKGEN_V2_DRP_CNTRL_READ	BIT(28)
  
  #define AXI_CLKGEN_V2_DRP_STATUS_BUSY	BIT(16)
  
  #define MMCM_REG_CLKOUT0_1	0x08
  #define MMCM_REG_CLKOUT0_2	0x09
  #define MMCM_REG_CLK_FB1	0x14
  #define MMCM_REG_CLK_FB2	0x15
  #define MMCM_REG_CLK_DIV	0x16
  #define MMCM_REG_LOCK1		0x18
  #define MMCM_REG_LOCK2		0x19
  #define MMCM_REG_LOCK3		0x1a
  #define MMCM_REG_FILTER1	0x4e
  #define MMCM_REG_FILTER2	0x4f
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  struct axi_clkgen {
  	void __iomem *base;
  	struct clk_hw clk_hw;
  };
  
  static uint32_t axi_clkgen_lookup_filter(unsigned int m)
  {
  	switch (m) {
  	case 0:
  		return 0x01001990;
  	case 1:
  		return 0x01001190;
  	case 2:
  		return 0x01009890;
  	case 3:
  		return 0x01001890;
  	case 4:
  		return 0x01008890;
  	case 5 ... 8:
  		return 0x01009090;
  	case 9 ... 11:
  		return 0x01000890;
  	case 12:
  		return 0x08009090;
  	case 13 ... 22:
  		return 0x01001090;
  	case 23 ... 36:
  		return 0x01008090;
  	case 37 ... 46:
  		return 0x08001090;
  	default:
  		return 0x08008090;
  	}
  }
  
  static const uint32_t axi_clkgen_lock_table[] = {
  	0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
  	0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
  	0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
  	0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
  	0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
  	0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
  	0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
  	0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
  	0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
  };
  
  static uint32_t axi_clkgen_lookup_lock(unsigned int m)
  {
  	if (m < ARRAY_SIZE(axi_clkgen_lock_table))
  		return axi_clkgen_lock_table[m];
  	return 0x1f1f00fa;
  }
  
  static const unsigned int fpfd_min = 10000;
  static const unsigned int fpfd_max = 300000;
  static const unsigned int fvco_min = 600000;
  static const unsigned int fvco_max = 1200000;
  
  static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
  	unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
  {
  	unsigned long d, d_min, d_max, _d_min, _d_max;
  	unsigned long m, m_min, m_max;
  	unsigned long f, dout, best_f, fvco;
  
  	fin /= 1000;
  	fout /= 1000;
  
  	best_f = ULONG_MAX;
  	*best_d = 0;
  	*best_m = 0;
  	*best_dout = 0;
  
  	d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
  	d_max = min_t(unsigned long, fin / fpfd_min, 80);
  
  	m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
  	m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
  
  	for (m = m_min; m <= m_max; m++) {
  		_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
  		_d_max = min(d_max, fin * m / fvco_min);
  
  		for (d = _d_min; d <= _d_max; d++) {
  			fvco = fin * m / d;
  
  			dout = DIV_ROUND_CLOSEST(fvco, fout);
  			dout = clamp_t(unsigned long, dout, 1, 128);
  			f = fvco / dout;
  			if (abs(f - fout) < abs(best_f - fout)) {
  				best_f = f;
  				*best_d = d;
  				*best_m = m;
  				*best_dout = dout;
  				if (best_f == fout)
  					return;
  			}
  		}
  	}
  }
  
  static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
  	unsigned int *high, unsigned int *edge, unsigned int *nocount)
  {
  	if (divider == 1)
  		*nocount = 1;
  	else
  		*nocount = 0;
  
  	*high = divider / 2;
  	*edge = divider % 2;
  	*low = divider - *high;
  }
  
  static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
  	unsigned int reg, unsigned int val)
  {
  	writel(val, axi_clkgen->base + reg);
  }
  
  static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
  	unsigned int reg, unsigned int *val)
  {
  	*val = readl(axi_clkgen->base + reg);
  }
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
  {
  	unsigned int timeout = 10000;
  	unsigned int val;
  
  	do {
  		axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val);
  	} while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout);
  
  	if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY)
  		return -EIO;
  
  	return val & 0xffff;
  }
d95b599c0   Lars-Peter Clausen   clk: axi-clkgen: ...
181
  static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  	unsigned int reg, unsigned int *val)
  {
  	unsigned int reg_val;
  	int ret;
  
  	ret = axi_clkgen_wait_non_busy(axi_clkgen);
  	if (ret < 0)
  		return ret;
  
  	reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ;
  	reg_val |= (reg << 16);
  
  	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
  
  	ret = axi_clkgen_wait_non_busy(axi_clkgen);
  	if (ret < 0)
  		return ret;
  
  	*val = ret;
  
  	return 0;
  }
d95b599c0   Lars-Peter Clausen   clk: axi-clkgen: ...
204
  static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
205
206
207
208
209
210
211
212
213
214
  	unsigned int reg, unsigned int val, unsigned int mask)
  {
  	unsigned int reg_val = 0;
  	int ret;
  
  	ret = axi_clkgen_wait_non_busy(axi_clkgen);
  	if (ret < 0)
  		return ret;
  
  	if (mask != 0xffff) {
d95b599c0   Lars-Peter Clausen   clk: axi-clkgen: ...
215
  		axi_clkgen_mmcm_read(axi_clkgen, reg, &reg_val);
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
216
217
218
219
220
221
222
223
224
  		reg_val &= ~mask;
  	}
  
  	reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask);
  
  	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
  
  	return 0;
  }
d95b599c0   Lars-Peter Clausen   clk: axi-clkgen: ...
225
  static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
226
227
228
229
230
231
232
233
234
  	bool enable)
  {
  	unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
  
  	if (enable)
  		val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE;
  
  	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
  }
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
  {
  	return container_of(clk_hw, struct axi_clkgen, clk_hw);
  }
  
  static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
  	unsigned long rate, unsigned long parent_rate)
  {
  	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
  	unsigned int d, m, dout;
  	unsigned int nocount;
  	unsigned int high;
  	unsigned int edge;
  	unsigned int low;
  	uint32_t filter;
  	uint32_t lock;
  
  	if (parent_rate == 0 || rate == 0)
  		return -EINVAL;
  
  	axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
  
  	if (d == 0 || dout == 0 || m == 0)
  		return -EINVAL;
  
  	filter = axi_clkgen_lookup_filter(m - 1);
  	lock = axi_clkgen_lookup_lock(m - 1);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
262
  	axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
263
264
265
266
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_1,
  		(high << 6) | low, 0xefff);
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_2,
  		(edge << 7) | (nocount << 6), 0x03ff);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
267
268
  
  	axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
269
270
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
  		(edge << 13) | (nocount << 12) | (high << 6) | low, 0x3fff);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
271
272
  
  	axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
273
274
275
276
277
278
279
280
281
282
283
284
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB1,
  		(high << 6) | low, 0xefff);
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB2,
  		(edge << 7) | (nocount << 6), 0x03ff);
  
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
  		(((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff);
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3,
  		(((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900);
  	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  
  	return 0;
  }
  
  static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
  	unsigned long *parent_rate)
  {
  	unsigned int d, m, dout;
  
  	axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
  
  	if (d == 0 || dout == 0 || m == 0)
  		return -EINVAL;
  
  	return *parent_rate / d * m / dout;
  }
  
  static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
  	unsigned long parent_rate)
  {
  	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
  	unsigned int d, m, dout;
  	unsigned int reg;
  	unsigned long long tmp;
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
309
  	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, &reg);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
310
  	dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
311
  	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &reg);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
312
  	d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
313
  	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, &reg);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
314
315
316
317
318
319
320
  	m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
  
  	if (d == 0 || dout == 0)
  		return 0;
  
  	tmp = (unsigned long long)(parent_rate / d) * m;
  	do_div(tmp, dout);
3d6f1c721   Stephen Boyd   clk: axi-clkgen: ...
321
  	return min_t(unsigned long long, tmp, ULONG_MAX);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
322
  }
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  static int axi_clkgen_enable(struct clk_hw *clk_hw)
  {
  	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
  
  	axi_clkgen_mmcm_enable(axi_clkgen, true);
  
  	return 0;
  }
  
  static void axi_clkgen_disable(struct clk_hw *clk_hw)
  {
  	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
  
  	axi_clkgen_mmcm_enable(axi_clkgen, false);
  }
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  static int axi_clkgen_set_parent(struct clk_hw *clk_hw, u8 index)
  {
  	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
  
  	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, index);
  
  	return 0;
  }
  
  static u8 axi_clkgen_get_parent(struct clk_hw *clk_hw)
  {
  	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
  	unsigned int parent;
  
  	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, &parent);
  
  	return parent;
  }
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
356
357
358
359
  static const struct clk_ops axi_clkgen_ops = {
  	.recalc_rate = axi_clkgen_recalc_rate,
  	.round_rate = axi_clkgen_round_rate,
  	.set_rate = axi_clkgen_set_rate,
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
360
361
  	.enable = axi_clkgen_enable,
  	.disable = axi_clkgen_disable,
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
362
363
  	.set_parent = axi_clkgen_set_parent,
  	.get_parent = axi_clkgen_get_parent,
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
364
  };
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
365
366
  static const struct of_device_id axi_clkgen_ids[] = {
  	{
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
367
  		.compatible = "adi,axi-clkgen-2.00.a",
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
368
369
370
371
  	},
  	{ },
  };
  MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
372
373
  static int axi_clkgen_probe(struct platform_device *pdev)
  {
1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
374
  	const struct of_device_id *id;
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
375
376
  	struct axi_clkgen *axi_clkgen;
  	struct clk_init_data init;
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
377
  	const char *parent_names[2];
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
378
379
  	const char *clk_name;
  	struct resource *mem;
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
380
  	unsigned int i;
e0d30bb92   Stephen Boyd   clk: axi-clkgen: ...
381
  	int ret;
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
382

1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
383
384
385
386
387
388
  	if (!pdev->dev.of_node)
  		return -ENODEV;
  
  	id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
  	if (!id)
  		return -ENODEV;
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
389
390
391
392
393
394
395
396
  	axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
  	if (!axi_clkgen)
  		return -ENOMEM;
  
  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
  	if (IS_ERR(axi_clkgen->base))
  		return PTR_ERR(axi_clkgen->base);
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
397
398
  	init.num_parents = of_clk_get_parent_count(pdev->dev.of_node);
  	if (init.num_parents < 1 || init.num_parents > 2)
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
399
  		return -EINVAL;
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
400
401
402
403
404
  	for (i = 0; i < init.num_parents; i++) {
  		parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i);
  		if (!parent_names[i])
  			return -EINVAL;
  	}
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
405
406
407
408
409
410
  	clk_name = pdev->dev.of_node->name;
  	of_property_read_string(pdev->dev.of_node, "clock-output-names",
  		&clk_name);
  
  	init.name = clk_name;
  	init.ops = &axi_clkgen_ops;
62d1e7823   Lars-Peter Clausen   clk: axi-clkgen: ...
411
412
  	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
  	init.parent_names = parent_names;
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
413

1887c3a64   Lars-Peter Clausen   clk: axi-clkgen: ...
414
  	axi_clkgen_mmcm_enable(axi_clkgen, false);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
415
  	axi_clkgen->clk_hw.init = &init;
e0d30bb92   Stephen Boyd   clk: axi-clkgen: ...
416
417
418
  	ret = devm_clk_hw_register(&pdev->dev, &axi_clkgen->clk_hw);
  	if (ret)
  		return ret;
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
419

e0d30bb92   Stephen Boyd   clk: axi-clkgen: ...
420
421
  	return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get,
  				      &axi_clkgen->clk_hw);
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
422
423
424
425
426
427
428
429
  }
  
  static int axi_clkgen_remove(struct platform_device *pdev)
  {
  	of_clk_del_provider(pdev->dev.of_node);
  
  	return 0;
  }
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
430
431
432
  static struct platform_driver axi_clkgen_driver = {
  	.driver = {
  		.name = "adi-axi-clkgen",
0e646c52c   Lars-Peter Clausen   clk: Add axi-clkg...
433
434
435
436
437
438
439
440
441
442
  		.of_match_table = axi_clkgen_ids,
  	},
  	.probe = axi_clkgen_probe,
  	.remove = axi_clkgen_remove,
  };
  module_platform_driver(axi_clkgen_driver);
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
  MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");