reboot-mode-rtc.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c), Vaisala Oyj
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <dm/device_compat.h>
  8. #include <reboot-mode/reboot-mode-rtc.h>
  9. #include <reboot-mode/reboot-mode.h>
  10. #include <rtc.h>
  11. DECLARE_GLOBAL_DATA_PTR;
  12. static int reboot_mode_get(struct udevice *dev, u32 *buf)
  13. {
  14. if (!buf)
  15. return -EINVAL;
  16. int ret;
  17. u8 *val = (u8 *)buf;
  18. struct reboot_mode_rtc_platdata *plat_data;
  19. plat_data = dev_get_plat(dev);
  20. if (!plat_data)
  21. return -EINVAL;
  22. for (int i = 0; i < plat_data->size; i++) {
  23. ret = rtc_read8(plat_data->rtc, plat_data->addr + i);
  24. if (ret < 0)
  25. return ret;
  26. val[i] = ret;
  27. }
  28. if (plat_data->is_big_endian)
  29. *buf = __be32_to_cpu(*buf);
  30. else
  31. *buf = __le32_to_cpu(*buf);
  32. return 0;
  33. }
  34. static int reboot_mode_set(struct udevice *dev, u32 buf)
  35. {
  36. int ret;
  37. u8 *val;
  38. struct reboot_mode_rtc_platdata *plat_data;
  39. plat_data = dev_get_plat(dev);
  40. if (!plat_data)
  41. return -EINVAL;
  42. if (plat_data->is_big_endian)
  43. buf = __cpu_to_be32(buf);
  44. else
  45. buf = __cpu_to_le32(buf);
  46. val = (u8 *)&buf;
  47. for (int i = 0; i < plat_data->size; i++) {
  48. ret = rtc_write8(plat_data->rtc, (plat_data->addr + i), val[i]);
  49. if (ret < 0)
  50. return ret;
  51. }
  52. return 0;
  53. }
  54. #if CONFIG_IS_ENABLED(OF_CONTROL)
  55. static int reboot_mode_ofdata_to_platdata(struct udevice *dev)
  56. {
  57. struct ofnode_phandle_args phandle_args;
  58. struct reboot_mode_rtc_platdata *plat_data;
  59. plat_data = dev_get_plat(dev);
  60. if (!plat_data)
  61. return -EINVAL;
  62. if (dev_read_phandle_with_args(dev, "rtc", NULL, 0, 0, &phandle_args)) {
  63. dev_err(dev, "RTC device not specified\n");
  64. return -ENOENT;
  65. }
  66. if (uclass_get_device_by_ofnode(UCLASS_RTC, phandle_args.node,
  67. &plat_data->rtc)) {
  68. dev_err(dev, "could not get the RTC device\n");
  69. return -ENODEV;
  70. }
  71. plat_data->addr =
  72. dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat_data->size);
  73. if (plat_data->addr == FDT_ADDR_T_NONE) {
  74. dev_err(dev, "Invalid RTC address\n");
  75. return -EINVAL;
  76. }
  77. if (plat_data->size > sizeof(u32)) {
  78. dev_err(dev, "Invalid reg size\n");
  79. return -EINVAL;
  80. }
  81. plat_data->is_big_endian = ofnode_read_bool(dev_ofnode(dev), "big-endian");
  82. return 0;
  83. }
  84. static const struct udevice_id reboot_mode_ids[] = {
  85. { .compatible = "reboot-mode-rtc", 0 },
  86. {}
  87. };
  88. #endif
  89. static const struct reboot_mode_ops reboot_mode_rtc_ops = {
  90. .get = reboot_mode_get,
  91. .set = reboot_mode_set,
  92. };
  93. U_BOOT_DRIVER(reboot_mode_rtc) = {
  94. .name = "reboot-mode-rtc",
  95. .id = UCLASS_REBOOT_MODE,
  96. #if CONFIG_IS_ENABLED(OF_CONTROL)
  97. .of_match = reboot_mode_ids,
  98. .of_to_plat = reboot_mode_ofdata_to_platdata,
  99. #endif
  100. .plat_auto = sizeof(struct reboot_mode_rtc_platdata),
  101. .ops = &reboot_mode_rtc_ops,
  102. };