root/drivers/char/hw_random/mtk-rng.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mtk_rng_init
  2. mtk_rng_cleanup
  3. mtk_rng_wait_ready
  4. mtk_rng_read
  5. mtk_rng_probe
  6. mtk_rng_runtime_suspend
  7. mtk_rng_runtime_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Driver for Mediatek Hardware Random Number Generator
   4  *
   5  * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
   6  */
   7 #define MTK_RNG_DEV KBUILD_MODNAME
   8 
   9 #include <linux/clk.h>
  10 #include <linux/delay.h>
  11 #include <linux/err.h>
  12 #include <linux/hw_random.h>
  13 #include <linux/io.h>
  14 #include <linux/iopoll.h>
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/of.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/pm_runtime.h>
  20 
  21 /* Runtime PM autosuspend timeout: */
  22 #define RNG_AUTOSUSPEND_TIMEOUT         100
  23 
  24 #define USEC_POLL                       2
  25 #define TIMEOUT_POLL                    20
  26 
  27 #define RNG_CTRL                        0x00
  28 #define RNG_EN                          BIT(0)
  29 #define RNG_READY                       BIT(31)
  30 
  31 #define RNG_DATA                        0x08
  32 
  33 #define to_mtk_rng(p)   container_of(p, struct mtk_rng, rng)
  34 
  35 struct mtk_rng {
  36         void __iomem *base;
  37         struct clk *clk;
  38         struct hwrng rng;
  39 };
  40 
  41 static int mtk_rng_init(struct hwrng *rng)
  42 {
  43         struct mtk_rng *priv = to_mtk_rng(rng);
  44         u32 val;
  45         int err;
  46 
  47         err = clk_prepare_enable(priv->clk);
  48         if (err)
  49                 return err;
  50 
  51         val = readl(priv->base + RNG_CTRL);
  52         val |= RNG_EN;
  53         writel(val, priv->base + RNG_CTRL);
  54 
  55         return 0;
  56 }
  57 
  58 static void mtk_rng_cleanup(struct hwrng *rng)
  59 {
  60         struct mtk_rng *priv = to_mtk_rng(rng);
  61         u32 val;
  62 
  63         val = readl(priv->base + RNG_CTRL);
  64         val &= ~RNG_EN;
  65         writel(val, priv->base + RNG_CTRL);
  66 
  67         clk_disable_unprepare(priv->clk);
  68 }
  69 
  70 static bool mtk_rng_wait_ready(struct hwrng *rng, bool wait)
  71 {
  72         struct mtk_rng *priv = to_mtk_rng(rng);
  73         int ready;
  74 
  75         ready = readl(priv->base + RNG_CTRL) & RNG_READY;
  76         if (!ready && wait)
  77                 readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready,
  78                                           ready & RNG_READY, USEC_POLL,
  79                                           TIMEOUT_POLL);
  80         return !!ready;
  81 }
  82 
  83 static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
  84 {
  85         struct mtk_rng *priv = to_mtk_rng(rng);
  86         int retval = 0;
  87 
  88         pm_runtime_get_sync((struct device *)priv->rng.priv);
  89 
  90         while (max >= sizeof(u32)) {
  91                 if (!mtk_rng_wait_ready(rng, wait))
  92                         break;
  93 
  94                 *(u32 *)buf = readl(priv->base + RNG_DATA);
  95                 retval += sizeof(u32);
  96                 buf += sizeof(u32);
  97                 max -= sizeof(u32);
  98         }
  99 
 100         pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
 101         pm_runtime_put_sync_autosuspend((struct device *)priv->rng.priv);
 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 #ifndef CONFIG_PM
 124         priv->rng.init = mtk_rng_init;
 125         priv->rng.cleanup = mtk_rng_cleanup;
 126 #endif
 127         priv->rng.read = mtk_rng_read;
 128         priv->rng.priv = (unsigned long)&pdev->dev;
 129         priv->rng.quality = 900;
 130 
 131         priv->clk = devm_clk_get(&pdev->dev, "rng");
 132         if (IS_ERR(priv->clk)) {
 133                 ret = PTR_ERR(priv->clk);
 134                 dev_err(&pdev->dev, "no clock for device: %d\n", ret);
 135                 return ret;
 136         }
 137 
 138         priv->base = devm_ioremap_resource(&pdev->dev, res);
 139         if (IS_ERR(priv->base))
 140                 return PTR_ERR(priv->base);
 141 
 142         ret = devm_hwrng_register(&pdev->dev, &priv->rng);
 143         if (ret) {
 144                 dev_err(&pdev->dev, "failed to register rng device: %d\n",
 145                         ret);
 146                 return ret;
 147         }
 148 
 149         dev_set_drvdata(&pdev->dev, priv);
 150         pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT);
 151         pm_runtime_use_autosuspend(&pdev->dev);
 152         pm_runtime_enable(&pdev->dev);
 153 
 154         dev_info(&pdev->dev, "registered RNG driver\n");
 155 
 156         return 0;
 157 }
 158 
 159 #ifdef CONFIG_PM
 160 static int mtk_rng_runtime_suspend(struct device *dev)
 161 {
 162         struct mtk_rng *priv = dev_get_drvdata(dev);
 163 
 164         mtk_rng_cleanup(&priv->rng);
 165 
 166         return 0;
 167 }
 168 
 169 static int mtk_rng_runtime_resume(struct device *dev)
 170 {
 171         struct mtk_rng *priv = dev_get_drvdata(dev);
 172 
 173         return mtk_rng_init(&priv->rng);
 174 }
 175 
 176 static UNIVERSAL_DEV_PM_OPS(mtk_rng_pm_ops, mtk_rng_runtime_suspend,
 177                             mtk_rng_runtime_resume, NULL);
 178 #define MTK_RNG_PM_OPS (&mtk_rng_pm_ops)
 179 #else   /* CONFIG_PM */
 180 #define MTK_RNG_PM_OPS NULL
 181 #endif  /* CONFIG_PM */
 182 
 183 static const struct of_device_id mtk_rng_match[] = {
 184         { .compatible = "mediatek,mt7623-rng" },
 185         {},
 186 };
 187 MODULE_DEVICE_TABLE(of, mtk_rng_match);
 188 
 189 static struct platform_driver mtk_rng_driver = {
 190         .probe          = mtk_rng_probe,
 191         .driver = {
 192                 .name = MTK_RNG_DEV,
 193                 .pm = MTK_RNG_PM_OPS,
 194                 .of_match_table = mtk_rng_match,
 195         },
 196 };
 197 
 198 module_platform_driver(mtk_rng_driver);
 199 
 200 MODULE_DESCRIPTION("Mediatek Random Number Generator Driver");
 201 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
 202 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */