1 // SPDX-License-Identifier: GPL-2.0
3 * Ingenic True Random Number Generator driver
4 * Copyright (c) 2019 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>
5 * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
10 #include <linux/kernel.h>
11 #include <linux/hw_random.h>
13 #include <linux/iopoll.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
19 /* DTRNG register offsets */
20 #define TRNG_REG_CFG_OFFSET 0x00
21 #define TRNG_REG_RANDOMNUM_OFFSET 0x04
22 #define TRNG_REG_STATUS_OFFSET 0x08
24 /* bits within the CFG register */
25 #define CFG_GEN_EN BIT(0)
27 /* bits within the STATUS register */
28 #define STATUS_RANDOM_RDY BIT(0)
35 static int ingenic_trng_init(struct hwrng
*rng
)
37 struct ingenic_trng
*trng
= container_of(rng
, struct ingenic_trng
, rng
);
40 ctrl
= readl(trng
->base
+ TRNG_REG_CFG_OFFSET
);
42 writel(ctrl
, trng
->base
+ TRNG_REG_CFG_OFFSET
);
47 static void ingenic_trng_cleanup(struct hwrng
*rng
)
49 struct ingenic_trng
*trng
= container_of(rng
, struct ingenic_trng
, rng
);
52 ctrl
= readl(trng
->base
+ TRNG_REG_CFG_OFFSET
);
54 writel(ctrl
, trng
->base
+ TRNG_REG_CFG_OFFSET
);
57 static int ingenic_trng_read(struct hwrng
*rng
, void *buf
, size_t max
, bool wait
)
59 struct ingenic_trng
*trng
= container_of(rng
, struct ingenic_trng
, rng
);
64 ret
= readl_poll_timeout(trng
->base
+ TRNG_REG_STATUS_OFFSET
, status
,
65 status
& STATUS_RANDOM_RDY
, 10, 1000);
66 if (ret
== -ETIMEDOUT
) {
67 pr_err("%s: Wait for DTRNG data ready timeout\n", __func__
);
71 *data
= readl(trng
->base
+ TRNG_REG_RANDOMNUM_OFFSET
);
76 static int ingenic_trng_probe(struct platform_device
*pdev
)
78 struct ingenic_trng
*trng
;
82 trng
= devm_kzalloc(&pdev
->dev
, sizeof(*trng
), GFP_KERNEL
);
86 trng
->base
= devm_platform_ioremap_resource(pdev
, 0);
87 if (IS_ERR(trng
->base
))
88 return dev_err_probe(&pdev
->dev
, PTR_ERR(trng
->base
),
89 "%s: Failed to map DTRNG registers\n", __func__
);
91 clk
= devm_clk_get_enabled(&pdev
->dev
, NULL
);
93 return dev_err_probe(&pdev
->dev
, PTR_ERR(clk
),
94 "%s: Cannot get and enable DTRNG clock\n", __func__
);
96 trng
->rng
.name
= pdev
->name
;
97 trng
->rng
.init
= ingenic_trng_init
;
98 trng
->rng
.cleanup
= ingenic_trng_cleanup
;
99 trng
->rng
.read
= ingenic_trng_read
;
101 ret
= devm_hwrng_register(&pdev
->dev
, &trng
->rng
);
103 return dev_err_probe(&pdev
->dev
, ret
, "Failed to register hwrng\n");
105 platform_set_drvdata(pdev
, trng
);
107 dev_info(&pdev
->dev
, "Ingenic DTRNG driver registered\n");
111 static const struct of_device_id ingenic_trng_of_match
[] = {
112 { .compatible
= "ingenic,x1830-dtrng" },
115 MODULE_DEVICE_TABLE(of
, ingenic_trng_of_match
);
117 static struct platform_driver ingenic_trng_driver
= {
118 .probe
= ingenic_trng_probe
,
120 .name
= "ingenic-trng",
121 .of_match_table
= ingenic_trng_of_match
,
125 module_platform_driver(ingenic_trng_driver
);
127 MODULE_LICENSE("GPL");
128 MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
129 MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
130 MODULE_DESCRIPTION("Ingenic True Random Number Generator driver");