th1520-aon-reboot.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * T-HEAD TH1520 AON Firmware Reboot Driver
  4. *
  5. * Copyright (c) 2025 Icenowy Zheng <uwu@icenowy.me>
  6. */
  7. #include <linux/auxiliary_bus.h>
  8. #include <linux/firmware/thead/thead,th1520-aon.h>
  9. #include <linux/module.h>
  10. #include <linux/notifier.h>
  11. #include <linux/of.h>
  12. #include <linux/reboot.h>
  13. #include <linux/slab.h>
  14. #define TH1520_AON_REBOOT_PRIORITY 200
  15. struct th1520_aon_msg_empty_body {
  16. struct th1520_aon_rpc_msg_hdr hdr;
  17. u16 reserved[12];
  18. } __packed __aligned(1);
  19. static int th1520_aon_pwroff_handler(struct sys_off_data *data)
  20. {
  21. struct th1520_aon_chan *aon_chan = data->cb_data;
  22. struct th1520_aon_msg_empty_body msg = {};
  23. msg.hdr.svc = TH1520_AON_RPC_SVC_WDG;
  24. msg.hdr.func = TH1520_AON_WDG_FUNC_POWER_OFF;
  25. msg.hdr.size = TH1520_AON_RPC_MSG_NUM;
  26. th1520_aon_call_rpc(aon_chan, &msg);
  27. return NOTIFY_DONE;
  28. }
  29. static int th1520_aon_restart_handler(struct sys_off_data *data)
  30. {
  31. struct th1520_aon_chan *aon_chan = data->cb_data;
  32. struct th1520_aon_msg_empty_body msg = {};
  33. msg.hdr.svc = TH1520_AON_RPC_SVC_WDG;
  34. msg.hdr.func = TH1520_AON_WDG_FUNC_RESTART;
  35. msg.hdr.size = TH1520_AON_RPC_MSG_NUM;
  36. th1520_aon_call_rpc(aon_chan, &msg);
  37. return NOTIFY_DONE;
  38. }
  39. static int th1520_aon_reboot_probe(struct auxiliary_device *adev,
  40. const struct auxiliary_device_id *id)
  41. {
  42. struct device *dev = &adev->dev;
  43. int ret;
  44. /* Expect struct th1520_aon_chan to be passed via platform_data */
  45. ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF,
  46. TH1520_AON_REBOOT_PRIORITY,
  47. th1520_aon_pwroff_handler,
  48. adev->dev.platform_data);
  49. if (ret) {
  50. dev_err(dev, "Failed to register power off handler\n");
  51. return ret;
  52. }
  53. ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART,
  54. TH1520_AON_REBOOT_PRIORITY,
  55. th1520_aon_restart_handler,
  56. adev->dev.platform_data);
  57. if (ret) {
  58. dev_err(dev, "Failed to register restart handler\n");
  59. return ret;
  60. }
  61. return 0;
  62. }
  63. static const struct auxiliary_device_id th1520_aon_reboot_id_table[] = {
  64. { .name = "th1520_pm_domains.reboot" },
  65. {},
  66. };
  67. MODULE_DEVICE_TABLE(auxiliary, th1520_aon_reboot_id_table);
  68. static struct auxiliary_driver th1520_aon_reboot_driver = {
  69. .driver = {
  70. .name = "th1520-aon-reboot",
  71. },
  72. .probe = th1520_aon_reboot_probe,
  73. .id_table = th1520_aon_reboot_id_table,
  74. };
  75. module_auxiliary_driver(th1520_aon_reboot_driver);
  76. MODULE_AUTHOR("Icenowy Zheng <uwu@icenowy.me>");
  77. MODULE_DESCRIPTION("T-HEAD TH1520 AON-firmware-based reboot driver");
  78. MODULE_LICENSE("GPL");