mtk-regulator-coupler.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Voltage regulators coupler for MediaTek SoCs
  4. *
  5. * Copyright (C) 2022 Collabora, Ltd.
  6. * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
  7. */
  8. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/of.h>
  12. #include <linux/regulator/coupler.h>
  13. #include <linux/regulator/driver.h>
  14. #include <linux/regulator/machine.h>
  15. #include <linux/suspend.h>
  16. #define to_mediatek_coupler(x) container_of(x, struct mediatek_regulator_coupler, coupler)
  17. struct mediatek_regulator_coupler {
  18. struct regulator_coupler coupler;
  19. struct regulator_dev *vsram_rdev;
  20. };
  21. /*
  22. * We currently support only couples of not more than two vregs and
  23. * modify the vsram voltage only when changing voltage of vgpu.
  24. *
  25. * This function is limited to the GPU<->SRAM voltages relationships.
  26. */
  27. static int mediatek_regulator_balance_voltage(struct regulator_coupler *coupler,
  28. struct regulator_dev *rdev,
  29. suspend_state_t state)
  30. {
  31. struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
  32. int max_spread = rdev->constraints->max_spread[0];
  33. int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;
  34. int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;
  35. int vsram_target_min_uV, vsram_target_max_uV;
  36. int min_uV = 0;
  37. int max_uV = INT_MAX;
  38. int ret;
  39. /*
  40. * If the target device is on, setting the SRAM voltage directly
  41. * is not supported as it scales through its coupled supply voltage.
  42. *
  43. * An exception is made in case the use_count is zero: this means
  44. * that this is the first time we power up the SRAM regulator, which
  45. * implies that the target device has yet to perform initialization
  46. * and setting a voltage at that time is harmless.
  47. */
  48. if (rdev == mrc->vsram_rdev) {
  49. if (rdev->use_count == 0)
  50. return regulator_do_balance_voltage(rdev, state, true);
  51. return -EPERM;
  52. }
  53. ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
  54. if (ret < 0)
  55. return ret;
  56. if (min_uV == 0) {
  57. ret = regulator_get_voltage_rdev(rdev);
  58. if (ret < 0)
  59. return ret;
  60. min_uV = ret;
  61. }
  62. ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
  63. if (ret < 0)
  64. return ret;
  65. /*
  66. * If we're asked to set a voltage less than VSRAM min_uV, set
  67. * the minimum allowed voltage on VSRAM, as in this case it is
  68. * safe to ignore the max_spread parameter.
  69. */
  70. vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);
  71. vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);
  72. /* Make sure we're not out of range */
  73. vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);
  74. pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",
  75. vsram_target_min_uV, vsram_target_max_uV,
  76. rdev_get_name(mrc->vsram_rdev), min_uV);
  77. ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,
  78. vsram_target_max_uV, state);
  79. if (ret)
  80. return ret;
  81. /* The sram voltage is now balanced: update the target vreg voltage */
  82. return regulator_do_balance_voltage(rdev, state, true);
  83. }
  84. static int mediatek_regulator_attach(struct regulator_coupler *coupler,
  85. struct regulator_dev *rdev)
  86. {
  87. struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
  88. const char *rdev_name = rdev_get_name(rdev);
  89. /*
  90. * If we're getting a coupling of more than two regulators here and
  91. * this means that this is surely not a GPU<->SRAM couple: in that
  92. * case, we may want to use another coupler implementation, if any,
  93. * or the generic one: the regulator core will keep walking through
  94. * the list of couplers when any .attach_regulator() cb returns 1.
  95. */
  96. if (rdev->coupling_desc.n_coupled > 2)
  97. return 1;
  98. if (strstr(rdev_name, "sram")) {
  99. if (mrc->vsram_rdev)
  100. return -EINVAL;
  101. mrc->vsram_rdev = rdev;
  102. } else if (!strstr(rdev_name, "vgpu") && !strstr(rdev_name, "Vgpu")) {
  103. return 1;
  104. }
  105. return 0;
  106. }
  107. static int mediatek_regulator_detach(struct regulator_coupler *coupler,
  108. struct regulator_dev *rdev)
  109. {
  110. struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
  111. if (rdev == mrc->vsram_rdev)
  112. mrc->vsram_rdev = NULL;
  113. return 0;
  114. }
  115. static struct mediatek_regulator_coupler mediatek_coupler = {
  116. .coupler = {
  117. .attach_regulator = mediatek_regulator_attach,
  118. .detach_regulator = mediatek_regulator_detach,
  119. .balance_voltage = mediatek_regulator_balance_voltage,
  120. },
  121. };
  122. static int mediatek_regulator_coupler_init(void)
  123. {
  124. if (!of_machine_is_compatible("mediatek,mt8183") &&
  125. !of_machine_is_compatible("mediatek,mt8186") &&
  126. !of_machine_is_compatible("mediatek,mt8192"))
  127. return 0;
  128. return regulator_coupler_register(&mediatek_coupler.coupler);
  129. }
  130. arch_initcall(mediatek_regulator_coupler_init);
  131. MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
  132. MODULE_DESCRIPTION("MediaTek Regulator Coupler driver");
  133. MODULE_LICENSE("GPL");