rtc-dm355evm.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * rtc-dm355evm.c - access battery-backed counter in MSP430 firmware
  4. *
  5. * Copyright (c) 2008 by David Brownell
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/init.h>
  9. #include <linux/rtc.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/mfd/dm355evm_msp.h>
  12. #include <linux/module.h>
  13. /*
  14. * The MSP430 firmware on the DM355 EVM uses a watch crystal to feed
  15. * a 1 Hz counter. When a backup battery is supplied, that makes a
  16. * reasonable RTC for applications where alarms and non-NTP drift
  17. * compensation aren't important.
  18. *
  19. * The only real glitch is the inability to read or write all four
  20. * counter bytes atomically: the count may increment in the middle
  21. * of an operation, causing trouble when the LSB rolls over.
  22. *
  23. * This driver was tested with firmware revision A4.
  24. */
  25. union evm_time {
  26. u8 bytes[4];
  27. u32 value;
  28. };
  29. static int dm355evm_rtc_read_time(struct device *dev, struct rtc_time *tm)
  30. {
  31. union evm_time time;
  32. int status;
  33. int tries = 0;
  34. do {
  35. /*
  36. * Read LSB(0) to MSB(3) bytes. Defend against the counter
  37. * rolling over by re-reading until the value is stable,
  38. * and assuming the four reads take at most a few seconds.
  39. */
  40. status = dm355evm_msp_read(DM355EVM_MSP_RTC_0);
  41. if (status < 0)
  42. return status;
  43. if (tries && time.bytes[0] == status)
  44. break;
  45. time.bytes[0] = status;
  46. status = dm355evm_msp_read(DM355EVM_MSP_RTC_1);
  47. if (status < 0)
  48. return status;
  49. if (tries && time.bytes[1] == status)
  50. break;
  51. time.bytes[1] = status;
  52. status = dm355evm_msp_read(DM355EVM_MSP_RTC_2);
  53. if (status < 0)
  54. return status;
  55. if (tries && time.bytes[2] == status)
  56. break;
  57. time.bytes[2] = status;
  58. status = dm355evm_msp_read(DM355EVM_MSP_RTC_3);
  59. if (status < 0)
  60. return status;
  61. if (tries && time.bytes[3] == status)
  62. break;
  63. time.bytes[3] = status;
  64. } while (++tries < 5);
  65. dev_dbg(dev, "read timestamp %08x\n", time.value);
  66. rtc_time64_to_tm(le32_to_cpu(time.value), tm);
  67. return 0;
  68. }
  69. static int dm355evm_rtc_set_time(struct device *dev, struct rtc_time *tm)
  70. {
  71. union evm_time time;
  72. unsigned long value;
  73. int status;
  74. value = rtc_tm_to_time64(tm);
  75. time.value = cpu_to_le32(value);
  76. dev_dbg(dev, "write timestamp %08x\n", time.value);
  77. /*
  78. * REVISIT handle non-atomic writes ... maybe just retry until
  79. * byte[1] sticks (no rollover)?
  80. */
  81. status = dm355evm_msp_write(time.bytes[0], DM355EVM_MSP_RTC_0);
  82. if (status < 0)
  83. return status;
  84. status = dm355evm_msp_write(time.bytes[1], DM355EVM_MSP_RTC_1);
  85. if (status < 0)
  86. return status;
  87. status = dm355evm_msp_write(time.bytes[2], DM355EVM_MSP_RTC_2);
  88. if (status < 0)
  89. return status;
  90. status = dm355evm_msp_write(time.bytes[3], DM355EVM_MSP_RTC_3);
  91. if (status < 0)
  92. return status;
  93. return 0;
  94. }
  95. static const struct rtc_class_ops dm355evm_rtc_ops = {
  96. .read_time = dm355evm_rtc_read_time,
  97. .set_time = dm355evm_rtc_set_time,
  98. };
  99. /*----------------------------------------------------------------------*/
  100. static int dm355evm_rtc_probe(struct platform_device *pdev)
  101. {
  102. struct rtc_device *rtc;
  103. rtc = devm_rtc_allocate_device(&pdev->dev);
  104. if (IS_ERR(rtc))
  105. return PTR_ERR(rtc);
  106. platform_set_drvdata(pdev, rtc);
  107. rtc->ops = &dm355evm_rtc_ops;
  108. rtc->range_max = U32_MAX;
  109. return rtc_register_device(rtc);
  110. }
  111. /*
  112. * I2C is used to talk to the MSP430, but this platform device is
  113. * exposed by an MFD driver that manages I2C communications.
  114. */
  115. static struct platform_driver rtc_dm355evm_driver = {
  116. .probe = dm355evm_rtc_probe,
  117. .driver = {
  118. .name = "rtc-dm355evm",
  119. },
  120. };
  121. module_platform_driver(rtc_dm355evm_driver);
  122. MODULE_LICENSE("GPL");