sm-misc.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2024 NXP
  4. */
  5. #include <linux/debugfs.h>
  6. #include <linux/device/devres.h>
  7. #include <linux/firmware/imx/sm.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/scmi_protocol.h>
  12. #include <linux/scmi_imx_protocol.h>
  13. #include <linux/seq_file.h>
  14. #include <linux/sizes.h>
  15. static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops;
  16. static struct scmi_protocol_handle *ph;
  17. struct notifier_block scmi_imx_misc_ctrl_nb;
  18. int scmi_imx_misc_ctrl_set(u32 id, u32 val)
  19. {
  20. if (!ph)
  21. return -EPROBE_DEFER;
  22. return imx_misc_ctrl_ops->misc_ctrl_set(ph, id, 1, &val);
  23. };
  24. EXPORT_SYMBOL(scmi_imx_misc_ctrl_set);
  25. int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val)
  26. {
  27. if (!ph)
  28. return -EPROBE_DEFER;
  29. return imx_misc_ctrl_ops->misc_ctrl_get(ph, id, num, val);
  30. }
  31. EXPORT_SYMBOL(scmi_imx_misc_ctrl_get);
  32. static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb,
  33. unsigned long event, void *data)
  34. {
  35. /*
  36. * notifier_chain_register requires a valid notifier_block and
  37. * valid notifier_call. SCMI_EVENT_IMX_MISC_CONTROL is needed
  38. * to let SCMI firmware enable control events, but the hook here
  39. * is just a dummy function to avoid kernel panic as of now.
  40. */
  41. return 0;
  42. }
  43. static int syslog_show(struct seq_file *file, void *priv)
  44. {
  45. /* 4KB is large enough for syslog */
  46. void *syslog __free(kfree) = kmalloc(SZ_4K, GFP_KERNEL);
  47. /* syslog API use num words, not num bytes */
  48. u16 size = SZ_4K / 4;
  49. int ret;
  50. if (!ph)
  51. return -ENODEV;
  52. ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog);
  53. if (ret)
  54. return ret;
  55. seq_hex_dump(file, " ", DUMP_PREFIX_NONE, 16, sizeof(u32), syslog, size * 4, false);
  56. seq_putc(file, '\n');
  57. return 0;
  58. }
  59. DEFINE_SHOW_ATTRIBUTE(syslog);
  60. static void scmi_imx_misc_put(void *p)
  61. {
  62. debugfs_remove((struct dentry *)p);
  63. }
  64. static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
  65. {
  66. const struct scmi_handle *handle = sdev->handle;
  67. struct device_node *np = sdev->dev.of_node;
  68. struct dentry *scmi_imx_dentry;
  69. u32 src_id, flags;
  70. int ret, i, num;
  71. if (!handle)
  72. return -ENODEV;
  73. if (imx_misc_ctrl_ops) {
  74. dev_err(&sdev->dev, "misc ctrl already initialized\n");
  75. return -EEXIST;
  76. }
  77. imx_misc_ctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_MISC, &ph);
  78. if (IS_ERR(imx_misc_ctrl_ops))
  79. return PTR_ERR(imx_misc_ctrl_ops);
  80. num = of_property_count_u32_elems(np, "nxp,ctrl-ids");
  81. if (num % 2) {
  82. dev_err(&sdev->dev, "Invalid wakeup-sources\n");
  83. return -EINVAL;
  84. }
  85. scmi_imx_misc_ctrl_nb.notifier_call = &scmi_imx_misc_ctrl_notifier;
  86. for (i = 0; i < num; i += 2) {
  87. ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i, &src_id);
  88. if (ret) {
  89. dev_err(&sdev->dev, "Failed to read ctrl-id: %i\n", i);
  90. continue;
  91. }
  92. ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i + 1, &flags);
  93. if (ret) {
  94. dev_err(&sdev->dev, "Failed to read ctrl-id value: %d\n", i + 1);
  95. continue;
  96. }
  97. ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_MISC,
  98. SCMI_EVENT_IMX_MISC_CONTROL,
  99. &src_id,
  100. &scmi_imx_misc_ctrl_nb);
  101. if (ret) {
  102. dev_err(&sdev->dev, "Failed to register scmi misc event: %d\n", src_id);
  103. } else {
  104. ret = imx_misc_ctrl_ops->misc_ctrl_req_notify(ph, src_id,
  105. SCMI_EVENT_IMX_MISC_CONTROL,
  106. flags);
  107. if (ret)
  108. dev_err(&sdev->dev, "Failed to req notify: %d\n", src_id);
  109. }
  110. }
  111. scmi_imx_dentry = debugfs_create_dir("scmi_imx", NULL);
  112. debugfs_create_file("syslog", 0444, scmi_imx_dentry, &sdev->dev, &syslog_fops);
  113. return devm_add_action_or_reset(&sdev->dev, scmi_imx_misc_put, scmi_imx_dentry);
  114. }
  115. static const struct scmi_device_id scmi_id_table[] = {
  116. { SCMI_PROTOCOL_IMX_MISC, "imx-misc-ctrl" },
  117. { },
  118. };
  119. MODULE_DEVICE_TABLE(scmi, scmi_id_table);
  120. static struct scmi_driver scmi_imx_misc_ctrl_driver = {
  121. .name = "scmi-imx-misc-ctrl",
  122. .probe = scmi_imx_misc_ctrl_probe,
  123. .id_table = scmi_id_table,
  124. };
  125. module_scmi_driver(scmi_imx_misc_ctrl_driver);
  126. MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
  127. MODULE_DESCRIPTION("IMX SM MISC driver");
  128. MODULE_LICENSE("GPL");