Path: blob/master/drivers/char/hw_random/timeriomem-rng.c
15111 views
/*1* drivers/char/hw_random/timeriomem-rng.c2*3* Copyright (C) 2009 Alexander Clouter <[email protected]>4*5* Derived from drivers/char/hw_random/omap-rng.c6* Copyright 2005 (c) MontaVista Software, Inc.7* Author: Deepak Saxena <[email protected]>8*9* This program is free software; you can redistribute it and/or modify10* it under the terms of the GNU General Public License version 2 as11* published by the Free Software Foundation.12*13* Overview:14* This driver is useful for platforms that have an IO range that provides15* periodic random data from a single IO memory address. All the platform16* has to do is provide the address and 'wait time' that new data becomes17* available.18*19* TODO: add support for reading sizes other than 32bits and masking20*/2122#include <linux/module.h>23#include <linux/kernel.h>24#include <linux/platform_device.h>25#include <linux/hw_random.h>26#include <linux/io.h>27#include <linux/timeriomem-rng.h>28#include <linux/jiffies.h>29#include <linux/sched.h>30#include <linux/timer.h>31#include <linux/completion.h>3233static struct timeriomem_rng_data *timeriomem_rng_data;3435static void timeriomem_rng_trigger(unsigned long);36static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0);3738/*39* have data return 1, however return 0 if we have nothing40*/41static int timeriomem_rng_data_present(struct hwrng *rng, int wait)42{43if (rng->priv == 0)44return 1;4546if (!wait || timeriomem_rng_data->present)47return timeriomem_rng_data->present;4849wait_for_completion(&timeriomem_rng_data->completion);5051return 1;52}5354static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data)55{56unsigned long cur;57s32 delay;5859*data = readl(timeriomem_rng_data->address);6061if (rng->priv != 0) {62cur = jiffies;6364delay = cur - timeriomem_rng_timer.expires;65delay = rng->priv - (delay % rng->priv);6667timeriomem_rng_timer.expires = cur + delay;68timeriomem_rng_data->present = 0;6970init_completion(&timeriomem_rng_data->completion);71add_timer(&timeriomem_rng_timer);72}7374return 4;75}7677static void timeriomem_rng_trigger(unsigned long dummy)78{79timeriomem_rng_data->present = 1;80complete(&timeriomem_rng_data->completion);81}8283static struct hwrng timeriomem_rng_ops = {84.name = "timeriomem",85.data_present = timeriomem_rng_data_present,86.data_read = timeriomem_rng_data_read,87.priv = 0,88};8990static int __devinit timeriomem_rng_probe(struct platform_device *pdev)91{92struct resource *res;93int ret;9495res = platform_get_resource(pdev, IORESOURCE_MEM, 0);9697if (!res)98return -ENOENT;99100timeriomem_rng_data = pdev->dev.platform_data;101102timeriomem_rng_data->address = ioremap(res->start,103res->end - res->start + 1);104if (!timeriomem_rng_data->address)105return -EIO;106107if (timeriomem_rng_data->period != 0108&& usecs_to_jiffies(timeriomem_rng_data->period) > 0) {109timeriomem_rng_timer.expires = jiffies;110111timeriomem_rng_ops.priv = usecs_to_jiffies(112timeriomem_rng_data->period);113}114timeriomem_rng_data->present = 1;115116ret = hwrng_register(&timeriomem_rng_ops);117if (ret)118goto failed;119120dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",121timeriomem_rng_data->address,122timeriomem_rng_data->period);123124return 0;125126failed:127dev_err(&pdev->dev, "problem registering\n");128iounmap(timeriomem_rng_data->address);129130return ret;131}132133static int __devexit timeriomem_rng_remove(struct platform_device *pdev)134{135del_timer_sync(&timeriomem_rng_timer);136hwrng_unregister(&timeriomem_rng_ops);137138iounmap(timeriomem_rng_data->address);139140return 0;141}142143static struct platform_driver timeriomem_rng_driver = {144.driver = {145.name = "timeriomem_rng",146.owner = THIS_MODULE,147},148.probe = timeriomem_rng_probe,149.remove = __devexit_p(timeriomem_rng_remove),150};151152static int __init timeriomem_rng_init(void)153{154return platform_driver_register(&timeriomem_rng_driver);155}156157static void __exit timeriomem_rng_exit(void)158{159platform_driver_unregister(&timeriomem_rng_driver);160}161162module_init(timeriomem_rng_init);163module_exit(timeriomem_rng_exit);164165MODULE_LICENSE("GPL");166MODULE_AUTHOR("Alexander Clouter <[email protected]>");167MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");168169170