sm-misc.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2024 NXP
  4. */
  5. #include <linux/firmware/imx/sm.h>
  6. #include <linux/module.h>
  7. #include <linux/of.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/scmi_protocol.h>
  10. #include <linux/scmi_imx_protocol.h>
  11. static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops;
  12. static struct scmi_protocol_handle *ph;
  13. struct notifier_block scmi_imx_misc_ctrl_nb;
  14. int scmi_imx_misc_ctrl_set(u32 id, u32 val)
  15. {
  16. if (!ph)
  17. return -EPROBE_DEFER;
  18. return imx_misc_ctrl_ops->misc_ctrl_set(ph, id, 1, &val);
  19. };
  20. EXPORT_SYMBOL(scmi_imx_misc_ctrl_set);
  21. int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val)
  22. {
  23. if (!ph)
  24. return -EPROBE_DEFER;
  25. return imx_misc_ctrl_ops->misc_ctrl_get(ph, id, num, val);
  26. }
  27. EXPORT_SYMBOL(scmi_imx_misc_ctrl_get);
  28. static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb,
  29. unsigned long event, void *data)
  30. {
  31. /*
  32. * notifier_chain_register requires a valid notifier_block and
  33. * valid notifier_call. SCMI_EVENT_IMX_MISC_CONTROL is needed
  34. * to let SCMI firmware enable control events, but the hook here
  35. * is just a dummy function to avoid kernel panic as of now.
  36. */
  37. return 0;
  38. }
  39. static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
  40. {
  41. const struct scmi_handle *handle = sdev->handle;
  42. struct device_node *np = sdev->dev.of_node;
  43. u32 src_id, flags;
  44. int ret, i, num;
  45. if (!handle)
  46. return -ENODEV;
  47. if (imx_misc_ctrl_ops) {
  48. dev_err(&sdev->dev, "misc ctrl already initialized\n");
  49. return -EEXIST;
  50. }
  51. imx_misc_ctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_MISC, &ph);
  52. if (IS_ERR(imx_misc_ctrl_ops))
  53. return PTR_ERR(imx_misc_ctrl_ops);
  54. num = of_property_count_u32_elems(np, "nxp,ctrl-ids");
  55. if (num % 2) {
  56. dev_err(&sdev->dev, "Invalid wakeup-sources\n");
  57. return -EINVAL;
  58. }
  59. scmi_imx_misc_ctrl_nb.notifier_call = &scmi_imx_misc_ctrl_notifier;
  60. for (i = 0; i < num; i += 2) {
  61. ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i, &src_id);
  62. if (ret) {
  63. dev_err(&sdev->dev, "Failed to read ctrl-id: %i\n", i);
  64. continue;
  65. }
  66. ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i + 1, &flags);
  67. if (ret) {
  68. dev_err(&sdev->dev, "Failed to read ctrl-id value: %d\n", i + 1);
  69. continue;
  70. }
  71. ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_MISC,
  72. SCMI_EVENT_IMX_MISC_CONTROL,
  73. &src_id,
  74. &scmi_imx_misc_ctrl_nb);
  75. if (ret) {
  76. dev_err(&sdev->dev, "Failed to register scmi misc event: %d\n", src_id);
  77. } else {
  78. ret = imx_misc_ctrl_ops->misc_ctrl_req_notify(ph, src_id,
  79. SCMI_EVENT_IMX_MISC_CONTROL,
  80. flags);
  81. if (ret)
  82. dev_err(&sdev->dev, "Failed to req notify: %d\n", src_id);
  83. }
  84. }
  85. return 0;
  86. }
  87. static const struct scmi_device_id scmi_id_table[] = {
  88. { SCMI_PROTOCOL_IMX_MISC, "imx-misc-ctrl" },
  89. { },
  90. };
  91. MODULE_DEVICE_TABLE(scmi, scmi_id_table);
  92. static struct scmi_driver scmi_imx_misc_ctrl_driver = {
  93. .name = "scmi-imx-misc-ctrl",
  94. .probe = scmi_imx_misc_ctrl_probe,
  95. .id_table = scmi_id_table,
  96. };
  97. module_scmi_driver(scmi_imx_misc_ctrl_driver);
  98. MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
  99. MODULE_DESCRIPTION("IMX SM MISC driver");
  100. MODULE_LICENSE("GPL");