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>
18 #define RNG_EN (1 << 0)
21 #define RNG_AVAIL_MASK (0xff000000)
24 #define RNG_THRES 0x0c
27 struct bcm63xx_rng_priv
{
33 #define to_rng_priv(rng) container_of(rng, struct bcm63xx_rng_priv, rng)
35 static int bcm63xx_rng_init(struct hwrng
*rng
)
37 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
41 error
= clk_prepare_enable(priv
->clk
);
45 val
= __raw_readl(priv
->regs
+ RNG_CTRL
);
47 __raw_writel(val
, priv
->regs
+ RNG_CTRL
);
52 static void bcm63xx_rng_cleanup(struct hwrng
*rng
)
54 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
57 val
= __raw_readl(priv
->regs
+ RNG_CTRL
);
59 __raw_writel(val
, priv
->regs
+ RNG_CTRL
);
61 clk_disable_unprepare(priv
->clk
);
64 static int bcm63xx_rng_data_present(struct hwrng
*rng
, int wait
)
66 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
68 return __raw_readl(priv
->regs
+ RNG_STAT
) & RNG_AVAIL_MASK
;
71 static int bcm63xx_rng_data_read(struct hwrng
*rng
, u32
*data
)
73 struct bcm63xx_rng_priv
*priv
= to_rng_priv(rng
);
75 *data
= __raw_readl(priv
->regs
+ RNG_DATA
);
80 static int bcm63xx_rng_probe(struct platform_device
*pdev
)
84 struct bcm63xx_rng_priv
*priv
;
86 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
88 dev_err(&pdev
->dev
, "no iomem resource\n");
92 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
96 priv
->rng
.name
= pdev
->name
;
97 priv
->rng
.init
= bcm63xx_rng_init
;
98 priv
->rng
.cleanup
= bcm63xx_rng_cleanup
;
99 priv
->rng
.data_present
= bcm63xx_rng_data_present
;
100 priv
->rng
.data_read
= bcm63xx_rng_data_read
;
102 priv
->clk
= devm_clk_get(&pdev
->dev
, "ipsec");
103 if (IS_ERR(priv
->clk
)) {
104 ret
= PTR_ERR(priv
->clk
);
105 dev_err(&pdev
->dev
, "no clock for device: %d\n", ret
);
109 if (!devm_request_mem_region(&pdev
->dev
, r
->start
,
110 resource_size(r
), pdev
->name
)) {
111 dev_err(&pdev
->dev
, "request mem failed");
115 priv
->regs
= devm_ioremap_nocache(&pdev
->dev
, r
->start
,
118 dev_err(&pdev
->dev
, "ioremap failed");
122 ret
= devm_hwrng_register(&pdev
->dev
, &priv
->rng
);
124 dev_err(&pdev
->dev
, "failed to register rng device: %d\n",
129 dev_info(&pdev
->dev
, "registered RNG driver\n");
135 static const struct of_device_id bcm63xx_rng_of_match
[] = {
136 { .compatible
= "brcm,bcm6368-rng", },
139 MODULE_DEVICE_TABLE(of
, bcm63xx_rng_of_match
);
142 static struct platform_driver bcm63xx_rng_driver
= {
143 .probe
= bcm63xx_rng_probe
,
145 .name
= "bcm63xx-rng",
146 .of_match_table
= of_match_ptr(bcm63xx_rng_of_match
),
150 module_platform_driver(bcm63xx_rng_driver
);
152 MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
153 MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver");
154 MODULE_LICENSE("GPL");