2 * drivers/char/hw_random/timeriomem-rng.c
4 * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk>
6 * Derived from drivers/char/hw_random/omap-rng.c
7 * Copyright 2005 (c) MontaVista Software, Inc.
8 * Author: Deepak Saxena <dsaxena@plexity.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 * This driver is useful for platforms that have an IO range that provides
16 * periodic random data from a single IO memory address. All the platform
17 * has to do is provide the address and 'wait time' that new data becomes
20 * TODO: add support for reading sizes other than 32bits and masking
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/platform_device.h>
27 #include <linux/hw_random.h>
29 #include <linux/slab.h>
30 #include <linux/timeriomem-rng.h>
31 #include <linux/jiffies.h>
32 #include <linux/sched.h>
33 #include <linux/timer.h>
34 #include <linux/completion.h>
36 struct timeriomem_rng_private_data
{
37 void __iomem
*io_base
;
40 unsigned int present
:1;
42 struct timer_list timer
;
43 struct completion completion
;
45 struct hwrng timeriomem_rng_ops
;
48 #define to_rng_priv(rng) \
49 ((struct timeriomem_rng_private_data *)rng->priv)
52 * have data return 1, however return 0 if we have nothing
54 static int timeriomem_rng_data_present(struct hwrng
*rng
, int wait
)
56 struct timeriomem_rng_private_data
*priv
= to_rng_priv(rng
);
58 if (!wait
|| priv
->present
)
61 wait_for_completion(&priv
->completion
);
66 static int timeriomem_rng_data_read(struct hwrng
*rng
, u32
*data
)
68 struct timeriomem_rng_private_data
*priv
= to_rng_priv(rng
);
72 *data
= readl(priv
->io_base
);
76 delay
= cur
- priv
->expires
;
77 delay
= priv
->period
- (delay
% priv
->period
);
79 priv
->expires
= cur
+ delay
;
82 reinit_completion(&priv
->completion
);
83 mod_timer(&priv
->timer
, priv
->expires
);
88 static void timeriomem_rng_trigger(unsigned long data
)
90 struct timeriomem_rng_private_data
*priv
91 = (struct timeriomem_rng_private_data
*)data
;
94 complete(&priv
->completion
);
97 static int timeriomem_rng_probe(struct platform_device
*pdev
)
99 struct timeriomem_rng_data
*pdata
= pdev
->dev
.platform_data
;
100 struct timeriomem_rng_private_data
*priv
;
101 struct resource
*res
;
105 if (!pdev
->dev
.of_node
&& !pdata
) {
106 dev_err(&pdev
->dev
, "timeriomem_rng_data is missing\n");
110 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
114 if (res
->start
% 4 != 0 || resource_size(res
) != 4) {
116 "address must be four bytes wide and aligned\n");
120 /* Allocate memory for the device structure (and zero it) */
121 priv
= kzalloc(sizeof(struct timeriomem_rng_private_data
), GFP_KERNEL
);
123 dev_err(&pdev
->dev
, "failed to allocate device structure.\n");
127 platform_set_drvdata(pdev
, priv
);
129 if (pdev
->dev
.of_node
) {
132 if (!of_property_read_u32(pdev
->dev
.of_node
,
136 dev_err(&pdev
->dev
, "missing period\n");
141 period
= pdata
->period
;
143 priv
->period
= usecs_to_jiffies(period
);
144 if (priv
->period
< 1) {
145 dev_err(&pdev
->dev
, "period is less than one jiffy\n");
150 priv
->expires
= jiffies
;
153 init_completion(&priv
->completion
);
154 complete(&priv
->completion
);
156 setup_timer(&priv
->timer
, timeriomem_rng_trigger
, (unsigned long)priv
);
158 priv
->timeriomem_rng_ops
.name
= dev_name(&pdev
->dev
);
159 priv
->timeriomem_rng_ops
.data_present
= timeriomem_rng_data_present
;
160 priv
->timeriomem_rng_ops
.data_read
= timeriomem_rng_data_read
;
161 priv
->timeriomem_rng_ops
.priv
= (unsigned long)priv
;
163 if (!request_mem_region(res
->start
, resource_size(res
),
164 dev_name(&pdev
->dev
))) {
165 dev_err(&pdev
->dev
, "request_mem_region failed\n");
170 priv
->io_base
= ioremap(res
->start
, resource_size(res
));
171 if (priv
->io_base
== NULL
) {
172 dev_err(&pdev
->dev
, "ioremap failed\n");
177 err
= hwrng_register(&priv
->timeriomem_rng_ops
);
179 dev_err(&pdev
->dev
, "problem registering\n");
183 dev_info(&pdev
->dev
, "32bits from 0x%p @ %dus\n",
184 priv
->io_base
, period
);
189 iounmap(priv
->io_base
);
191 release_mem_region(res
->start
, resource_size(res
));
193 del_timer_sync(&priv
->timer
);
199 static int timeriomem_rng_remove(struct platform_device
*pdev
)
201 struct timeriomem_rng_private_data
*priv
= platform_get_drvdata(pdev
);
202 struct resource
*res
;
204 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
206 hwrng_unregister(&priv
->timeriomem_rng_ops
);
208 del_timer_sync(&priv
->timer
);
209 iounmap(priv
->io_base
);
210 release_mem_region(res
->start
, resource_size(res
));
216 static const struct of_device_id timeriomem_rng_match
[] = {
217 { .compatible
= "timeriomem_rng" },
220 MODULE_DEVICE_TABLE(of
, timeriomem_rng_match
);
222 static struct platform_driver timeriomem_rng_driver
= {
224 .name
= "timeriomem_rng",
225 .owner
= THIS_MODULE
,
226 .of_match_table
= timeriomem_rng_match
,
228 .probe
= timeriomem_rng_probe
,
229 .remove
= timeriomem_rng_remove
,
232 module_platform_driver(timeriomem_rng_driver
);
234 MODULE_LICENSE("GPL");
235 MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
236 MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");