You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.8 KiB

  1. /* Copyright 2021 Nick Brassel (@tzarc)
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <quantum.h>
  17. #ifndef USBPD_UCPD1_CFG1
  18. # define USBPD_UCPD1_CFG1 (UCPD_CFG1_PSC_UCPDCLK_0 | UCPD_CFG1_TRANSWIN_3 | UCPD_CFG1_IFRGAP_4 | UCPD_CFG1_HBITCLKDIV_4)
  19. #endif // USBPD_UCPD1_CFG1
  20. // Initialises the USBPD subsystem
  21. __attribute__((weak)) void usbpd_init(void) {
  22. // Disable dead-battery signals
  23. PWR->CR3 |= PWR_CR3_UCPD_DBDIS;
  24. // Enable the clock for the UCPD1 peripheral
  25. RCC->APB1ENR2 |= RCC_APB1ENR2_UCPD1EN;
  26. // Copy the existing value
  27. uint32_t CFG1 = UCPD1->CFG1;
  28. // Force-disable UCPD1 before configuring
  29. CFG1 &= ~UCPD_CFG1_UCPDEN;
  30. // Configure UCPD1
  31. CFG1 = USBPD_UCPD1_CFG1;
  32. // Apply the changes
  33. UCPD1->CFG1 = CFG1;
  34. // Enable UCPD1
  35. UCPD1->CFG1 |= UCPD_CFG1_UCPDEN;
  36. // Copy the existing value
  37. uint32_t CR = UCPD1->CR;
  38. // Clear out ANASUBMODE (irrelevant as a sink device)
  39. CR &= ~UCPD_CR_ANASUBMODE_Msk;
  40. // Advertise our capabilities as a sink, with both CC lines enabled
  41. CR |= UCPD_CR_ANAMODE | UCPD_CR_CCENABLE_Msk;
  42. // Apply the changes
  43. UCPD1->CR = CR;
  44. }
  45. // Gets the current state of the USBPD allowance
  46. __attribute__((weak)) usbpd_allowance_t usbpd_get_allowance(void) {
  47. uint32_t CR = UCPD1->CR;
  48. int ucpd_enabled = (UCPD1->CFG1 & UCPD_CFG1_UCPDEN_Msk) >> UCPD_CFG1_UCPDEN_Pos;
  49. int anamode = (CR & UCPD_CR_ANAMODE_Msk) >> UCPD_CR_ANAMODE_Pos;
  50. int cc_enabled = (CR & UCPD_CR_CCENABLE_Msk) >> UCPD_CR_CCENABLE_Pos;
  51. if (ucpd_enabled && anamode && cc_enabled) {
  52. uint32_t SR = UCPD1->SR;
  53. int vstate_cc1 = (SR & UCPD_SR_TYPEC_VSTATE_CC1_Msk) >> UCPD_SR_TYPEC_VSTATE_CC1_Pos;
  54. int vstate_cc2 = (SR & UCPD_SR_TYPEC_VSTATE_CC2_Msk) >> UCPD_SR_TYPEC_VSTATE_CC2_Pos;
  55. int vstate_max = vstate_cc1 > vstate_cc2 ? vstate_cc1 : vstate_cc2;
  56. switch (vstate_max) {
  57. case 0:
  58. case 1:
  59. return USBPD_500MA; // Note that this is 500mA (i.e. max USB 2.0), not 900mA, as we're not using USB 3.1 as a sink device.
  60. case 2:
  61. return USBPD_1500MA;
  62. case 3:
  63. return USBPD_3000MA;
  64. }
  65. }
  66. return USBPD_500MA;
  67. }