Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[deliverable/linux.git] / drivers / char / hw_random / atmel-rng.c
CommitLineData
677d3e2f
PK
1/*
2 * Copyright (c) 2011 Peter Korsgaard <jacmet@sunsite.dk>
3 *
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.
7 */
8
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>
14#include <linux/io.h>
15#include <linux/hw_random.h>
16#include <linux/platform_device.h>
17
18#define TRNG_CR 0x00
19#define TRNG_ISR 0x1c
20#define TRNG_ODATA 0x50
21
22#define TRNG_KEY 0x524e4700 /* RNG */
23
24struct atmel_trng {
25 struct clk *clk;
26 void __iomem *base;
27 struct hwrng rng;
28};
29
30static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
31 bool wait)
32{
33 struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng);
34 u32 *data = buf;
35
36 /* data ready? */
c475c06f 37 if (readl(trng->base + TRNG_ISR) & 1) {
677d3e2f 38 *data = readl(trng->base + TRNG_ODATA);
121daad8
PK
39 /*
40 ensure data ready is only set again AFTER the next data
41 word is ready in case it got set between checking ISR
42 and reading ODATA, so we don't risk re-reading the
43 same word
44 */
45 readl(trng->base + TRNG_ISR);
677d3e2f
PK
46 return 4;
47 } else
48 return 0;
49}
50
51static int atmel_trng_probe(struct platform_device *pdev)
52{
53 struct atmel_trng *trng;
54 struct resource *res;
55 int ret;
56
677d3e2f
PK
57 trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
58 if (!trng)
59 return -ENOMEM;
60
bfaff75b
JH
61 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
62 trng->base = devm_ioremap_resource(&pdev->dev, res);
63 if (IS_ERR(trng->base))
64 return PTR_ERR(trng->base);
677d3e2f 65
0c0becd0 66 trng->clk = devm_clk_get(&pdev->dev, NULL);
677d3e2f
PK
67 if (IS_ERR(trng->clk))
68 return PTR_ERR(trng->clk);
69
21961efa 70 ret = clk_prepare_enable(trng->clk);
677d3e2f 71 if (ret)
0c0becd0 72 return ret;
677d3e2f
PK
73
74 writel(TRNG_KEY | 1, trng->base + TRNG_CR);
75 trng->rng.name = pdev->name;
76 trng->rng.read = atmel_trng_read;
77
78 ret = hwrng_register(&trng->rng);
79 if (ret)
80 goto err_register;
81
82 platform_set_drvdata(pdev, trng);
83
84 return 0;
85
86err_register:
87 clk_disable(trng->clk);
677d3e2f
PK
88 return ret;
89}
90
39af33fc 91static int atmel_trng_remove(struct platform_device *pdev)
677d3e2f
PK
92{
93 struct atmel_trng *trng = platform_get_drvdata(pdev);
94
95 hwrng_unregister(&trng->rng);
96
97 writel(TRNG_KEY, trng->base + TRNG_CR);
21961efa 98 clk_disable_unprepare(trng->clk);
677d3e2f 99
677d3e2f
PK
100 return 0;
101}
102
103#ifdef CONFIG_PM
104static int atmel_trng_suspend(struct device *dev)
105{
106 struct atmel_trng *trng = dev_get_drvdata(dev);
107
21961efa 108 clk_disable_unprepare(trng->clk);
677d3e2f
PK
109
110 return 0;
111}
112
113static int atmel_trng_resume(struct device *dev)
114{
115 struct atmel_trng *trng = dev_get_drvdata(dev);
116
21961efa 117 return clk_prepare_enable(trng->clk);
677d3e2f
PK
118}
119
120static const struct dev_pm_ops atmel_trng_pm_ops = {
121 .suspend = atmel_trng_suspend,
122 .resume = atmel_trng_resume,
123};
124#endif /* CONFIG_PM */
125
4951db7e
BB
126static const struct of_device_id atmel_trng_dt_ids[] = {
127 { .compatible = "atmel,at91sam9g45-trng" },
128 { /* sentinel */ }
129};
130MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids);
131
677d3e2f
PK
132static struct platform_driver atmel_trng_driver = {
133 .probe = atmel_trng_probe,
bcd2982a 134 .remove = atmel_trng_remove,
677d3e2f
PK
135 .driver = {
136 .name = "atmel-trng",
677d3e2f
PK
137#ifdef CONFIG_PM
138 .pm = &atmel_trng_pm_ops,
139#endif /* CONFIG_PM */
4951db7e 140 .of_match_table = atmel_trng_dt_ids,
677d3e2f
PK
141 },
142};
143
b21cb324 144module_platform_driver(atmel_trng_driver);
677d3e2f
PK
145
146MODULE_LICENSE("GPL");
147MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
148MODULE_DESCRIPTION("Atmel true random number generator driver");
This page took 0.583142 seconds and 5 git commands to generate.