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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc8 173 lines 3.7 kB view raw
1/* 2 * Broadcom BCM63xx Random Number Generator support 3 * 4 * Copyright (C) 2011, Florian Fainelli <florian@openwrt.org> 5 * Copyright (C) 2009, Broadcom Corporation 6 * 7 */ 8#include <linux/module.h> 9#include <linux/slab.h> 10#include <linux/io.h> 11#include <linux/err.h> 12#include <linux/clk.h> 13#include <linux/platform_device.h> 14#include <linux/hw_random.h> 15 16#include <bcm63xx_io.h> 17#include <bcm63xx_regs.h> 18 19struct bcm63xx_rng_priv { 20 struct clk *clk; 21 void __iomem *regs; 22}; 23 24#define to_rng_priv(rng) ((struct bcm63xx_rng_priv *)rng->priv) 25 26static int bcm63xx_rng_init(struct hwrng *rng) 27{ 28 struct bcm63xx_rng_priv *priv = to_rng_priv(rng); 29 u32 val; 30 31 val = bcm_readl(priv->regs + RNG_CTRL); 32 val |= RNG_EN; 33 bcm_writel(val, priv->regs + RNG_CTRL); 34 35 return 0; 36} 37 38static void bcm63xx_rng_cleanup(struct hwrng *rng) 39{ 40 struct bcm63xx_rng_priv *priv = to_rng_priv(rng); 41 u32 val; 42 43 val = bcm_readl(priv->regs + RNG_CTRL); 44 val &= ~RNG_EN; 45 bcm_writel(val, priv->regs + RNG_CTRL); 46} 47 48static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) 49{ 50 struct bcm63xx_rng_priv *priv = to_rng_priv(rng); 51 52 return bcm_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK; 53} 54 55static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data) 56{ 57 struct bcm63xx_rng_priv *priv = to_rng_priv(rng); 58 59 *data = bcm_readl(priv->regs + RNG_DATA); 60 61 return 4; 62} 63 64static int bcm63xx_rng_probe(struct platform_device *pdev) 65{ 66 struct resource *r; 67 struct clk *clk; 68 int ret; 69 struct bcm63xx_rng_priv *priv; 70 struct hwrng *rng; 71 72 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 73 if (!r) { 74 dev_err(&pdev->dev, "no iomem resource\n"); 75 ret = -ENXIO; 76 goto out; 77 } 78 79 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 80 if (!priv) { 81 dev_err(&pdev->dev, "no memory for private structure\n"); 82 ret = -ENOMEM; 83 goto out; 84 } 85 86 rng = kzalloc(sizeof(*rng), GFP_KERNEL); 87 if (!rng) { 88 dev_err(&pdev->dev, "no memory for rng structure\n"); 89 ret = -ENOMEM; 90 goto out_free_priv; 91 } 92 93 platform_set_drvdata(pdev, rng); 94 rng->priv = (unsigned long)priv; 95 rng->name = pdev->name; 96 rng->init = bcm63xx_rng_init; 97 rng->cleanup = bcm63xx_rng_cleanup; 98 rng->data_present = bcm63xx_rng_data_present; 99 rng->data_read = bcm63xx_rng_data_read; 100 101 clk = clk_get(&pdev->dev, "ipsec"); 102 if (IS_ERR(clk)) { 103 dev_err(&pdev->dev, "no clock for device\n"); 104 ret = PTR_ERR(clk); 105 goto out_free_rng; 106 } 107 108 priv->clk = clk; 109 110 if (!devm_request_mem_region(&pdev->dev, r->start, 111 resource_size(r), pdev->name)) { 112 dev_err(&pdev->dev, "request mem failed"); 113 ret = -ENOMEM; 114 goto out_free_rng; 115 } 116 117 priv->regs = devm_ioremap_nocache(&pdev->dev, r->start, 118 resource_size(r)); 119 if (!priv->regs) { 120 dev_err(&pdev->dev, "ioremap failed"); 121 ret = -ENOMEM; 122 goto out_free_rng; 123 } 124 125 clk_enable(clk); 126 127 ret = hwrng_register(rng); 128 if (ret) { 129 dev_err(&pdev->dev, "failed to register rng device\n"); 130 goto out_clk_disable; 131 } 132 133 dev_info(&pdev->dev, "registered RNG driver\n"); 134 135 return 0; 136 137out_clk_disable: 138 clk_disable(clk); 139out_free_rng: 140 kfree(rng); 141out_free_priv: 142 kfree(priv); 143out: 144 return ret; 145} 146 147static int bcm63xx_rng_remove(struct platform_device *pdev) 148{ 149 struct hwrng *rng = platform_get_drvdata(pdev); 150 struct bcm63xx_rng_priv *priv = to_rng_priv(rng); 151 152 hwrng_unregister(rng); 153 clk_disable(priv->clk); 154 kfree(priv); 155 kfree(rng); 156 157 return 0; 158} 159 160static struct platform_driver bcm63xx_rng_driver = { 161 .probe = bcm63xx_rng_probe, 162 .remove = bcm63xx_rng_remove, 163 .driver = { 164 .name = "bcm63xx-rng", 165 .owner = THIS_MODULE, 166 }, 167}; 168 169module_platform_driver(bcm63xx_rng_driver); 170 171MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); 172MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver"); 173MODULE_LICENSE("GPL");