axp209.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2012
  4. * Henrik Nordstrom <henrik@henriknordstrom.net>
  5. */
  6. #include <common.h>
  7. #include <command.h>
  8. #include <asm/arch/pmic_bus.h>
  9. #include <axp_pmic.h>
  10. #ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_08
  11. # define AXP209_VRC_SLOPE AXP209_VRC_LDO3_800uV_uS
  12. #endif
  13. #ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_16
  14. # define AXP209_VRC_SLOPE AXP209_VRC_LDO3_1600uV_uS
  15. #endif
  16. #if defined CONFIG_AXP_ALDO3_VOLT_SLOPE_NONE || !defined AXP209_VRC_SLOPE
  17. # define AXP209_VRC_SLOPE 0x00
  18. #endif
  19. static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
  20. {
  21. if (mvolt < min)
  22. mvolt = min;
  23. else if (mvolt > max)
  24. mvolt = max;
  25. return (mvolt - min) / div;
  26. }
  27. int axp_set_dcdc2(unsigned int mvolt)
  28. {
  29. int rc;
  30. u8 cfg, current;
  31. if (mvolt == 0)
  32. return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
  33. AXP209_OUTPUT_CTRL_DCDC2);
  34. rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
  35. if (rc)
  36. return rc;
  37. cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
  38. /* Do we really need to be this gentle? It has built-in voltage slope */
  39. while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
  40. current != cfg) {
  41. if (current < cfg)
  42. current++;
  43. else
  44. current--;
  45. rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
  46. if (rc)
  47. break;
  48. }
  49. return rc;
  50. }
  51. int axp_set_dcdc3(unsigned int mvolt)
  52. {
  53. u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
  54. int rc;
  55. if (mvolt == 0)
  56. return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
  57. AXP209_OUTPUT_CTRL_DCDC3);
  58. rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
  59. if (rc)
  60. return rc;
  61. return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
  62. }
  63. int axp_set_aldo2(unsigned int mvolt)
  64. {
  65. int rc;
  66. u8 cfg, reg;
  67. if (mvolt == 0)
  68. return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
  69. AXP209_OUTPUT_CTRL_LDO2);
  70. cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
  71. rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
  72. if (rc)
  73. return rc;
  74. reg |= AXP209_LDO24_LDO2_SET(reg, cfg);
  75. rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
  76. if (rc)
  77. return rc;
  78. return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
  79. }
  80. int axp_set_aldo3(unsigned int mvolt)
  81. {
  82. u8 cfg;
  83. int rc;
  84. if (mvolt == 0)
  85. return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
  86. AXP209_OUTPUT_CTRL_LDO3);
  87. /*
  88. * Some boards have trouble reaching the target voltage without causing
  89. * great inrush currents. To prevent this, boards can enable a certain
  90. * slope to ramp up voltage. Note, this only works when changing an
  91. * already active power rail. When toggling power on, the AXP ramps up
  92. * steeply at 0.0167 V/uS.
  93. */
  94. rc = pmic_bus_read(AXP209_VRC_DCDC2_LDO3, &cfg);
  95. cfg = AXP209_VRC_LDO3_SLOPE_SET(cfg, AXP209_VRC_SLOPE);
  96. rc |= pmic_bus_write(AXP209_VRC_DCDC2_LDO3, cfg);
  97. if (rc)
  98. return rc;
  99. #ifdef CONFIG_AXP_ALDO3_INRUSH_QUIRK
  100. /*
  101. * On some boards, LDO3 has a too big capacitor installed. When
  102. * turning on LDO3, this causes the AXP209 to shutdown on
  103. * voltages over 1.9 volt. As a workaround, we enable LDO3
  104. * first with the lowest possible voltage. If this still causes
  105. * high inrush currents, the voltage slope should be increased.
  106. */
  107. rc = pmic_bus_read(AXP209_OUTPUT_CTRL, &cfg);
  108. if (rc)
  109. return rc;
  110. if (!(cfg & AXP209_OUTPUT_CTRL_LDO3)) {
  111. rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, 0x0); /* 0.7 Volt */
  112. mdelay(1);
  113. rc |= pmic_bus_setbits(AXP209_OUTPUT_CTRL,
  114. AXP209_OUTPUT_CTRL_LDO3);
  115. if (rc)
  116. return rc;
  117. }
  118. #endif
  119. if (mvolt == -1) {
  120. cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN;
  121. } else {
  122. cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
  123. cfg = AXP209_LDO3_VOLTAGE_SET(cfg);
  124. }
  125. rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
  126. if (rc)
  127. return rc;
  128. return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
  129. }
  130. int axp_set_aldo4(unsigned int mvolt)
  131. {
  132. int rc;
  133. static const unsigned int vindex[] = {
  134. 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
  135. 2700, 2800, 3000, 3100, 3200, 3300
  136. };
  137. u8 cfg, reg;
  138. if (mvolt == 0)
  139. return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
  140. AXP209_OUTPUT_CTRL_LDO4);
  141. /* Translate mvolt to register cfg value, requested <= selected */
  142. for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
  143. rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
  144. if (rc)
  145. return rc;
  146. reg |= AXP209_LDO24_LDO4_SET(reg, cfg);
  147. rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
  148. if (rc)
  149. return rc;
  150. return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
  151. }
  152. int axp_init(void)
  153. {
  154. u8 ver;
  155. int i, rc;
  156. rc = pmic_bus_init();
  157. if (rc)
  158. return rc;
  159. rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
  160. if (rc)
  161. return rc;
  162. if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1)
  163. return -EINVAL;
  164. /* Mask all interrupts */
  165. for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
  166. rc = pmic_bus_write(i, 0);
  167. if (rc)
  168. return rc;
  169. }
  170. /*
  171. * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
  172. * from android these are sometimes on.
  173. */
  174. rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
  175. if (rc)
  176. return rc;
  177. rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
  178. if (rc)
  179. return rc;
  180. rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
  181. if (rc)
  182. return rc;
  183. return 0;
  184. }
  185. int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  186. {
  187. pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
  188. /* infinite loop during shutdown */
  189. while (1) {}
  190. /* not reached */
  191. return 0;
  192. }