1 /* 2 * omap-rng.c - RNG driver for TI OMAP CPU family 3 * 4 * Author: Deepak Saxena <dsaxena@plexity.net> 5 * 6 * Copyright 2005 (c) MontaVista Software, Inc. 7 * 8 * Mostly based on original driver: 9 * 10 * Copyright (C) 2005 Nokia Corporation 11 * Author: Juha Yrjölä <juha.yrjola@nokia.com> 12 * 13 * This file is licensed under the terms of the GNU General Public 14 * License version 2. This program is licensed "as is" without any 15 * warranty of any kind, whether express or implied. 16 */ 17 18 #include <linux/module.h> 19 #include <linux/init.h> 20 #include <linux/random.h> 21 #include <linux/err.h> 22 #include <linux/platform_device.h> 23 #include <linux/hw_random.h> 24 #include <linux/delay.h> 25 #include <linux/slab.h> 26 #include <linux/pm_runtime.h> 27 28 #include <asm/io.h> 29 30 #define RNG_OUT_REG 0x00 /* Output register */ 31 #define RNG_STAT_REG 0x04 /* Status register 32 [0] = STAT_BUSY */ 33 #define RNG_ALARM_REG 0x24 /* Alarm register 34 [7:0] = ALARM_COUNTER */ 35 #define RNG_CONFIG_REG 0x28 /* Configuration register 36 [11:6] = RESET_COUNT 37 [5:3] = RING2_DELAY 38 [2:0] = RING1_DELAY */ 39 #define RNG_REV_REG 0x3c /* Revision register 40 [7:0] = REV_NB */ 41 #define RNG_MASK_REG 0x40 /* Mask and reset register 42 [2] = IT_EN 43 [1] = SOFTRESET 44 [0] = AUTOIDLE */ 45 #define RNG_SYSSTATUS 0x44 /* System status 46 [0] = RESETDONE */ 47 48 /** 49 * struct omap_rng_private_data - RNG IP block-specific data 50 * @base: virtual address of the beginning of the RNG IP block registers 51 * @mem_res: struct resource * for the IP block registers physical memory 52 */ 53 struct omap_rng_private_data { 54 void __iomem *base; 55 struct resource *mem_res; 56 }; 57 58 static inline u32 omap_rng_read_reg(struct omap_rng_private_data *priv, int reg) 59 { 60 return __raw_readl(priv->base + reg); 61 } 62 63 static inline void omap_rng_write_reg(struct omap_rng_private_data *priv, 64 int reg, u32 val) 65 { 66 __raw_writel(val, priv->base + reg); 67 } 68 69 static int omap_rng_data_present(struct hwrng *rng, int wait) 70 { 71 struct omap_rng_private_data *priv; 72 int data, i; 73 74 priv = (struct omap_rng_private_data *)rng->priv; 75 76 for (i = 0; i < 20; i++) { 77 data = omap_rng_read_reg(priv, RNG_STAT_REG) ? 0 : 1; 78 if (data || !wait) 79 break; 80 /* RNG produces data fast enough (2+ MBit/sec, even 81 * during "rngtest" loads, that these delays don't 82 * seem to trigger. We *could* use the RNG IRQ, but 83 * that'd be higher overhead ... so why bother? 84 */ 85 udelay(10); 86 } 87 return data; 88 } 89 90 static int omap_rng_data_read(struct hwrng *rng, u32 *data) 91 { 92 struct omap_rng_private_data *priv; 93 94 priv = (struct omap_rng_private_data *)rng->priv; 95 96 *data = omap_rng_read_reg(priv, RNG_OUT_REG); 97 98 return sizeof(u32); 99 } 100 101 static struct hwrng omap_rng_ops = { 102 .name = "omap", 103 .data_present = omap_rng_data_present, 104 .data_read = omap_rng_data_read, 105 }; 106 107 static int __devinit omap_rng_probe(struct platform_device *pdev) 108 { 109 struct omap_rng_private_data *priv; 110 int ret; 111 112 priv = kzalloc(sizeof(struct omap_rng_private_data), GFP_KERNEL); 113 if (!priv) { 114 dev_err(&pdev->dev, "could not allocate memory\n"); 115 return -ENOMEM; 116 }; 117 118 omap_rng_ops.priv = (unsigned long)priv; 119 dev_set_drvdata(&pdev->dev, priv); 120 121 priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 122 if (!priv->mem_res) { 123 ret = -ENOENT; 124 goto err_ioremap; 125 } 126 127 priv->base = devm_request_and_ioremap(&pdev->dev, priv->mem_res); 128 if (!priv->base) { 129 ret = -ENOMEM; 130 goto err_ioremap; 131 } 132 dev_set_drvdata(&pdev->dev, priv); 133 134 pm_runtime_enable(&pdev->dev); 135 pm_runtime_get_sync(&pdev->dev); 136 137 ret = hwrng_register(&omap_rng_ops); 138 if (ret) 139 goto err_register; 140 141 dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", 142 omap_rng_read_reg(priv, RNG_REV_REG)); 143 144 omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); 145 146 return 0; 147 148 err_register: 149 priv->base = NULL; 150 pm_runtime_disable(&pdev->dev); 151 err_ioremap: 152 kfree(priv); 153 154 return ret; 155 } 156 157 static int __exit omap_rng_remove(struct platform_device *pdev) 158 { 159 struct omap_rng_private_data *priv = dev_get_drvdata(&pdev->dev); 160 161 hwrng_unregister(&omap_rng_ops); 162 163 omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); 164 165 pm_runtime_put_sync(&pdev->dev); 166 pm_runtime_disable(&pdev->dev); 167 168 release_mem_region(priv->mem_res->start, resource_size(priv->mem_res)); 169 170 kfree(priv); 171 172 return 0; 173 } 174 175 #ifdef CONFIG_PM_SLEEP 176 177 static int omap_rng_suspend(struct device *dev) 178 { 179 struct omap_rng_private_data *priv = dev_get_drvdata(dev); 180 181 omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); 182 pm_runtime_put_sync(dev); 183 184 return 0; 185 } 186 187 static int omap_rng_resume(struct device *dev) 188 { 189 struct omap_rng_private_data *priv = dev_get_drvdata(dev); 190 191 pm_runtime_get_sync(dev); 192 omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); 193 194 return 0; 195 } 196 197 static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume); 198 #define OMAP_RNG_PM (&omap_rng_pm) 199 200 #else 201 202 #define OMAP_RNG_PM NULL 203 204 #endif 205 206 /* work with hotplug and coldplug */ 207 MODULE_ALIAS("platform:omap_rng"); 208 209 static struct platform_driver omap_rng_driver = { 210 .driver = { 211 .name = "omap_rng", 212 .owner = THIS_MODULE, 213 .pm = OMAP_RNG_PM, 214 }, 215 .probe = omap_rng_probe, 216 .remove = __exit_p(omap_rng_remove), 217 }; 218 219 static int __init omap_rng_init(void) 220 { 221 return platform_driver_register(&omap_rng_driver); 222 } 223 224 static void __exit omap_rng_exit(void) 225 { 226 platform_driver_unregister(&omap_rng_driver); 227 } 228 229 module_init(omap_rng_init); 230 module_exit(omap_rng_exit); 231 232 MODULE_AUTHOR("Deepak Saxena (and others)"); 233 MODULE_LICENSE("GPL"); 234