aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mcs814x/files-3.3/drivers/char/hw_random/mcs814x-rng.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mcs814x/files-3.3/drivers/char/hw_random/mcs814x-rng.c')
-rw-r--r--target/linux/mcs814x/files-3.3/drivers/char/hw_random/mcs814x-rng.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/target/linux/mcs814x/files-3.3/drivers/char/hw_random/mcs814x-rng.c b/target/linux/mcs814x/files-3.3/drivers/char/hw_random/mcs814x-rng.c
new file mode 100644
index 000000000..b1e95810d
--- /dev/null
+++ b/target/linux/mcs814x/files-3.3/drivers/char/hw_random/mcs814x-rng.c
@@ -0,0 +1,128 @@
+/*
+ * RNG driver for Moschip MCS814x SoC
+ *
+ * Copyright 2012 (C), Florian Fainelli <florian@openwrt.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#define STAT 0x00
+#define RND 0x04
+
+struct mcs814x_rng_priv {
+ void __iomem *regs;
+};
+
+static int mcs814x_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+ struct mcs814x_rng_priv *priv = (struct mcs814x_rng_priv *)rng->priv;
+
+ *buffer = readl_relaxed(priv->regs + RND);
+
+ return 4;
+}
+
+static int mcs814x_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mcs814x_rng_priv *priv;
+ struct hwrng *rng;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rng = kzalloc(sizeof(*rng), GFP_KERNEL);
+ if (!rng) {
+ ret = -ENOMEM;
+ goto out_priv;
+ }
+
+ platform_set_drvdata(pdev, rng);
+ rng->priv = (unsigned long)priv;
+ rng->name = pdev->name;
+ rng->data_read = mcs814x_rng_data_read;
+
+ if (!devm_request_mem_region(&pdev->dev,
+ res->start, resource_size(res),
+ pdev->name)) {
+ ret = -EBUSY;
+ goto out_rng;
+ }
+
+ priv->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!priv->regs) {
+ ret = -ENOMEM;
+ goto out_rng;
+ }
+
+ ret = hwrng_register(rng);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register hwrng driver\n");
+ goto out;
+ }
+
+ dev_info(&pdev->dev, "registered\n");
+
+ return ret;
+
+out_rng:
+ platform_set_drvdata(pdev, NULL);
+ kfree(rng);
+out_priv:
+ kfree(priv);
+out:
+ return ret;
+}
+
+static int mcs814x_rng_remove(struct platform_device *pdev)
+{
+ struct hwrng *rng = platform_get_drvdata(pdev);
+ struct mcs814x_rng_priv *priv = (struct mcs814x_rng_priv *)rng->priv;
+
+ hwrng_unregister(rng);
+ kfree(priv);
+ kfree(rng);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id mcs814x_rng_ids[] = {
+ { .compatible = "moschip,mcs814x-rng", },
+ { /* sentinel */ },
+};
+
+static struct platform_driver mcs814x_rng_driver = {
+ .driver = {
+ .name = "mcs814x-rng",
+ .owner = THIS_MODULE,
+ .of_match_table = mcs814x_rng_ids,
+ },
+ .probe = mcs814x_rng_probe,
+ .remove = __devexit_p(mcs814x_rng_remove),
+};
+
+module_platform_driver(mcs814x_rng_driver);
+
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) for Moschip MCS814x");
+MODULE_LICENSE("GPL");