scmi_pm_domain.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * SCMI Generic power domain support.
  4. *
  5. * Copyright (C) 2018-2021 ARM Ltd.
  6. */
  7. #include <linux/err.h>
  8. #include <linux/io.h>
  9. #include <linux/module.h>
  10. #include <linux/pm_domain.h>
  11. #include <linux/scmi_protocol.h>
  12. static const struct scmi_power_proto_ops *power_ops;
  13. struct scmi_pm_domain {
  14. struct generic_pm_domain genpd;
  15. const struct scmi_protocol_handle *ph;
  16. const char *name;
  17. u32 domain;
  18. };
  19. #define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd)
  20. static int scmi_pd_power(struct generic_pm_domain *domain, u32 state)
  21. {
  22. struct scmi_pm_domain *pd = to_scmi_pd(domain);
  23. return power_ops->state_set(pd->ph, pd->domain, state);
  24. }
  25. static int scmi_pd_power_on(struct generic_pm_domain *domain)
  26. {
  27. return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_ON);
  28. }
  29. static int scmi_pd_power_off(struct generic_pm_domain *domain)
  30. {
  31. return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_OFF);
  32. }
  33. static int scmi_pm_domain_probe(struct scmi_device *sdev)
  34. {
  35. int num_domains, i, ret;
  36. struct device *dev = &sdev->dev;
  37. struct device_node *np = dev->of_node;
  38. struct scmi_pm_domain *scmi_pd;
  39. struct genpd_onecell_data *scmi_pd_data;
  40. struct generic_pm_domain **domains;
  41. const struct scmi_handle *handle = sdev->handle;
  42. struct scmi_protocol_handle *ph;
  43. if (!handle)
  44. return -ENODEV;
  45. power_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_POWER, &ph);
  46. if (IS_ERR(power_ops))
  47. return PTR_ERR(power_ops);
  48. num_domains = power_ops->num_domains_get(ph);
  49. if (num_domains < 0) {
  50. dev_err(dev, "number of domains not found\n");
  51. return num_domains;
  52. }
  53. scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL);
  54. if (!scmi_pd)
  55. return -ENOMEM;
  56. scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL);
  57. if (!scmi_pd_data)
  58. return -ENOMEM;
  59. domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
  60. if (!domains)
  61. return -ENOMEM;
  62. for (i = 0; i < num_domains; i++, scmi_pd++) {
  63. u32 state;
  64. if (power_ops->state_get(ph, i, &state)) {
  65. dev_warn(dev, "failed to get state for domain %d\n", i);
  66. continue;
  67. }
  68. /*
  69. * Register the explicit power on request to the firmware so
  70. * that it is tracked as used by OSPM agent and not
  71. * accidentally turned off with OSPM's knowledge
  72. */
  73. if (state == SCMI_POWER_STATE_GENERIC_ON)
  74. power_ops->state_set(ph, i, state);
  75. scmi_pd->domain = i;
  76. scmi_pd->ph = ph;
  77. scmi_pd->name = power_ops->name_get(ph, i);
  78. scmi_pd->genpd.name = scmi_pd->name;
  79. scmi_pd->genpd.power_off = scmi_pd_power_off;
  80. scmi_pd->genpd.power_on = scmi_pd_power_on;
  81. scmi_pd->genpd.flags = GENPD_FLAG_ACTIVE_WAKEUP;
  82. pm_genpd_init(&scmi_pd->genpd, NULL,
  83. state == SCMI_POWER_STATE_GENERIC_OFF);
  84. domains[i] = &scmi_pd->genpd;
  85. }
  86. scmi_pd_data->domains = domains;
  87. scmi_pd_data->num_domains = num_domains;
  88. ret = of_genpd_add_provider_onecell(np, scmi_pd_data);
  89. if (ret)
  90. goto err_rm_genpds;
  91. dev_set_drvdata(dev, scmi_pd_data);
  92. return 0;
  93. err_rm_genpds:
  94. for (i = num_domains - 1; i >= 0; i--)
  95. pm_genpd_remove(domains[i]);
  96. return ret;
  97. }
  98. static void scmi_pm_domain_remove(struct scmi_device *sdev)
  99. {
  100. int i;
  101. struct genpd_onecell_data *scmi_pd_data;
  102. struct device *dev = &sdev->dev;
  103. struct device_node *np = dev->of_node;
  104. of_genpd_del_provider(np);
  105. scmi_pd_data = dev_get_drvdata(dev);
  106. for (i = 0; i < scmi_pd_data->num_domains; i++) {
  107. if (!scmi_pd_data->domains[i])
  108. continue;
  109. pm_genpd_remove(scmi_pd_data->domains[i]);
  110. }
  111. }
  112. static const struct scmi_device_id scmi_id_table[] = {
  113. { SCMI_PROTOCOL_POWER, "genpd" },
  114. { },
  115. };
  116. MODULE_DEVICE_TABLE(scmi, scmi_id_table);
  117. static struct scmi_driver scmi_power_domain_driver = {
  118. .name = "scmi-power-domain",
  119. .probe = scmi_pm_domain_probe,
  120. .remove = scmi_pm_domain_remove,
  121. .id_table = scmi_id_table,
  122. };
  123. module_scmi_driver(scmi_power_domain_driver);
  124. MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
  125. MODULE_DESCRIPTION("ARM SCMI power domain driver");
  126. MODULE_LICENSE("GPL v2");