diff options
author | Dan Douglass <dan.douglass@freescale.com> | 2014-02-20 12:25:56 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:57:35 -0400 |
commit | fcc6fc800470df5651b5339c2521340fbc039860 (patch) | |
tree | d1ac8be1dfbb6ee6241329d751641a108efb2baf /drivers/char/hw_random | |
parent | 43bf6edb7035d3c9a2c02fb3f0359ca640ec8071 (diff) |
ENGR00292341 imx6sl hwrng
Add hwrng support for i.MX6SL.
1. Add RNG driver. This driver originated as fsl-rngc.c. It
has been modified to support device tree. The name has been
changed since it supports both b and c variants of RNG.
2. Added clock and compatible info to the device tree data.
3. Added the entry in the options in the Kconfig for hwrng.
Signed-off-by: Dan Douglass <dan.douglass@freescale.com>
Diffstat (limited to 'drivers/char/hw_random')
-rw-r--r-- | drivers/char/hw_random/Kconfig | 12 | ||||
-rw-r--r-- | drivers/char/hw_random/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/hw_random/imx-rng.c | 440 |
3 files changed, 453 insertions, 0 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 2f9dbf7568fb..1bd1603a276d 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -226,6 +226,18 @@ config HW_RANDOM_MXC_RNGA | |||
226 | 226 | ||
227 | If unsure, say Y. | 227 | If unsure, say Y. |
228 | 228 | ||
229 | config HW_RANDOM_IMX_RNG | ||
230 | tristate "Freescale RNG B/C Random Number Generator" | ||
231 | depends on HW_RANDOM && ARCH_MXC && HAVE_IMX_RNG | ||
232 | ---help--- | ||
233 | This driver provides kernel-side support for the Random Number | ||
234 | Generator (RNGBB and RNGC) hardware found on Freescale i.MX processors. | ||
235 | |||
236 | To compile this driver as a module, choose M here: the | ||
237 | module will be called fsl-rngc. | ||
238 | |||
239 | If unsure, say Y. | ||
240 | |||
229 | config HW_RANDOM_NOMADIK | 241 | config HW_RANDOM_NOMADIK |
230 | tristate "ST-Ericsson Nomadik Random Number Generator support" | 242 | tristate "ST-Ericsson Nomadik Random Number Generator support" |
231 | depends on HW_RANDOM && ARCH_NOMADIK | 243 | depends on HW_RANDOM && ARCH_NOMADIK |
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index bed467c9300e..face64c5fcf0 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o | |||
19 | obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o | 19 | obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o |
20 | obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o | 20 | obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o |
21 | obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o | 21 | obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o |
22 | obj-$(CONFIG_HW_RANDOM_IMX_RNG) += imx-rng.o | ||
22 | obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o | 23 | obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o |
23 | obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o | 24 | obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o |
24 | obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o | 25 | obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o |
diff --git a/drivers/char/hw_random/imx-rng.c b/drivers/char/hw_random/imx-rng.c new file mode 100644 index 000000000000..f1d7bd5d91cf --- /dev/null +++ b/drivers/char/hw_random/imx-rng.c | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | * RNG driver for Freescale RNG B/C | ||
3 | * | ||
4 | * Copyright (C) 2008-2014 Freescale Semiconductor, Inc. | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * The code contained herein is licensed under the GNU General Public | ||
9 | * License. You may obtain a copy of the GNU General Public License | ||
10 | * Version 2 or later at the following locations: | ||
11 | * | ||
12 | * http://www.opensource.org/licenses/gpl-license.html | ||
13 | * http://www.gnu.org/copyleft/gpl.html | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
18 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
19 | * | ||
20 | * derived from | ||
21 | * | ||
22 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
23 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
24 | * | ||
25 | * derived from | ||
26 | * | ||
27 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
28 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
29 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
30 | * | ||
31 | * This file is licensed under the terms of the GNU General Public | ||
32 | * License version 2. This program is licensed "as is" without any | ||
33 | * warranty of any kind, whether express or implied. | ||
34 | */ | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/clk.h> | ||
40 | #include <linux/err.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | #include <linux/of_address.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | #include <linux/hw_random.h> | ||
45 | #include <linux/io.h> | ||
46 | #include <linux/slab.h> | ||
47 | |||
48 | #define MODULE_NAME "imx-rng" | ||
49 | |||
50 | #define RNGC_VERSION_MAJOR3 3 | ||
51 | |||
52 | #define RNGC_VERSION_ID 0x0000 | ||
53 | #define RNGC_COMMAND 0x0004 | ||
54 | #define RNGC_CONTROL 0x0008 | ||
55 | #define RNGC_STATUS 0x000C | ||
56 | #define RNGC_ERROR 0x0010 | ||
57 | #define RNGC_FIFO 0x0014 | ||
58 | #define RNGC_VERIF_CTRL 0x0020 | ||
59 | #define RNGC_OSC_CTRL_COUNT 0x0028 | ||
60 | #define RNGC_OSC_COUNT 0x002C | ||
61 | #define RNGC_OSC_COUNT_STATUS 0x0030 | ||
62 | |||
63 | #define RNGC_VERID_ZEROS_MASK 0x0f000000 | ||
64 | #define RNGC_VERID_RNG_TYPE_MASK 0xf0000000 | ||
65 | #define RNGC_VERID_RNG_TYPE_SHIFT 28 | ||
66 | #define RNGC_VERID_CHIP_VERSION_MASK 0x00ff0000 | ||
67 | #define RNGC_VERID_CHIP_VERSION_SHIFT 16 | ||
68 | #define RNGC_VERID_VERSION_MAJOR_MASK 0x0000ff00 | ||
69 | #define RNGC_VERID_VERSION_MAJOR_SHIFT 8 | ||
70 | #define RNGC_VERID_VERSION_MINOR_MASK 0x000000ff | ||
71 | #define RNGC_VERID_VERSION_MINOR_SHIFT 0 | ||
72 | |||
73 | #define RNGC_CMD_ZEROS_MASK 0xffffff8c | ||
74 | #define RNGC_CMD_SW_RST 0x00000040 | ||
75 | #define RNGC_CMD_CLR_ERR 0x00000020 | ||
76 | #define RNGC_CMD_CLR_INT 0x00000010 | ||
77 | #define RNGC_CMD_SEED 0x00000002 | ||
78 | #define RNGC_CMD_SELF_TEST 0x00000001 | ||
79 | |||
80 | #define RNGC_CTRL_ZEROS_MASK 0xfffffc8c | ||
81 | #define RNGC_CTRL_CTL_ACC 0x00000200 | ||
82 | #define RNGC_CTRL_VERIF_MODE 0x00000100 | ||
83 | #define RNGC_CTRL_MASK_ERROR 0x00000040 | ||
84 | |||
85 | #define RNGC_CTRL_MASK_DONE 0x00000020 | ||
86 | #define RNGC_CTRL_AUTO_SEED 0x00000010 | ||
87 | #define RNGC_CTRL_FIFO_UFLOW_MASK 0x00000003 | ||
88 | #define RNGC_CTRL_FIFO_UFLOW_SHIFT 0 | ||
89 | |||
90 | #define RNGC_CTRL_FIFO_UFLOW_ZEROS_ERROR 0 | ||
91 | #define RNGC_CTRL_FIFO_UFLOW_ZEROS_ERROR2 1 | ||
92 | #define RNGC_CTRL_FIFO_UFLOW_BUS_XFR 2 | ||
93 | #define RNGC_CTRL_FIFO_UFLOW_ZEROS_INTR 3 | ||
94 | |||
95 | #define RNGC_STATUS_ST_PF_MASK 0x00c00000 | ||
96 | #define RNGC_STATUS_ST_PF_SHIFT 22 | ||
97 | #define RNGC_STATUS_ST_PF_TRNG 0x00800000 | ||
98 | #define RNGC_STATUS_ST_PF_PRNG 0x00400000 | ||
99 | #define RNGC_STATUS_ERROR 0x00010000 | ||
100 | #define RNGC_STATUS_FIFO_SIZE_MASK 0x0000f000 | ||
101 | #define RNGC_STATUS_FIFO_SIZE_SHIFT 12 | ||
102 | #define RNGC_STATUS_FIFO_LEVEL_MASK 0x00000f00 | ||
103 | #define RNGC_STATUS_FIFO_LEVEL_SHIFT 8 | ||
104 | #define RNGC_STATUS_NEXT_SEED_DONE 0x00000040 | ||
105 | #define RNGC_STATUS_SEED_DONE 0x00000020 | ||
106 | #define RNGC_STATUS_ST_DONE 0x00000010 | ||
107 | #define RNGC_STATUS_RESEED 0x00000008 | ||
108 | #define RNGC_STATUS_SLEEP 0x00000004 | ||
109 | #define RNGC_STATUS_BUSY 0x00000002 | ||
110 | #define RNGC_STATUS_SEC_STATE 0x00000001 | ||
111 | |||
112 | #define RNGC_ERROR_STATUS_ZEROS_MASK 0xffffffc0 | ||
113 | #define RNGC_ERROR_STATUS_BAD_KEY 0x00000040 | ||
114 | #define RNGC_ERROR_STATUS_RAND_ERR 0x00000020 | ||
115 | #define RNGC_ERROR_STATUS_FIFO_ERR 0x00000010 | ||
116 | #define RNGC_ERROR_STATUS_STAT_ERR 0x00000008 | ||
117 | #define RNGC_ERROR_STATUS_ST_ERR 0x00000004 | ||
118 | #define RNGC_ERROR_STATUS_OSC_ERR 0x00000002 | ||
119 | #define RNGC_ERROR_STATUS_LFSR_ERR 0x00000001 | ||
120 | |||
121 | #define RNG_ADDR_RANGE 0x34 | ||
122 | |||
123 | static DECLARE_COMPLETION(rng_self_testing); | ||
124 | static DECLARE_COMPLETION(rng_seed_done); | ||
125 | |||
126 | static struct platform_device *imx_rng_dev; | ||
127 | |||
128 | struct imx_rng_priv_data { | ||
129 | void __iomem *reg_base; | ||
130 | }; | ||
131 | |||
132 | int irq_rng; | ||
133 | |||
134 | static int imx_rng_data_present(struct hwrng *rng, int wait) | ||
135 | { | ||
136 | int level; | ||
137 | struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv; | ||
138 | |||
139 | /* how many random numbers are in FIFO? [0-16] */ | ||
140 | level = (readl(prv->reg_base + RNGC_STATUS) & | ||
141 | RNGC_STATUS_FIFO_LEVEL_MASK) >> RNGC_STATUS_FIFO_LEVEL_SHIFT; | ||
142 | |||
143 | return level > 0 ? 1 : 0; | ||
144 | } | ||
145 | |||
146 | static int imx_rng_data_read(struct hwrng *rng, u32 * data) | ||
147 | { | ||
148 | int err; | ||
149 | struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv; | ||
150 | |||
151 | /* retrieve a random number from FIFO */ | ||
152 | *data = readl(prv->reg_base + RNGC_FIFO); | ||
153 | |||
154 | /* is there some error while reading this random number? */ | ||
155 | err = readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR; | ||
156 | |||
157 | /* if error happened doesn't return random number */ | ||
158 | return err ? 0 : 4; | ||
159 | } | ||
160 | |||
161 | static irqreturn_t imx_rng_irq(int irq, void *dev) | ||
162 | { | ||
163 | int handled = 0; | ||
164 | struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)dev; | ||
165 | |||
166 | /* is the seed creation done? */ | ||
167 | if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_SEED_DONE) { | ||
168 | complete(&rng_seed_done); | ||
169 | writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, | ||
170 | prv->reg_base + RNGC_COMMAND); | ||
171 | handled = 1; | ||
172 | } | ||
173 | |||
174 | /* is the self test done? */ | ||
175 | if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ST_DONE) { | ||
176 | complete(&rng_self_testing); | ||
177 | writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, | ||
178 | prv->reg_base + RNGC_COMMAND); | ||
179 | handled = 1; | ||
180 | } | ||
181 | |||
182 | /* is there any error? */ | ||
183 | if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR) { | ||
184 | /* clear interrupt */ | ||
185 | writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, | ||
186 | prv->reg_base + RNGC_COMMAND); | ||
187 | handled = 1; | ||
188 | } | ||
189 | |||
190 | return handled; | ||
191 | } | ||
192 | |||
193 | static int imx_rng_init(struct hwrng *rng) | ||
194 | { | ||
195 | int err; | ||
196 | struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv; | ||
197 | u32 cmd, ctrl, osc; | ||
198 | |||
199 | INIT_COMPLETION(rng_self_testing); | ||
200 | INIT_COMPLETION(rng_seed_done); | ||
201 | |||
202 | err = readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR; | ||
203 | if (err) { | ||
204 | /* is this a bad keys error ? */ | ||
205 | if (readl(prv->reg_base + RNGC_ERROR) & | ||
206 | RNGC_ERROR_STATUS_BAD_KEY) { | ||
207 | dev_err(&imx_rng_dev->dev, "Can't start, Bad Keys.\n"); | ||
208 | return -EIO; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* mask all interrupts, will be unmasked soon */ | ||
213 | ctrl = readl(prv->reg_base + RNGC_CONTROL); | ||
214 | writel(ctrl | RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR, | ||
215 | prv->reg_base + RNGC_CONTROL); | ||
216 | |||
217 | /* verify if oscillator is working */ | ||
218 | osc = readl(prv->reg_base + RNGC_ERROR); | ||
219 | if (osc & RNGC_ERROR_STATUS_OSC_ERR) { | ||
220 | dev_err(&imx_rng_dev->dev, "RNGC Oscillator is dead!\n"); | ||
221 | return -EIO; | ||
222 | } | ||
223 | |||
224 | err = request_irq(irq_rng, imx_rng_irq, | ||
225 | 0, "imx-rng", (void *)rng->priv); | ||
226 | if (err) { | ||
227 | dev_err(&imx_rng_dev->dev, "Can't get interrupt working.\n"); | ||
228 | return -EIO; | ||
229 | } | ||
230 | |||
231 | /* do self test, repeat until get success */ | ||
232 | do { | ||
233 | /* clear error */ | ||
234 | cmd = readl(prv->reg_base + RNGC_COMMAND); | ||
235 | writel(cmd | RNGC_CMD_CLR_ERR, prv->reg_base + RNGC_COMMAND); | ||
236 | |||
237 | /* unmask all interrupt */ | ||
238 | ctrl = readl(prv->reg_base + RNGC_CONTROL); | ||
239 | writel(ctrl & ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR), | ||
240 | prv->reg_base + RNGC_CONTROL); | ||
241 | |||
242 | /* run self test */ | ||
243 | cmd = readl(prv->reg_base + RNGC_COMMAND); | ||
244 | writel(cmd | RNGC_CMD_SELF_TEST, | ||
245 | prv->reg_base + RNGC_COMMAND); | ||
246 | |||
247 | wait_for_completion(&rng_self_testing); | ||
248 | |||
249 | } while (readl(prv->reg_base + RNGC_ERROR) & | ||
250 | RNGC_ERROR_STATUS_ST_ERR); | ||
251 | |||
252 | /* clear interrupt. Is it really necessary here? */ | ||
253 | writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR, | ||
254 | prv->reg_base + RNGC_COMMAND); | ||
255 | |||
256 | /* create seed, repeat while there is some statistical error */ | ||
257 | do { | ||
258 | /* clear error */ | ||
259 | cmd = readl(prv->reg_base + RNGC_COMMAND); | ||
260 | writel(cmd | RNGC_CMD_CLR_ERR, prv->reg_base + RNGC_COMMAND); | ||
261 | |||
262 | /* seed creation */ | ||
263 | cmd = readl(prv->reg_base + RNGC_COMMAND); | ||
264 | writel(cmd | RNGC_CMD_SEED, prv->reg_base + RNGC_COMMAND); | ||
265 | |||
266 | wait_for_completion(&rng_seed_done); | ||
267 | |||
268 | } while (readl(prv->reg_base + RNGC_ERROR) & | ||
269 | RNGC_ERROR_STATUS_STAT_ERR); | ||
270 | |||
271 | err = readl(prv->reg_base + RNGC_ERROR) & | ||
272 | (RNGC_ERROR_STATUS_STAT_ERR | | ||
273 | RNGC_ERROR_STATUS_RAND_ERR | | ||
274 | RNGC_ERROR_STATUS_FIFO_ERR | | ||
275 | RNGC_ERROR_STATUS_ST_ERR | | ||
276 | RNGC_ERROR_STATUS_OSC_ERR | | ||
277 | RNGC_ERROR_STATUS_LFSR_ERR); | ||
278 | |||
279 | if (err) { | ||
280 | dev_err(&imx_rng_dev->dev, "iMX RNG appears inoperable.\n"); | ||
281 | return -EIO; | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static struct hwrng imx_rng = { | ||
288 | .name = "imx-rng", | ||
289 | .init = imx_rng_init, | ||
290 | .data_present = imx_rng_data_present, | ||
291 | .data_read = imx_rng_data_read | ||
292 | }; | ||
293 | |||
294 | static int __init imx_rng_probe(struct platform_device *pdev) | ||
295 | { | ||
296 | struct device *dev = &pdev->dev; | ||
297 | struct device_node *np = dev->of_node; | ||
298 | struct clk *clk; | ||
299 | struct imx_rng_priv_data *priv; | ||
300 | int err = -ENODEV; | ||
301 | |||
302 | if (imx_rng_dev) | ||
303 | return -EBUSY; | ||
304 | |||
305 | /* Enable the clock */ | ||
306 | clk = of_clk_get(np, 0); | ||
307 | if (IS_ERR(clk)) { | ||
308 | dev_err(dev, "Can not get clock.\n"); | ||
309 | return PTR_ERR(clk); | ||
310 | } | ||
311 | clk_enable(clk); | ||
312 | |||
313 | /* Allocate private data memory */ | ||
314 | priv = kzalloc(sizeof(struct imx_rng_priv_data), GFP_KERNEL); | ||
315 | if (!priv) | ||
316 | return -ENOMEM; | ||
317 | |||
318 | imx_rng.priv = (unsigned long)priv; | ||
319 | dev_set_drvdata(dev, priv); | ||
320 | |||
321 | /* ioremap that register space */ | ||
322 | priv->reg_base = of_iomap(np, 0); | ||
323 | if (!priv->reg_base) { | ||
324 | kfree(priv); | ||
325 | dev_err(dev, "Failed to remap register space.\n"); | ||
326 | return -ENODEV; | ||
327 | } | ||
328 | |||
329 | irq_rng = platform_get_irq(pdev, 0); | ||
330 | |||
331 | err = hwrng_register(&imx_rng); | ||
332 | if (err) { | ||
333 | iounmap(priv->reg_base); | ||
334 | kfree(priv); | ||
335 | dev_err(dev, "failed to register hwrng (%d)\n", err); | ||
336 | return err; | ||
337 | } | ||
338 | |||
339 | imx_rng_dev = pdev; | ||
340 | dev_info(dev, "iMX RNG Registered.\n"); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int __exit imx_rng_remove(struct platform_device *pdev) | ||
346 | { | ||
347 | struct device *dev = &pdev->dev; | ||
348 | struct device_node *np = dev->of_node; | ||
349 | struct clk *clk; | ||
350 | struct imx_rng_priv_data *priv = dev_get_drvdata(dev); | ||
351 | |||
352 | /* Disable the clock */ | ||
353 | clk = of_clk_get(np, 0); | ||
354 | |||
355 | if (IS_ERR(clk)) | ||
356 | dev_err(dev, "Can not get clock.\n"); | ||
357 | else | ||
358 | clk_disable(clk); | ||
359 | |||
360 | hwrng_unregister(&imx_rng); | ||
361 | |||
362 | iounmap(priv->reg_base); | ||
363 | |||
364 | kfree(priv); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int imx_rng_suspend(struct platform_device *pdev, pm_message_t state) | ||
370 | { | ||
371 | #ifdef CONFIG_PM | ||
372 | struct device *dev = &pdev->dev; | ||
373 | struct device_node *np = dev->of_node; | ||
374 | struct clk *clk = of_clk_get(np, 0); | ||
375 | |||
376 | if (IS_ERR(clk)) { | ||
377 | dev_err(&pdev->dev, "Can not get rng_clk\n"); | ||
378 | return PTR_ERR(clk); | ||
379 | } | ||
380 | |||
381 | clk_disable(clk); | ||
382 | #endif | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int imx_rng_resume(struct platform_device *pdev) | ||
388 | { | ||
389 | #ifdef CONFIG_PM | ||
390 | struct device *dev = &pdev->dev; | ||
391 | struct device_node *np = dev->of_node; | ||
392 | struct clk *clk = of_clk_get(np, 0); | ||
393 | |||
394 | if (IS_ERR(clk)) { | ||
395 | dev_err(&pdev->dev, "Can not get rng_clk\n"); | ||
396 | return PTR_ERR(clk); | ||
397 | } | ||
398 | |||
399 | clk_enable(clk); | ||
400 | #endif | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static struct of_device_id imx_rng_dt_ids[] = { | ||
406 | { .compatible = "imx-rng",}, | ||
407 | { .compatible = "fsl,imx-rng",}, | ||
408 | { .compatible = "fsl,imx6sl-rng",}, | ||
409 | { }, | ||
410 | }; | ||
411 | |||
412 | MODULE_DEVICE_TABLE(of, imx_rng_dt_ids); | ||
413 | |||
414 | static struct platform_driver imx_rng_driver = { | ||
415 | .driver = { | ||
416 | .name = MODULE_NAME, | ||
417 | .owner = THIS_MODULE, | ||
418 | .of_match_table = imx_rng_dt_ids, | ||
419 | }, | ||
420 | .remove = __exit_p(imx_rng_remove), | ||
421 | .suspend = imx_rng_suspend, | ||
422 | .resume = imx_rng_resume, | ||
423 | }; | ||
424 | |||
425 | static int __init mod_init(void) | ||
426 | { | ||
427 | return platform_driver_probe(&imx_rng_driver, imx_rng_probe); | ||
428 | } | ||
429 | |||
430 | static void __exit mod_exit(void) | ||
431 | { | ||
432 | platform_driver_unregister(&imx_rng_driver); | ||
433 | } | ||
434 | |||
435 | module_init(mod_init); | ||
436 | module_exit(mod_exit); | ||
437 | |||
438 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
439 | MODULE_DESCRIPTION("H/W RNG(B/C) driver for i.MX"); | ||
440 | MODULE_LICENSE("GPL"); | ||