vexpress-poweroff.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. *
  4. * Copyright (C) 2012 ARM Limited
  5. */
  6. #include <linux/delay.h>
  7. #include <linux/notifier.h>
  8. #include <linux/of.h>
  9. #include <linux/of_device.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/reboot.h>
  12. #include <linux/stat.h>
  13. #include <linux/vexpress.h>
  14. static void vexpress_reset_do(struct device *dev, const char *what)
  15. {
  16. int err = -ENOENT;
  17. struct regmap *reg = dev_get_drvdata(dev);
  18. if (reg) {
  19. err = regmap_write(reg, 0, 0);
  20. if (!err)
  21. mdelay(1000);
  22. }
  23. dev_emerg(dev, "Unable to %s (%d)\n", what, err);
  24. }
  25. static struct device *vexpress_power_off_device;
  26. static atomic_t vexpress_restart_nb_refcnt = ATOMIC_INIT(0);
  27. static void vexpress_power_off(void)
  28. {
  29. vexpress_reset_do(vexpress_power_off_device, "power off");
  30. }
  31. static struct device *vexpress_restart_device;
  32. static int vexpress_restart(struct notifier_block *this, unsigned long mode,
  33. void *cmd)
  34. {
  35. vexpress_reset_do(vexpress_restart_device, "restart");
  36. return NOTIFY_DONE;
  37. }
  38. static struct notifier_block vexpress_restart_nb = {
  39. .notifier_call = vexpress_restart,
  40. .priority = 128,
  41. };
  42. static ssize_t vexpress_reset_active_show(struct device *dev,
  43. struct device_attribute *attr, char *buf)
  44. {
  45. return sprintf(buf, "%d\n", vexpress_restart_device == dev);
  46. }
  47. static ssize_t vexpress_reset_active_store(struct device *dev,
  48. struct device_attribute *attr, const char *buf, size_t count)
  49. {
  50. long value;
  51. int err = kstrtol(buf, 0, &value);
  52. if (!err && value)
  53. vexpress_restart_device = dev;
  54. return err ? err : count;
  55. }
  56. static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, vexpress_reset_active_show,
  57. vexpress_reset_active_store);
  58. enum vexpress_reset_func { FUNC_RESET, FUNC_SHUTDOWN, FUNC_REBOOT };
  59. static const struct of_device_id vexpress_reset_of_match[] = {
  60. {
  61. .compatible = "arm,vexpress-reset",
  62. .data = (void *)FUNC_RESET,
  63. }, {
  64. .compatible = "arm,vexpress-shutdown",
  65. .data = (void *)FUNC_SHUTDOWN
  66. }, {
  67. .compatible = "arm,vexpress-reboot",
  68. .data = (void *)FUNC_REBOOT
  69. },
  70. {}
  71. };
  72. static int _vexpress_register_restart_handler(struct device *dev)
  73. {
  74. int err;
  75. vexpress_restart_device = dev;
  76. if (atomic_inc_return(&vexpress_restart_nb_refcnt) == 1) {
  77. err = register_restart_handler(&vexpress_restart_nb);
  78. if (err) {
  79. dev_err(dev, "cannot register restart handler (err=%d)\n", err);
  80. atomic_dec(&vexpress_restart_nb_refcnt);
  81. return err;
  82. }
  83. }
  84. device_create_file(dev, &dev_attr_active);
  85. return 0;
  86. }
  87. static int vexpress_reset_probe(struct platform_device *pdev)
  88. {
  89. const struct of_device_id *match =
  90. of_match_device(vexpress_reset_of_match, &pdev->dev);
  91. struct regmap *regmap;
  92. int ret = 0;
  93. if (!match)
  94. return -EINVAL;
  95. regmap = devm_regmap_init_vexpress_config(&pdev->dev);
  96. if (IS_ERR(regmap))
  97. return PTR_ERR(regmap);
  98. dev_set_drvdata(&pdev->dev, regmap);
  99. switch ((enum vexpress_reset_func)match->data) {
  100. case FUNC_SHUTDOWN:
  101. vexpress_power_off_device = &pdev->dev;
  102. pm_power_off = vexpress_power_off;
  103. break;
  104. case FUNC_RESET:
  105. if (!vexpress_restart_device)
  106. ret = _vexpress_register_restart_handler(&pdev->dev);
  107. break;
  108. case FUNC_REBOOT:
  109. ret = _vexpress_register_restart_handler(&pdev->dev);
  110. break;
  111. }
  112. return ret;
  113. }
  114. static struct platform_driver vexpress_reset_driver = {
  115. .probe = vexpress_reset_probe,
  116. .driver = {
  117. .name = "vexpress-reset",
  118. .of_match_table = vexpress_reset_of_match,
  119. .suppress_bind_attrs = true,
  120. },
  121. };
  122. builtin_platform_driver(vexpress_reset_driver);