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; 457a794a73SHeiner Kallweit int ret; 46e123be16SNeil Armstrong 47e123be16SNeil Armstrong data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 48e123be16SNeil Armstrong if (!data) 49e123be16SNeil Armstrong return -ENOMEM; 50e123be16SNeil Armstrong 51e123be16SNeil Armstrong data->pdev = pdev; 52e123be16SNeil Armstrong 53ba147576SYueHaibing data->base = devm_platform_ioremap_resource(pdev, 0); 54e123be16SNeil Armstrong if (IS_ERR(data->base)) 55e123be16SNeil Armstrong return PTR_ERR(data->base); 56e123be16SNeil Armstrong 577a794a73SHeiner Kallweit data->core_clk = devm_clk_get(dev, "core"); 587a794a73SHeiner Kallweit if (IS_ERR(data->core_clk)) 597a794a73SHeiner Kallweit data->core_clk = NULL; 607a794a73SHeiner Kallweit 617a794a73SHeiner Kallweit if (data->core_clk) { 627a794a73SHeiner Kallweit ret = clk_prepare_enable(data->core_clk); 637a794a73SHeiner Kallweit if (ret) 647a794a73SHeiner Kallweit return ret; 657a794a73SHeiner Kallweit ret = devm_add_action_or_reset(dev, meson_rng_clk_disable, 667a794a73SHeiner Kallweit data->core_clk); 677a794a73SHeiner Kallweit if (ret) 687a794a73SHeiner Kallweit return ret; 697a794a73SHeiner Kallweit } 707a794a73SHeiner Kallweit 71e123be16SNeil Armstrong data->rng.name = pdev->name; 72e123be16SNeil Armstrong data->rng.read = meson_rng_read; 73e123be16SNeil Armstrong 74e123be16SNeil Armstrong platform_set_drvdata(pdev, data); 75e123be16SNeil Armstrong 76e123be16SNeil Armstrong return devm_hwrng_register(dev, &data->rng); 77e123be16SNeil Armstrong } 78e123be16SNeil Armstrong 79e123be16SNeil Armstrong static const struct of_device_id meson_rng_of_match[] = { 80e123be16SNeil Armstrong { .compatible = "amlogic,meson-rng", }, 81e123be16SNeil Armstrong {}, 82e123be16SNeil Armstrong }; 83877f69a8SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, meson_rng_of_match); 84e123be16SNeil Armstrong 85e123be16SNeil Armstrong static struct platform_driver meson_rng_driver = { 86e123be16SNeil Armstrong .probe = meson_rng_probe, 87e123be16SNeil Armstrong .driver = { 88e123be16SNeil Armstrong .name = "meson-rng", 89e123be16SNeil Armstrong .of_match_table = meson_rng_of_match, 90e123be16SNeil Armstrong }, 91e123be16SNeil Armstrong }; 92e123be16SNeil Armstrong 93e123be16SNeil Armstrong module_platform_driver(meson_rng_driver); 94e123be16SNeil Armstrong 95e123be16SNeil Armstrong MODULE_DESCRIPTION("Meson H/W Random Number Generator driver"); 96e123be16SNeil Armstrong MODULE_AUTHOR("Lawrence Mok <lawrence.mok@amlogic.com>"); 97e123be16SNeil Armstrong MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 98e123be16SNeil Armstrong MODULE_LICENSE("Dual BSD/GPL"); 99