This source file includes following definitions.
- atmel_trng_read
- atmel_trng_enable
- atmel_trng_disable
- atmel_trng_probe
- atmel_trng_remove
- atmel_trng_suspend
- atmel_trng_resume
1
2
3
4
5
6
7
8
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/slab.h>
13 #include <linux/err.h>
14 #include <linux/clk.h>
15 #include <linux/io.h>
16 #include <linux/hw_random.h>
17 #include <linux/platform_device.h>
18
19 #define TRNG_CR 0x00
20 #define TRNG_ISR 0x1c
21 #define TRNG_ODATA 0x50
22
23 #define TRNG_KEY 0x524e4700
24
25 struct atmel_trng {
26 struct clk *clk;
27 void __iomem *base;
28 struct hwrng rng;
29 };
30
31 static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
32 bool wait)
33 {
34 struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng);
35 u32 *data = buf;
36
37
38 if (readl(trng->base + TRNG_ISR) & 1) {
39 *data = readl(trng->base + TRNG_ODATA);
40
41
42
43
44
45
46 readl(trng->base + TRNG_ISR);
47 return 4;
48 } else
49 return 0;
50 }
51
52 static void atmel_trng_enable(struct atmel_trng *trng)
53 {
54 writel(TRNG_KEY | 1, trng->base + TRNG_CR);
55 }
56
57 static void atmel_trng_disable(struct atmel_trng *trng)
58 {
59 writel(TRNG_KEY, trng->base + TRNG_CR);
60 }
61
62 static int atmel_trng_probe(struct platform_device *pdev)
63 {
64 struct atmel_trng *trng;
65 struct resource *res;
66 int ret;
67
68 trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
69 if (!trng)
70 return -ENOMEM;
71
72 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
73 trng->base = devm_ioremap_resource(&pdev->dev, res);
74 if (IS_ERR(trng->base))
75 return PTR_ERR(trng->base);
76
77 trng->clk = devm_clk_get(&pdev->dev, NULL);
78 if (IS_ERR(trng->clk))
79 return PTR_ERR(trng->clk);
80
81 ret = clk_prepare_enable(trng->clk);
82 if (ret)
83 return ret;
84
85 atmel_trng_enable(trng);
86 trng->rng.name = pdev->name;
87 trng->rng.read = atmel_trng_read;
88
89 ret = devm_hwrng_register(&pdev->dev, &trng->rng);
90 if (ret)
91 goto err_register;
92
93 platform_set_drvdata(pdev, trng);
94
95 return 0;
96
97 err_register:
98 clk_disable_unprepare(trng->clk);
99 return ret;
100 }
101
102 static int atmel_trng_remove(struct platform_device *pdev)
103 {
104 struct atmel_trng *trng = platform_get_drvdata(pdev);
105
106
107 atmel_trng_disable(trng);
108 clk_disable_unprepare(trng->clk);
109
110 return 0;
111 }
112
113 #ifdef CONFIG_PM
114 static int atmel_trng_suspend(struct device *dev)
115 {
116 struct atmel_trng *trng = dev_get_drvdata(dev);
117
118 atmel_trng_disable(trng);
119 clk_disable_unprepare(trng->clk);
120
121 return 0;
122 }
123
124 static int atmel_trng_resume(struct device *dev)
125 {
126 struct atmel_trng *trng = dev_get_drvdata(dev);
127 int ret;
128
129 ret = clk_prepare_enable(trng->clk);
130 if (ret)
131 return ret;
132
133 atmel_trng_enable(trng);
134
135 return 0;
136 }
137
138 static const struct dev_pm_ops atmel_trng_pm_ops = {
139 .suspend = atmel_trng_suspend,
140 .resume = atmel_trng_resume,
141 };
142 #endif
143
144 static const struct of_device_id atmel_trng_dt_ids[] = {
145 { .compatible = "atmel,at91sam9g45-trng" },
146 { }
147 };
148 MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids);
149
150 static struct platform_driver atmel_trng_driver = {
151 .probe = atmel_trng_probe,
152 .remove = atmel_trng_remove,
153 .driver = {
154 .name = "atmel-trng",
155 #ifdef CONFIG_PM
156 .pm = &atmel_trng_pm_ops,
157 #endif
158 .of_match_table = atmel_trng_dt_ids,
159 },
160 };
161
162 module_platform_driver(atmel_trng_driver);
163
164 MODULE_LICENSE("GPL");
165 MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
166 MODULE_DESCRIPTION("Atmel true random number generator driver");