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
= devm_kzalloc(&pdev
->dev
,
122 sizeof(struct timeriomem_rng_private_data
), GFP_KERNEL
);
126 platform_set_drvdata(pdev
, priv
);
128 if (pdev
->dev
.of_node
) {
131 if (!of_property_read_u32(pdev
->dev
.of_node
,
135 dev_err(&pdev
->dev
, "missing period\n");
139 period
= pdata
->period
;
142 priv
->period
= usecs_to_jiffies(period
);
143 if (priv
->period
< 1) {
144 dev_err(&pdev
->dev
, "period is less than one jiffy\n");
148 priv
->expires
= jiffies
;
151 init_completion(&priv
->completion
);
152 complete(&priv
->completion
);
154 setup_timer(&priv
->timer
, timeriomem_rng_trigger
, (unsigned long)priv
);
156 priv
->timeriomem_rng_ops
.name
= dev_name(&pdev
->dev
);
157 priv
->timeriomem_rng_ops
.data_present
= timeriomem_rng_data_present
;
158 priv
->timeriomem_rng_ops
.data_read
= timeriomem_rng_data_read
;
159 priv
->timeriomem_rng_ops
.priv
= (unsigned long)priv
;
161 priv
->io_base
= devm_ioremap_resource(&pdev
->dev
, res
);
162 if (IS_ERR(priv
->io_base
)) {
163 err
= PTR_ERR(priv
->io_base
);
167 err
= hwrng_register(&priv
->timeriomem_rng_ops
);
169 dev_err(&pdev
->dev
, "problem registering\n");
173 dev_info(&pdev
->dev
, "32bits from 0x%p @ %dus\n",
174 priv
->io_base
, period
);
179 del_timer_sync(&priv
->timer
);
183 static int timeriomem_rng_remove(struct platform_device
*pdev
)
185 struct timeriomem_rng_private_data
*priv
= platform_get_drvdata(pdev
);
187 hwrng_unregister(&priv
->timeriomem_rng_ops
);
189 del_timer_sync(&priv
->timer
);
194 static const struct of_device_id timeriomem_rng_match
[] = {
195 { .compatible
= "timeriomem_rng" },
198 MODULE_DEVICE_TABLE(of
, timeriomem_rng_match
);
200 static struct platform_driver timeriomem_rng_driver
= {
202 .name
= "timeriomem_rng",
203 .of_match_table
= timeriomem_rng_match
,
205 .probe
= timeriomem_rng_probe
,
206 .remove
= timeriomem_rng_remove
,
209 module_platform_driver(timeriomem_rng_driver
);
211 MODULE_LICENSE("GPL");
212 MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
213 MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");