power-domain-uclass.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2016, NVIDIA CORPORATION.
  4. */
  5. #define LOG_CATEGORY UCLASS_POWER_DOMAIN
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <log.h>
  9. #include <malloc.h>
  10. #include <power-domain.h>
  11. #include <power-domain-uclass.h>
  12. #include <dm/device-internal.h>
  13. static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev)
  14. {
  15. return (struct power_domain_ops *)dev->driver->ops;
  16. }
  17. static int power_domain_of_xlate_default(struct power_domain *power_domain,
  18. struct ofnode_phandle_args *args)
  19. {
  20. debug("%s(power_domain=%p)\n", __func__, power_domain);
  21. if (args->args_count != 1) {
  22. debug("Invalid args_count: %d\n", args->args_count);
  23. return -EINVAL;
  24. }
  25. power_domain->id = args->args[0];
  26. return 0;
  27. }
  28. int power_domain_get_by_index(struct udevice *dev,
  29. struct power_domain *power_domain, int index)
  30. {
  31. struct ofnode_phandle_args args;
  32. int ret;
  33. struct udevice *dev_power_domain;
  34. struct power_domain_ops *ops;
  35. debug("%s(dev=%p, power_domain=%p)\n", __func__, dev, power_domain);
  36. ret = dev_read_phandle_with_args(dev, "power-domains",
  37. "#power-domain-cells", 0, index,
  38. &args);
  39. if (ret) {
  40. debug("%s: dev_read_phandle_with_args failed: %d\n",
  41. __func__, ret);
  42. return ret;
  43. }
  44. ret = uclass_get_device_by_ofnode(UCLASS_POWER_DOMAIN, args.node,
  45. &dev_power_domain);
  46. if (ret) {
  47. debug("%s: uclass_get_device_by_ofnode failed: %d\n",
  48. __func__, ret);
  49. return ret;
  50. }
  51. ops = power_domain_dev_ops(dev_power_domain);
  52. power_domain->dev = dev_power_domain;
  53. if (ops->of_xlate)
  54. ret = ops->of_xlate(power_domain, &args);
  55. else
  56. ret = power_domain_of_xlate_default(power_domain, &args);
  57. if (ret) {
  58. debug("of_xlate() failed: %d\n", ret);
  59. return ret;
  60. }
  61. ret = ops->request(power_domain);
  62. if (ret) {
  63. debug("ops->request() failed: %d\n", ret);
  64. return ret;
  65. }
  66. return 0;
  67. }
  68. int power_domain_get(struct udevice *dev, struct power_domain *power_domain)
  69. {
  70. return power_domain_get_by_index(dev, power_domain, 0);
  71. }
  72. int power_domain_free(struct power_domain *power_domain)
  73. {
  74. struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
  75. debug("%s(power_domain=%p)\n", __func__, power_domain);
  76. return ops->rfree(power_domain);
  77. }
  78. int power_domain_on(struct power_domain *power_domain)
  79. {
  80. struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
  81. debug("%s(power_domain=%p)\n", __func__, power_domain);
  82. return ops->on(power_domain);
  83. }
  84. int power_domain_off(struct power_domain *power_domain)
  85. {
  86. struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
  87. debug("%s(power_domain=%p)\n", __func__, power_domain);
  88. return ops->off(power_domain);
  89. }
  90. #if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA))
  91. static int dev_power_domain_ctrl(struct udevice *dev, bool on)
  92. {
  93. struct power_domain pd;
  94. int i, count, ret = 0;
  95. count = dev_count_phandle_with_args(dev, "power-domains",
  96. "#power-domain-cells", 0);
  97. for (i = 0; i < count; i++) {
  98. ret = power_domain_get_by_index(dev, &pd, i);
  99. if (ret)
  100. return ret;
  101. if (on)
  102. ret = power_domain_on(&pd);
  103. else
  104. ret = power_domain_off(&pd);
  105. }
  106. /*
  107. * For platforms with parent and child power-domain devices
  108. * we may not run device_remove() on the power-domain parent
  109. * because it will result in removing its children and switching
  110. * off their power-domain parent. So we will get here again and
  111. * again and will be stuck in an endless loop.
  112. */
  113. if (!on && dev_get_parent(dev) == pd.dev &&
  114. device_get_uclass_id(dev) == UCLASS_POWER_DOMAIN)
  115. return ret;
  116. /*
  117. * power_domain_get() bound the device, thus
  118. * we must remove it again to prevent unbinding
  119. * active devices (which would result in unbind
  120. * error).
  121. */
  122. if (count > 0 && !on)
  123. device_remove(pd.dev, DM_REMOVE_NORMAL);
  124. return ret;
  125. }
  126. int dev_power_domain_on(struct udevice *dev)
  127. {
  128. return dev_power_domain_ctrl(dev, true);
  129. }
  130. int dev_power_domain_off(struct udevice *dev)
  131. {
  132. return dev_power_domain_ctrl(dev, false);
  133. }
  134. #endif
  135. UCLASS_DRIVER(power_domain) = {
  136. .id = UCLASS_POWER_DOMAIN,
  137. .name = "power_domain",
  138. };