timeriomem-rng.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * drivers/char/hw_random/timeriomem-rng.c
  3. *
  4. * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk>
  5. *
  6. * Derived from drivers/char/hw_random/omap-rng.c
  7. * Copyright 2005 (c) MontaVista Software, Inc.
  8. * Author: Deepak Saxena <dsaxena@plexity.net>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. *
  14. * Overview:
  15. * This driver is useful for platforms that have an IO range that provides
  16. * periodic random data from a single IO memory address. All the platform
  17. * has to do is provide the address and 'wait time' that new data becomes
  18. * available.
  19. *
  20. * TODO: add support for reading sizes other than 32bits and masking
  21. */
  22. #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>
  32. static struct timeriomem_rng_data *timeriomem_rng_data;
  33. static void timeriomem_rng_trigger(unsigned long);
  34. static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0);
  35. /*
  36. * have data return 1, however return 0 if we have nothing
  37. */
  38. static int timeriomem_rng_data_present(struct hwrng *rng, int wait)
  39. {
  40. if (rng->priv == 0)
  41. return 1;
  42. if (!wait || timeriomem_rng_data->present)
  43. return timeriomem_rng_data->present;
  44. wait_for_completion(&timeriomem_rng_data->completion);
  45. return 1;
  46. }
  47. static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data)
  48. {
  49. unsigned long cur;
  50. s32 delay;
  51. *data = readl(timeriomem_rng_data->address);
  52. if (rng->priv != 0) {
  53. cur = jiffies;
  54. delay = cur - timeriomem_rng_timer.expires;
  55. delay = rng->priv - (delay % rng->priv);
  56. timeriomem_rng_timer.expires = cur + delay;
  57. timeriomem_rng_data->present = 0;
  58. init_completion(&timeriomem_rng_data->completion);
  59. add_timer(&timeriomem_rng_timer);
  60. }
  61. return 4;
  62. }
  63. static void timeriomem_rng_trigger(unsigned long dummy)
  64. {
  65. timeriomem_rng_data->present = 1;
  66. complete(&timeriomem_rng_data->completion);
  67. }
  68. static struct hwrng timeriomem_rng_ops = {
  69. .name = "timeriomem",
  70. .data_present = timeriomem_rng_data_present,
  71. .data_read = timeriomem_rng_data_read,
  72. .priv = 0,
  73. };
  74. static int __devinit timeriomem_rng_probe(struct platform_device *pdev)
  75. {
  76. struct resource *res;
  77. int ret;
  78. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  79. if (!res)
  80. return -ENOENT;
  81. timeriomem_rng_data = pdev->dev.platform_data;
  82. timeriomem_rng_data->address = ioremap(res->start, resource_size(res));
  83. if (!timeriomem_rng_data->address)
  84. return -EIO;
  85. if (timeriomem_rng_data->period != 0
  86. && usecs_to_jiffies(timeriomem_rng_data->period) > 0) {
  87. timeriomem_rng_timer.expires = jiffies;
  88. timeriomem_rng_ops.priv = usecs_to_jiffies(
  89. timeriomem_rng_data->period);
  90. }
  91. timeriomem_rng_data->present = 1;
  92. ret = hwrng_register(&timeriomem_rng_ops);
  93. if (ret)
  94. goto failed;
  95. dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
  96. timeriomem_rng_data->address,
  97. timeriomem_rng_data->period);
  98. return 0;
  99. failed:
  100. dev_err(&pdev->dev, "problem registering\n");
  101. iounmap(timeriomem_rng_data->address);
  102. return ret;
  103. }
  104. static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
  105. {
  106. del_timer_sync(&timeriomem_rng_timer);
  107. hwrng_unregister(&timeriomem_rng_ops);
  108. iounmap(timeriomem_rng_data->address);
  109. return 0;
  110. }
  111. static struct platform_driver timeriomem_rng_driver = {
  112. .driver = {
  113. .name = "timeriomem_rng",
  114. .owner = THIS_MODULE,
  115. },
  116. .probe = timeriomem_rng_probe,
  117. .remove = __devexit_p(timeriomem_rng_remove),
  118. };
  119. module_platform_driver(timeriomem_rng_driver);
  120. MODULE_LICENSE("GPL");
  121. MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
  122. MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");