11a9e9372SNeil Armstrong // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2e123be16SNeil Armstrong /* 3e123be16SNeil Armstrong * Copyright (c) 2016 BayLibre, SAS. 4e123be16SNeil Armstrong * Author: Neil Armstrong <narmstrong@baylibre.com> 5e123be16SNeil Armstrong * Copyright (C) 2014 Amlogic, Inc. 6e123be16SNeil Armstrong */ 7e123be16SNeil Armstrong #include <linux/err.h> 8e123be16SNeil Armstrong #include <linux/module.h> 9e123be16SNeil Armstrong #include <linux/io.h> 10e123be16SNeil Armstrong #include <linux/platform_device.h> 11e123be16SNeil Armstrong #include <linux/hw_random.h> 12e123be16SNeil Armstrong #include <linux/slab.h> 13e123be16SNeil Armstrong #include <linux/types.h> 14e123be16SNeil Armstrong #include <linux/of.h> 157a794a73SHeiner Kallweit #include <linux/clk.h> 16e123be16SNeil Armstrong 17e123be16SNeil Armstrong #define RNG_DATA 0x00 18e123be16SNeil Armstrong 19e123be16SNeil Armstrong struct meson_rng_data { 20e123be16SNeil Armstrong void __iomem *base; 21e123be16SNeil Armstrong struct platform_device *pdev; 22e123be16SNeil Armstrong struct hwrng rng; 237a794a73SHeiner Kallweit struct clk *core_clk; 24e123be16SNeil Armstrong }; 25e123be16SNeil Armstrong 26e123be16SNeil Armstrong static int meson_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) 27e123be16SNeil Armstrong { 28e123be16SNeil Armstrong struct meson_rng_data *data = 29e123be16SNeil Armstrong container_of(rng, struct meson_rng_data, rng); 30e123be16SNeil Armstrong 31e123be16SNeil Armstrong *(u32 *)buf = readl_relaxed(data->base + RNG_DATA); 32e123be16SNeil Armstrong 33e123be16SNeil Armstrong return sizeof(u32); 34e123be16SNeil Armstrong } 35e123be16SNeil Armstrong 367a794a73SHeiner Kallweit static void meson_rng_clk_disable(void *data) 377a794a73SHeiner Kallweit { 387a794a73SHeiner Kallweit clk_disable_unprepare(data); 397a794a73SHeiner Kallweit } 407a794a73SHeiner Kallweit 41e123be16SNeil Armstrong static int meson_rng_probe(struct platform_device *pdev) 42e123be16SNeil Armstrong { 43e123be16SNeil Armstrong struct device *dev = &pdev->dev; 44e123be16SNeil Armstrong struct meson_rng_data *data; 45e123be16SNeil Armstrong struct resource *res; 467a794a73SHeiner Kallweit int ret; 47e123be16SNeil Armstrong 48e123be16SNeil Armstrong data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 49e123be16SNeil Armstrong if (!data) 50e123be16SNeil Armstrong return -ENOMEM; 51e123be16SNeil Armstrong 52e123be16SNeil Armstrong data->pdev = pdev; 53e123be16SNeil Armstrong 54e123be16SNeil Armstrong res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 55e123be16SNeil Armstrong data->base = devm_ioremap_resource(dev, res); 56e123be16SNeil Armstrong if (IS_ERR(data->base)) 57e123be16SNeil Armstrong return PTR_ERR(data->base); 58e123be16SNeil Armstrong 597a794a73SHeiner Kallweit data->core_clk = devm_clk_get(dev, "core"); 607a794a73SHeiner Kallweit if (IS_ERR(data->core_clk)) 617a794a73SHeiner Kallweit data->core_clk = NULL; 627a794a73SHeiner Kallweit 637a794a73SHeiner Kallweit if (data->core_clk) { 647a794a73SHeiner Kallweit ret = clk_prepare_enable(data->core_clk); 657a794a73SHeiner Kallweit if (ret) 667a794a73SHeiner Kallweit return ret; 677a794a73SHeiner Kallweit ret = devm_add_action_or_reset(dev, meson_rng_clk_disable, 687a794a73SHeiner Kallweit data->core_clk); 697a794a73SHeiner Kallweit if (ret) 707a794a73SHeiner Kallweit return ret; 717a794a73SHeiner Kallweit } 727a794a73SHeiner Kallweit 73e123be16SNeil Armstrong data->rng.name = pdev->name; 74e123be16SNeil Armstrong data->rng.read = meson_rng_read; 75e123be16SNeil Armstrong 76e123be16SNeil Armstrong platform_set_drvdata(pdev, data); 77e123be16SNeil Armstrong 78e123be16SNeil Armstrong return devm_hwrng_register(dev, &data->rng); 79e123be16SNeil Armstrong } 80e123be16SNeil Armstrong 81e123be16SNeil Armstrong static const struct of_device_id meson_rng_of_match[] = { 82e123be16SNeil Armstrong { .compatible = "amlogic,meson-rng", }, 83e123be16SNeil Armstrong {}, 84e123be16SNeil Armstrong }; 85877f69a8SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, meson_rng_of_match); 86e123be16SNeil Armstrong 87e123be16SNeil Armstrong static struct platform_driver meson_rng_driver = { 88e123be16SNeil Armstrong .probe = meson_rng_probe, 89e123be16SNeil Armstrong .driver = { 90e123be16SNeil Armstrong .name = "meson-rng", 91e123be16SNeil Armstrong .of_match_table = meson_rng_of_match, 92e123be16SNeil Armstrong }, 93e123be16SNeil Armstrong }; 94e123be16SNeil Armstrong 95e123be16SNeil Armstrong module_platform_driver(meson_rng_driver); 96e123be16SNeil Armstrong 97e123be16SNeil Armstrong MODULE_DESCRIPTION("Meson H/W Random Number Generator driver"); 98e123be16SNeil Armstrong MODULE_AUTHOR("Lawrence Mok <lawrence.mok@amlogic.com>"); 99e123be16SNeil Armstrong MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 100e123be16SNeil Armstrong MODULE_LICENSE("Dual BSD/GPL"); 101