2 * Broadcom BCM63xx Random Number Generator support
4 * Copyright (C) 2011, Florian Fainelli <florian@openwrt.org>
5 * Copyright (C) 2009, Broadcom Corporation
8 #include <linux/module.h>
9 #include <linux/slab.h>
11 #include <linux/err.h>
12 #include <linux/clk.h>
13 #include <linux/platform_device.h>
14 #include <linux/hw_random.h>
16 #include <bcm63xx_io.h>
17 #include <bcm63xx_regs.h>
19 struct bcm63xx_rng_priv
{
24 #define to_rng_priv(rng) ((struct bcm63xx_rng_priv *)rng->priv)
26 static int bcm63xx_rng_init(struct hwrng
*rng
)
28 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
31 val
= bcm_readl(priv
->regs
+ RNG_CTRL
);
33 bcm_writel(val
, priv
->regs
+ RNG_CTRL
);
38 static void bcm63xx_rng_cleanup(struct hwrng
*rng
)
40 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
43 val
= bcm_readl(priv
->regs
+ RNG_CTRL
);
45 bcm_writel(val
, priv
->regs
+ RNG_CTRL
);
48 static int bcm63xx_rng_data_present(struct hwrng
*rng
, int wait
)
50 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
52 return bcm_readl(priv
->regs
+ RNG_STAT
) & RNG_AVAIL_MASK
;
55 static int bcm63xx_rng_data_read(struct hwrng
*rng
, u32
*data
)
57 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
59 *data
= bcm_readl(priv
->regs
+ RNG_DATA
);
64 static int bcm63xx_rng_probe(struct platform_device
*pdev
)
69 struct bcm63xx_rng_priv
*priv
;
72 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
74 dev_err(&pdev
->dev
, "no iomem resource\n");
79 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
81 dev_err(&pdev
->dev
, "no memory for private structure\n");
86 rng
= kzalloc(sizeof(*rng
), GFP_KERNEL
);
88 dev_err(&pdev
->dev
, "no memory for rng structure\n");
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
;
101 clk
= clk_get(&pdev
->dev
, "ipsec");
103 dev_err(&pdev
->dev
, "no clock for device\n");
110 if (!devm_request_mem_region(&pdev
->dev
, r
->start
,
111 resource_size(r
), pdev
->name
)) {
112 dev_err(&pdev
->dev
, "request mem failed");
117 priv
->regs
= devm_ioremap_nocache(&pdev
->dev
, r
->start
,
120 dev_err(&pdev
->dev
, "ioremap failed");
127 ret
= hwrng_register(rng
);
129 dev_err(&pdev
->dev
, "failed to register rng device\n");
130 goto out_clk_disable
;
133 dev_info(&pdev
->dev
, "registered RNG driver\n");
147 static int bcm63xx_rng_remove(struct platform_device
*pdev
)
149 struct hwrng
*rng
= platform_get_drvdata(pdev
);
150 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
152 hwrng_unregister(rng
);
153 clk_disable(priv
->clk
);
160 static struct platform_driver bcm63xx_rng_driver
= {
161 .probe
= bcm63xx_rng_probe
,
162 .remove
= bcm63xx_rng_remove
,
164 .name
= "bcm63xx-rng",
165 .owner
= THIS_MODULE
,
169 module_platform_driver(bcm63xx_rng_driver
);
171 MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
172 MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver");
173 MODULE_LICENSE("GPL");