Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hw_random: add driver for atmel true hardware random number generator

For the IP block on 9g45/9g46/9m10/9m11.

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Peter Korsgaard and committed by
Nicolas Ferre
677d3e2f 237a62a1

+172
+13
drivers/char/hw_random/Kconfig
··· 60 60 61 61 If unsure, say Y. 62 62 63 + config HW_RANDOM_ATMEL 64 + tristate "Atmel Random Number Generator support" 65 + depends on HW_RANDOM && ARCH_AT91SAM9G45 66 + default HW_RANDOM 67 + ---help--- 68 + This driver provides kernel-side support for the Random Number 69 + Generator hardware found on Atmel AT91 devices. 70 + 71 + To compile this driver as a module, choose M here: the 72 + module will be called atmel-rng. 73 + 74 + If unsure, say Y. 75 + 63 76 config HW_RANDOM_GEODE 64 77 tristate "AMD Geode HW Random Number Generator support" 65 78 depends on HW_RANDOM && X86_32 && PCI
+1
drivers/char/hw_random/Makefile
··· 7 7 obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o 8 8 obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o 9 9 obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o 10 + obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o 10 11 obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o 11 12 obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o 12 13 n2-rng-y := n2-drv.o n2-asm.o
+158
drivers/char/hw_random/atmel-rng.c
··· 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 + 24 + struct atmel_trng { 25 + struct clk *clk; 26 + void __iomem *base; 27 + struct hwrng rng; 28 + }; 29 + 30 + static 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? */ 37 + if (readl(trng->base + TRNG_ODATA) & 1) { 38 + *data = readl(trng->base + TRNG_ODATA); 39 + return 4; 40 + } else 41 + return 0; 42 + } 43 + 44 + static int atmel_trng_probe(struct platform_device *pdev) 45 + { 46 + struct atmel_trng *trng; 47 + struct resource *res; 48 + int ret; 49 + 50 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 51 + if (!res) 52 + return -EINVAL; 53 + 54 + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); 55 + if (!trng) 56 + return -ENOMEM; 57 + 58 + if (!devm_request_mem_region(&pdev->dev, res->start, 59 + resource_size(res), pdev->name)) 60 + return -EBUSY; 61 + 62 + trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 63 + if (!trng->base) 64 + return -EBUSY; 65 + 66 + trng->clk = clk_get(&pdev->dev, NULL); 67 + if (IS_ERR(trng->clk)) 68 + return PTR_ERR(trng->clk); 69 + 70 + ret = clk_enable(trng->clk); 71 + if (ret) 72 + goto err_enable; 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 + 86 + err_register: 87 + clk_disable(trng->clk); 88 + err_enable: 89 + clk_put(trng->clk); 90 + 91 + return ret; 92 + } 93 + 94 + static int __devexit atmel_trng_remove(struct platform_device *pdev) 95 + { 96 + struct atmel_trng *trng = platform_get_drvdata(pdev); 97 + 98 + hwrng_unregister(&trng->rng); 99 + 100 + writel(TRNG_KEY, trng->base + TRNG_CR); 101 + clk_disable(trng->clk); 102 + clk_put(trng->clk); 103 + 104 + platform_set_drvdata(pdev, NULL); 105 + 106 + return 0; 107 + } 108 + 109 + #ifdef CONFIG_PM 110 + static int atmel_trng_suspend(struct device *dev) 111 + { 112 + struct atmel_trng *trng = dev_get_drvdata(dev); 113 + 114 + clk_disable(trng->clk); 115 + 116 + return 0; 117 + } 118 + 119 + static int atmel_trng_resume(struct device *dev) 120 + { 121 + struct atmel_trng *trng = dev_get_drvdata(dev); 122 + 123 + return clk_enable(trng->clk); 124 + } 125 + 126 + static const struct dev_pm_ops atmel_trng_pm_ops = { 127 + .suspend = atmel_trng_suspend, 128 + .resume = atmel_trng_resume, 129 + }; 130 + #endif /* CONFIG_PM */ 131 + 132 + static struct platform_driver atmel_trng_driver = { 133 + .probe = atmel_trng_probe, 134 + .remove = __devexit_p(atmel_trng_remove), 135 + .driver = { 136 + .name = "atmel-trng", 137 + .owner = THIS_MODULE, 138 + #ifdef CONFIG_PM 139 + .pm = &atmel_trng_pm_ops, 140 + #endif /* CONFIG_PM */ 141 + }, 142 + }; 143 + 144 + static int __init atmel_trng_init(void) 145 + { 146 + return platform_driver_register(&atmel_trng_driver); 147 + } 148 + module_init(atmel_trng_init); 149 + 150 + static void __exit atmel_trng_exit(void) 151 + { 152 + platform_driver_unregister(&atmel_trng_driver); 153 + } 154 + module_exit(atmel_trng_exit); 155 + 156 + MODULE_LICENSE("GPL"); 157 + MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); 158 + MODULE_DESCRIPTION("Atmel true random number generator driver");