]> Git Repo - linux.git/blob - drivers/char/hw_random/mtk-rng.c
sched/deadline: Move DL related code from sched/core.c to sched/deadline.c
[linux.git] / drivers / char / hw_random / mtk-rng.c
1 /*
2  * Driver for Mediatek Hardware Random Number Generator
3  *
4  * Copyright (C) 2017 Sean Wang <[email protected]>
5  *
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.
10  *
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.
15  */
16 #define MTK_RNG_DEV KBUILD_MODNAME
17
18 #include <linux/clk.h>
19 #include <linux/delay.h>
20 #include <linux/err.h>
21 #include <linux/hw_random.h>
22 #include <linux/io.h>
23 #include <linux/iopoll.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/of.h>
27 #include <linux/platform_device.h>
28
29 #define USEC_POLL                       2
30 #define TIMEOUT_POLL                    20
31
32 #define RNG_CTRL                        0x00
33 #define RNG_EN                          BIT(0)
34 #define RNG_READY                       BIT(31)
35
36 #define RNG_DATA                        0x08
37
38 #define to_mtk_rng(p)   container_of(p, struct mtk_rng, rng)
39
40 struct mtk_rng {
41         void __iomem *base;
42         struct clk *clk;
43         struct hwrng rng;
44 };
45
46 static int mtk_rng_init(struct hwrng *rng)
47 {
48         struct mtk_rng *priv = to_mtk_rng(rng);
49         u32 val;
50         int err;
51
52         err = clk_prepare_enable(priv->clk);
53         if (err)
54                 return err;
55
56         val = readl(priv->base + RNG_CTRL);
57         val |= RNG_EN;
58         writel(val, priv->base + RNG_CTRL);
59
60         return 0;
61 }
62
63 static void mtk_rng_cleanup(struct hwrng *rng)
64 {
65         struct mtk_rng *priv = to_mtk_rng(rng);
66         u32 val;
67
68         val = readl(priv->base + RNG_CTRL);
69         val &= ~RNG_EN;
70         writel(val, priv->base + RNG_CTRL);
71
72         clk_disable_unprepare(priv->clk);
73 }
74
75 static bool mtk_rng_wait_ready(struct hwrng *rng, bool wait)
76 {
77         struct mtk_rng *priv = to_mtk_rng(rng);
78         int ready;
79
80         ready = readl(priv->base + RNG_CTRL) & RNG_READY;
81         if (!ready && wait)
82                 readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready,
83                                           ready & RNG_READY, USEC_POLL,
84                                           TIMEOUT_POLL);
85         return !!ready;
86 }
87
88 static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
89 {
90         struct mtk_rng *priv = to_mtk_rng(rng);
91         int retval = 0;
92
93         while (max >= sizeof(u32)) {
94                 if (!mtk_rng_wait_ready(rng, wait))
95                         break;
96
97                 *(u32 *)buf = readl(priv->base + RNG_DATA);
98                 retval += sizeof(u32);
99                 buf += sizeof(u32);
100                 max -= sizeof(u32);
101         }
102
103         return retval || !wait ? retval : -EIO;
104 }
105
106 static int mtk_rng_probe(struct platform_device *pdev)
107 {
108         struct resource *res;
109         int ret;
110         struct mtk_rng *priv;
111
112         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
113         if (!res) {
114                 dev_err(&pdev->dev, "no iomem resource\n");
115                 return -ENXIO;
116         }
117
118         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
119         if (!priv)
120                 return -ENOMEM;
121
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;
126
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);
131                 return ret;
132         }
133
134         priv->base = devm_ioremap_resource(&pdev->dev, res);
135         if (IS_ERR(priv->base))
136                 return PTR_ERR(priv->base);
137
138         ret = devm_hwrng_register(&pdev->dev, &priv->rng);
139         if (ret) {
140                 dev_err(&pdev->dev, "failed to register rng device: %d\n",
141                         ret);
142                 return ret;
143         }
144
145         dev_info(&pdev->dev, "registered RNG driver\n");
146
147         return 0;
148 }
149
150 static const struct of_device_id mtk_rng_match[] = {
151         { .compatible = "mediatek,mt7623-rng" },
152         {},
153 };
154 MODULE_DEVICE_TABLE(of, mtk_rng_match);
155
156 static struct platform_driver mtk_rng_driver = {
157         .probe          = mtk_rng_probe,
158         .driver = {
159                 .name = MTK_RNG_DEV,
160                 .of_match_table = mtk_rng_match,
161         },
162 };
163
164 module_platform_driver(mtk_rng_driver);
165
166 MODULE_DESCRIPTION("Mediatek Random Number Generator Driver");
167 MODULE_AUTHOR("Sean Wang <[email protected]>");
168 MODULE_LICENSE("GPL");
This page took 0.041622 seconds and 4 git commands to generate.