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