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/mod_devicetable.h>
12 #include <linux/slab.h>
13 #include <linux/err.h>
14 #include <linux/clk.h>
16 #include <linux/iopoll.h>
17 #include <linux/hw_random.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
25 #define TRNG_ISR_DATRDY BIT(0)
26 #define TRNG_ODATA 0x50
28 #define TRNG_KEY 0x524e4700 /* RNG */
30 #define TRNG_HALFR BIT(0) /* generate RN every 168 cycles */
32 struct atmel_trng_data
{
43 static bool atmel_trng_wait_ready(struct atmel_trng
*trng
, bool wait
)
47 ready
= readl(trng
->base
+ TRNG_ISR
) & TRNG_ISR_DATRDY
;
49 readl_poll_timeout(trng
->base
+ TRNG_ISR
, ready
,
50 ready
& TRNG_ISR_DATRDY
, 1000, 20000);
55 static int atmel_trng_read(struct hwrng
*rng
, void *buf
, size_t max
,
58 struct atmel_trng
*trng
= container_of(rng
, struct atmel_trng
, rng
);
62 ret
= pm_runtime_get_sync((struct device
*)trng
->rng
.priv
);
64 pm_runtime_put_sync((struct device
*)trng
->rng
.priv
);
68 ret
= atmel_trng_wait_ready(trng
, wait
);
72 *data
= readl(trng
->base
+ TRNG_ODATA
);
74 * ensure data ready is only set again AFTER the next data word is ready
75 * in case it got set between checking ISR and reading ODATA, so we
76 * don't risk re-reading the same word
78 readl(trng
->base
+ TRNG_ISR
);
82 pm_runtime_mark_last_busy((struct device
*)trng
->rng
.priv
);
83 pm_runtime_put_sync_autosuspend((struct device
*)trng
->rng
.priv
);
87 static int atmel_trng_init(struct atmel_trng
*trng
)
92 ret
= clk_prepare_enable(trng
->clk
);
96 if (trng
->has_half_rate
) {
97 rate
= clk_get_rate(trng
->clk
);
99 /* if peripheral clk is above 100MHz, set HALFR */
100 if (rate
> 100000000)
101 writel(TRNG_HALFR
, trng
->base
+ TRNG_MR
);
104 writel(TRNG_KEY
| 1, trng
->base
+ TRNG_CR
);
109 static void atmel_trng_cleanup(struct atmel_trng
*trng
)
111 writel(TRNG_KEY
, trng
->base
+ TRNG_CR
);
112 clk_disable_unprepare(trng
->clk
);
115 static int atmel_trng_probe(struct platform_device
*pdev
)
117 struct atmel_trng
*trng
;
118 const struct atmel_trng_data
*data
;
121 trng
= devm_kzalloc(&pdev
->dev
, sizeof(*trng
), GFP_KERNEL
);
125 trng
->base
= devm_platform_ioremap_resource(pdev
, 0);
126 if (IS_ERR(trng
->base
))
127 return PTR_ERR(trng
->base
);
129 trng
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
130 if (IS_ERR(trng
->clk
))
131 return PTR_ERR(trng
->clk
);
132 data
= of_device_get_match_data(&pdev
->dev
);
136 trng
->has_half_rate
= data
->has_half_rate
;
137 trng
->rng
.name
= pdev
->name
;
138 trng
->rng
.read
= atmel_trng_read
;
139 trng
->rng
.priv
= (unsigned long)&pdev
->dev
;
140 platform_set_drvdata(pdev
, trng
);
143 ret
= atmel_trng_init(trng
);
148 pm_runtime_set_autosuspend_delay(&pdev
->dev
, 100);
149 pm_runtime_use_autosuspend(&pdev
->dev
);
150 pm_runtime_enable(&pdev
->dev
);
152 ret
= devm_hwrng_register(&pdev
->dev
, &trng
->rng
);
154 pm_runtime_disable(&pdev
->dev
);
155 pm_runtime_set_suspended(&pdev
->dev
);
157 atmel_trng_cleanup(trng
);
164 static void atmel_trng_remove(struct platform_device
*pdev
)
166 struct atmel_trng
*trng
= platform_get_drvdata(pdev
);
168 atmel_trng_cleanup(trng
);
169 pm_runtime_disable(&pdev
->dev
);
170 pm_runtime_set_suspended(&pdev
->dev
);
173 static int __maybe_unused
atmel_trng_runtime_suspend(struct device
*dev
)
175 struct atmel_trng
*trng
= dev_get_drvdata(dev
);
177 atmel_trng_cleanup(trng
);
182 static int __maybe_unused
atmel_trng_runtime_resume(struct device
*dev
)
184 struct atmel_trng
*trng
= dev_get_drvdata(dev
);
186 return atmel_trng_init(trng
);
189 static const struct dev_pm_ops __maybe_unused atmel_trng_pm_ops
= {
190 SET_RUNTIME_PM_OPS(atmel_trng_runtime_suspend
,
191 atmel_trng_runtime_resume
, NULL
)
192 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
193 pm_runtime_force_resume
)
196 static const struct atmel_trng_data at91sam9g45_config
= {
197 .has_half_rate
= false,
200 static const struct atmel_trng_data sam9x60_config
= {
201 .has_half_rate
= true,
204 static const struct of_device_id atmel_trng_dt_ids
[] = {
206 .compatible
= "atmel,at91sam9g45-trng",
207 .data
= &at91sam9g45_config
,
209 .compatible
= "microchip,sam9x60-trng",
210 .data
= &sam9x60_config
,
215 MODULE_DEVICE_TABLE(of
, atmel_trng_dt_ids
);
217 static struct platform_driver atmel_trng_driver
= {
218 .probe
= atmel_trng_probe
,
219 .remove
= atmel_trng_remove
,
221 .name
= "atmel-trng",
222 .pm
= pm_ptr(&atmel_trng_pm_ops
),
223 .of_match_table
= atmel_trng_dt_ids
,
227 module_platform_driver(atmel_trng_driver
);
229 MODULE_LICENSE("GPL");
230 MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
231 MODULE_DESCRIPTION("Atmel true random number generator driver");