--- zzzz-none-000/linux-3.10.107/drivers/char/hw_random/exynos-rng.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/char/hw_random/exynos-rng.c 2021-02-04 17:41:59.000000000 +0000 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -54,15 +53,11 @@ __raw_writel(val, rng->mem + offset); } -static int exynos_init(struct hwrng *rng) +static int exynos_rng_configure(struct exynos_rng *exynos_rng) { - struct exynos_rng *exynos_rng = container_of(rng, - struct exynos_rng, rng); int i; int ret = 0; - pm_runtime_get_sync(exynos_rng->dev); - for (i = 0 ; i < 5 ; i++) exynos_rng_writel(exynos_rng, jiffies, EXYNOS_PRNG_SEED_OFFSET + 4*i); @@ -71,6 +66,17 @@ & SEED_SETTING_DONE)) ret = -EIO; + return ret; +} + +static int exynos_init(struct hwrng *rng) +{ + struct exynos_rng *exynos_rng = container_of(rng, + struct exynos_rng, rng); + int ret = 0; + + pm_runtime_get_sync(exynos_rng->dev); + ret = exynos_rng_configure(exynos_rng); pm_runtime_put_noidle(exynos_rng->dev); return ret; @@ -82,23 +88,30 @@ struct exynos_rng *exynos_rng = container_of(rng, struct exynos_rng, rng); u32 *data = buf; + int retry = 100; + int ret = 4; pm_runtime_get_sync(exynos_rng->dev); exynos_rng_writel(exynos_rng, PRNG_START, 0); while (!(exynos_rng_readl(exynos_rng, - EXYNOS_PRNG_STATUS_OFFSET) & PRNG_DONE)) + EXYNOS_PRNG_STATUS_OFFSET) & PRNG_DONE) && --retry) cpu_relax(); + if (!retry) { + ret = -ETIMEDOUT; + goto out; + } exynos_rng_writel(exynos_rng, PRNG_DONE, EXYNOS_PRNG_STATUS_OFFSET); *data = exynos_rng_readl(exynos_rng, EXYNOS_PRNG_OUT1_OFFSET); +out: pm_runtime_mark_last_busy(exynos_rng->dev); - pm_runtime_autosuspend(exynos_rng->dev); + pm_runtime_put_sync_autosuspend(exynos_rng->dev); - return 4; + return ret; } static int exynos_rng_probe(struct platform_device *pdev) @@ -133,7 +146,7 @@ pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); - ret = hwrng_register(&exynos_rng->rng); + ret = devm_hwrng_register(&pdev->dev, &exynos_rng->rng); if (ret) { pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -142,46 +155,65 @@ return ret; } -static int exynos_rng_remove(struct platform_device *pdev) +#ifdef CONFIG_PM +static int exynos_rng_runtime_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); - hwrng_unregister(&exynos_rng->rng); + clk_disable_unprepare(exynos_rng->clk); return 0; } -#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) -static int exynos_rng_runtime_suspend(struct device *dev) +static int exynos_rng_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); - clk_disable_unprepare(exynos_rng->clk); + return clk_prepare_enable(exynos_rng->clk); +} - return 0; +static int exynos_rng_suspend(struct device *dev) +{ + return pm_runtime_force_suspend(dev); } -static int exynos_rng_runtime_resume(struct device *dev) +static int exynos_rng_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); + int ret; - return clk_prepare_enable(exynos_rng->clk); + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + return exynos_rng_configure(exynos_rng); } #endif -static UNIVERSAL_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_runtime_suspend, - exynos_rng_runtime_resume, NULL); +static const struct dev_pm_ops exynos_rng_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(exynos_rng_suspend, exynos_rng_resume) + SET_RUNTIME_PM_OPS(exynos_rng_runtime_suspend, + exynos_rng_runtime_resume, NULL) +}; + +static const struct of_device_id exynos_rng_dt_match[] = { + { + .compatible = "samsung,exynos4-rng", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, exynos_rng_dt_match); static struct platform_driver exynos_rng_driver = { .driver = { .name = "exynos-rng", - .owner = THIS_MODULE, .pm = &exynos_rng_pm_ops, + .of_match_table = exynos_rng_dt_match, }, .probe = exynos_rng_probe, - .remove = exynos_rng_remove, }; module_platform_driver(exynos_rng_driver);