rtc-sun4v.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
  2. *
  3. * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/module.h>
  7. #include <linux/delay.h>
  8. #include <linux/init.h>
  9. #include <linux/rtc.h>
  10. #include <linux/platform_device.h>
  11. #include <asm/hypervisor.h>
  12. static unsigned long hypervisor_get_time(void)
  13. {
  14. unsigned long ret, time;
  15. int retries = 10000;
  16. retry:
  17. ret = sun4v_tod_get(&time);
  18. if (ret == HV_EOK)
  19. return time;
  20. if (ret == HV_EWOULDBLOCK) {
  21. if (--retries > 0) {
  22. udelay(100);
  23. goto retry;
  24. }
  25. printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
  26. return 0;
  27. }
  28. printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
  29. return 0;
  30. }
  31. static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
  32. {
  33. rtc_time_to_tm(hypervisor_get_time(), tm);
  34. return 0;
  35. }
  36. static int hypervisor_set_time(unsigned long secs)
  37. {
  38. unsigned long ret;
  39. int retries = 10000;
  40. retry:
  41. ret = sun4v_tod_set(secs);
  42. if (ret == HV_EOK)
  43. return 0;
  44. if (ret == HV_EWOULDBLOCK) {
  45. if (--retries > 0) {
  46. udelay(100);
  47. goto retry;
  48. }
  49. printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
  50. return -EAGAIN;
  51. }
  52. printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
  53. return -EOPNOTSUPP;
  54. }
  55. static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
  56. {
  57. unsigned long secs;
  58. int err;
  59. err = rtc_tm_to_time(tm, &secs);
  60. if (err)
  61. return err;
  62. return hypervisor_set_time(secs);
  63. }
  64. static const struct rtc_class_ops sun4v_rtc_ops = {
  65. .read_time = sun4v_read_time,
  66. .set_time = sun4v_set_time,
  67. };
  68. static int __init sun4v_rtc_probe(struct platform_device *pdev)
  69. {
  70. struct rtc_device *rtc = rtc_device_register("sun4v", &pdev->dev,
  71. &sun4v_rtc_ops, THIS_MODULE);
  72. if (IS_ERR(rtc))
  73. return PTR_ERR(rtc);
  74. platform_set_drvdata(pdev, rtc);
  75. return 0;
  76. }
  77. static int __exit sun4v_rtc_remove(struct platform_device *pdev)
  78. {
  79. struct rtc_device *rtc = platform_get_drvdata(pdev);
  80. rtc_device_unregister(rtc);
  81. return 0;
  82. }
  83. static struct platform_driver sun4v_rtc_driver = {
  84. .driver = {
  85. .name = "rtc-sun4v",
  86. .owner = THIS_MODULE,
  87. },
  88. .remove = __exit_p(sun4v_rtc_remove),
  89. };
  90. static int __init sun4v_rtc_init(void)
  91. {
  92. return platform_driver_probe(&sun4v_rtc_driver, sun4v_rtc_probe);
  93. }
  94. static void __exit sun4v_rtc_exit(void)
  95. {
  96. platform_driver_unregister(&sun4v_rtc_driver);
  97. }
  98. module_init(sun4v_rtc_init);
  99. module_exit(sun4v_rtc_exit);
  100. MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
  101. MODULE_DESCRIPTION("SUN4V RTC driver");
  102. MODULE_LICENSE("GPL");