2 * Copyright (c) 2011 Peter Korsgaard <jacmet@sunsite.dk>
4 * This file is licensed under the terms of the GNU General Public
5 * License version 2. This program is licensed "as is" without any
6 * warranty of any kind, whether express or implied.
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/err.h>
13 #include <linux/clk.h>
15 #include <linux/hw_random.h>
16 #include <linux/platform_device.h>
20 #define TRNG_ODATA 0x50
22 #define TRNG_KEY 0x524e4700 /* RNG */
30 static int atmel_trng_read(struct hwrng
*rng
, void *buf
, size_t max
,
33 struct atmel_trng
*trng
= container_of(rng
, struct atmel_trng
, rng
);
37 if (readl(trng
->base
+ TRNG_ODATA
) & 1) {
38 *data
= readl(trng
->base
+ TRNG_ODATA
);
44 static int atmel_trng_probe(struct platform_device
*pdev
)
46 struct atmel_trng
*trng
;
50 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
54 trng
= devm_kzalloc(&pdev
->dev
, sizeof(*trng
), GFP_KERNEL
);
58 if (!devm_request_mem_region(&pdev
->dev
, res
->start
,
59 resource_size(res
), pdev
->name
))
62 trng
->base
= devm_ioremap(&pdev
->dev
, res
->start
, resource_size(res
));
66 trng
->clk
= clk_get(&pdev
->dev
, NULL
);
67 if (IS_ERR(trng
->clk
))
68 return PTR_ERR(trng
->clk
);
70 ret
= clk_enable(trng
->clk
);
74 writel(TRNG_KEY
| 1, trng
->base
+ TRNG_CR
);
75 trng
->rng
.name
= pdev
->name
;
76 trng
->rng
.read
= atmel_trng_read
;
78 ret
= hwrng_register(&trng
->rng
);
82 platform_set_drvdata(pdev
, trng
);
87 clk_disable(trng
->clk
);
94 static int __devexit
atmel_trng_remove(struct platform_device
*pdev
)
96 struct atmel_trng
*trng
= platform_get_drvdata(pdev
);
98 hwrng_unregister(&trng
->rng
);
100 writel(TRNG_KEY
, trng
->base
+ TRNG_CR
);
101 clk_disable(trng
->clk
);
104 platform_set_drvdata(pdev
, NULL
);
110 static int atmel_trng_suspend(struct device
*dev
)
112 struct atmel_trng
*trng
= dev_get_drvdata(dev
);
114 clk_disable(trng
->clk
);
119 static int atmel_trng_resume(struct device
*dev
)
121 struct atmel_trng
*trng
= dev_get_drvdata(dev
);
123 return clk_enable(trng
->clk
);
126 static const struct dev_pm_ops atmel_trng_pm_ops
= {
127 .suspend
= atmel_trng_suspend
,
128 .resume
= atmel_trng_resume
,
130 #endif /* CONFIG_PM */
132 static struct platform_driver atmel_trng_driver
= {
133 .probe
= atmel_trng_probe
,
134 .remove
= __devexit_p(atmel_trng_remove
),
136 .name
= "atmel-trng",
137 .owner
= THIS_MODULE
,
139 .pm
= &atmel_trng_pm_ops
,
140 #endif /* CONFIG_PM */
144 module_platform_driver(atmel_trng_driver
);
146 MODULE_LICENSE("GPL");
147 MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
148 MODULE_DESCRIPTION("Atmel true random number generator driver");