2 * Driver for Mediatek Hardware Random Number Generator
4 * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 #define MTK_RNG_DEV KBUILD_MODNAME
18 #include <linux/clk.h>
19 #include <linux/delay.h>
20 #include <linux/err.h>
21 #include <linux/hw_random.h>
23 #include <linux/iopoll.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
27 #include <linux/platform_device.h>
30 #define TIMEOUT_POLL 20
34 #define RNG_READY BIT(31)
38 #define to_mtk_rng(p) container_of(p, struct mtk_rng, rng)
46 static int mtk_rng_init(struct hwrng
*rng
)
48 struct mtk_rng
*priv
= to_mtk_rng(rng
);
52 err
= clk_prepare_enable(priv
->clk
);
56 val
= readl(priv
->base
+ RNG_CTRL
);
58 writel(val
, priv
->base
+ RNG_CTRL
);
63 static void mtk_rng_cleanup(struct hwrng
*rng
)
65 struct mtk_rng
*priv
= to_mtk_rng(rng
);
68 val
= readl(priv
->base
+ RNG_CTRL
);
70 writel(val
, priv
->base
+ RNG_CTRL
);
72 clk_disable_unprepare(priv
->clk
);
75 static bool mtk_rng_wait_ready(struct hwrng
*rng
, bool wait
)
77 struct mtk_rng
*priv
= to_mtk_rng(rng
);
80 ready
= readl(priv
->base
+ RNG_CTRL
) & RNG_READY
;
82 readl_poll_timeout_atomic(priv
->base
+ RNG_CTRL
, ready
,
83 ready
& RNG_READY
, USEC_POLL
,
88 static int mtk_rng_read(struct hwrng
*rng
, void *buf
, size_t max
, bool wait
)
90 struct mtk_rng
*priv
= to_mtk_rng(rng
);
93 while (max
>= sizeof(u32
)) {
94 if (!mtk_rng_wait_ready(rng
, wait
))
97 *(u32
*)buf
= readl(priv
->base
+ RNG_DATA
);
98 retval
+= sizeof(u32
);
103 return retval
|| !wait
? retval
: -EIO
;
106 static int mtk_rng_probe(struct platform_device
*pdev
)
108 struct resource
*res
;
110 struct mtk_rng
*priv
;
112 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
114 dev_err(&pdev
->dev
, "no iomem resource\n");
118 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
122 priv
->rng
.name
= pdev
->name
;
123 priv
->rng
.init
= mtk_rng_init
;
124 priv
->rng
.cleanup
= mtk_rng_cleanup
;
125 priv
->rng
.read
= mtk_rng_read
;
127 priv
->clk
= devm_clk_get(&pdev
->dev
, "rng");
128 if (IS_ERR(priv
->clk
)) {
129 ret
= PTR_ERR(priv
->clk
);
130 dev_err(&pdev
->dev
, "no clock for device: %d\n", ret
);
134 priv
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
135 if (IS_ERR(priv
->base
))
136 return PTR_ERR(priv
->base
);
138 ret
= devm_hwrng_register(&pdev
->dev
, &priv
->rng
);
140 dev_err(&pdev
->dev
, "failed to register rng device: %d\n",
145 dev_info(&pdev
->dev
, "registered RNG driver\n");
150 static const struct of_device_id mtk_rng_match
[] = {
151 { .compatible
= "mediatek,mt7623-rng" },
154 MODULE_DEVICE_TABLE(of
, mtk_rng_match
);
156 static struct platform_driver mtk_rng_driver
= {
157 .probe
= mtk_rng_probe
,
160 .of_match_table
= mtk_rng_match
,
164 module_platform_driver(mtk_rng_driver
);
166 MODULE_DESCRIPTION("Mediatek Random Number Generator Driver");
167 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
168 MODULE_LICENSE("GPL");