common.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <errno.h>
  7. #include <libfdt.h>
  8. #include <common/debug.h>
  9. #include <common/fdt_wrappers.h>
  10. #include <drivers/allwinner/axp.h>
  11. int axp_check_id(void)
  12. {
  13. int ret;
  14. ret = axp_read(0x03);
  15. if (ret < 0)
  16. return ret;
  17. ret &= 0xcf;
  18. if (ret != axp_chip_id) {
  19. ERROR("PMIC: Found unknown PMIC %02x\n", ret);
  20. return ret;
  21. }
  22. return 0;
  23. }
  24. int axp_clrsetbits(uint8_t reg, uint8_t clr_mask, uint8_t set_mask)
  25. {
  26. uint8_t val;
  27. int ret;
  28. ret = axp_read(reg);
  29. if (ret < 0)
  30. return ret;
  31. val = (ret & ~clr_mask) | set_mask;
  32. return axp_write(reg, val);
  33. }
  34. void axp_power_off(void)
  35. {
  36. /* Set "power disable control" bit */
  37. axp_setbits(0x32, BIT(7));
  38. }
  39. #if SUNXI_SETUP_REGULATORS == 1
  40. /*
  41. * Retrieve the voltage from a given regulator DTB node.
  42. * Both the regulator-{min,max}-microvolt properties must be present and
  43. * have the same value. Return that value in millivolts.
  44. */
  45. static int fdt_get_regulator_millivolt(const void *fdt, int node)
  46. {
  47. const fdt32_t *prop;
  48. uint32_t min_volt;
  49. prop = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
  50. if (prop == NULL)
  51. return -EINVAL;
  52. min_volt = fdt32_to_cpu(*prop);
  53. prop = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
  54. if (prop == NULL)
  55. return -EINVAL;
  56. if (fdt32_to_cpu(*prop) != min_volt)
  57. return -EINVAL;
  58. return min_volt / 1000;
  59. }
  60. static int setup_regulator(const void *fdt, int node,
  61. const struct axp_regulator *reg)
  62. {
  63. uint8_t val;
  64. int mvolt;
  65. mvolt = fdt_get_regulator_millivolt(fdt, node);
  66. if (mvolt < reg->min_volt || mvolt > reg->max_volt)
  67. return -EINVAL;
  68. val = (mvolt / reg->step) - (reg->min_volt / reg->step);
  69. if (val > reg->split)
  70. val = ((val - reg->split) / 2) + reg->split;
  71. axp_write(reg->volt_reg, val);
  72. axp_setbits(reg->switch_reg, BIT(reg->switch_bit));
  73. INFO("PMIC: %s voltage: %d.%03dV\n", reg->dt_name,
  74. mvolt / 1000, mvolt % 1000);
  75. return 0;
  76. }
  77. static bool should_enable_regulator(const void *fdt, int node)
  78. {
  79. if (!fdt_node_is_enabled(fdt, node)) {
  80. return false;
  81. }
  82. if (fdt_getprop(fdt, node, "phandle", NULL) != NULL) {
  83. return true;
  84. }
  85. if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL) {
  86. return true;
  87. }
  88. return false;
  89. }
  90. static bool board_uses_usb0_host_mode(const void *fdt)
  91. {
  92. int node, length;
  93. const char *prop;
  94. node = fdt_node_offset_by_compatible(fdt, -1,
  95. "allwinner,sun8i-a33-musb");
  96. if (node < 0) {
  97. return false;
  98. }
  99. prop = fdt_getprop(fdt, node, "dr_mode", &length);
  100. if (!prop) {
  101. return false;
  102. }
  103. return !strncmp(prop, "host", length);
  104. }
  105. void axp_setup_regulators(const void *fdt)
  106. {
  107. int node;
  108. bool sw = false;
  109. if (fdt == NULL)
  110. return;
  111. /* locate the PMIC DT node, bail out if not found */
  112. node = fdt_node_offset_by_compatible(fdt, -1, axp_compatible);
  113. if (node < 0) {
  114. WARN("PMIC: No PMIC DT node, skipping setup\n");
  115. return;
  116. }
  117. /* This applies to AXP803 only. */
  118. if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL) &&
  119. board_uses_usb0_host_mode(fdt)) {
  120. axp_clrbits(0x8f, BIT(4));
  121. axp_setbits(0x30, BIT(2));
  122. INFO("PMIC: Enabling DRIVEVBUS\n");
  123. }
  124. /* descend into the "regulators" subnode */
  125. node = fdt_subnode_offset(fdt, node, "regulators");
  126. if (node < 0) {
  127. WARN("PMIC: No regulators DT node, skipping setup\n");
  128. return;
  129. }
  130. /* iterate over all regulators to find used ones */
  131. fdt_for_each_subnode(node, fdt, node) {
  132. const struct axp_regulator *reg;
  133. const char *name;
  134. int length;
  135. /* We only care if it's always on or referenced. */
  136. if (!should_enable_regulator(fdt, node))
  137. continue;
  138. name = fdt_get_name(fdt, node, &length);
  139. /* Enable the switch last to avoid overheating. */
  140. if (!strncmp(name, "dc1sw", length) ||
  141. !strncmp(name, "sw", length)) {
  142. sw = true;
  143. continue;
  144. }
  145. for (reg = axp_regulators; reg->dt_name; reg++) {
  146. if (!strncmp(name, reg->dt_name, length)) {
  147. setup_regulator(fdt, node, reg);
  148. break;
  149. }
  150. }
  151. }
  152. /*
  153. * On the AXP803, if DLDO2 is enabled after DC1SW, the PMIC overheats
  154. * and shuts down. So always enable DC1SW as the very last regulator.
  155. */
  156. if (sw) {
  157. INFO("PMIC: Enabling DC SW\n");
  158. if (axp_chip_id == AXP803_CHIP_ID)
  159. axp_setbits(0x12, BIT(7));
  160. if (axp_chip_id == AXP805_CHIP_ID)
  161. axp_setbits(0x11, BIT(7));
  162. }
  163. }
  164. #endif /* SUNXI_SETUP_REGULATORS */