usbpd_stm32g4.c (3033B)
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 17 #include <quantum.h> 18 19 #ifndef USBPD_UCPD1_CFG1 20 # define USBPD_UCPD1_CFG1 (UCPD_CFG1_PSC_UCPDCLK_0 | UCPD_CFG1_TRANSWIN_3 | UCPD_CFG1_IFRGAP_4 | UCPD_CFG1_HBITCLKDIV_4) 21 #endif // USBPD_UCPD1_CFG1 22 23 // Initialises the USBPD subsystem 24 __attribute__((weak)) void usbpd_init(void) { 25 // Enable the clock for the UCPD1 peripheral 26 RCC->APB1ENR2 |= RCC_APB1ENR2_UCPD1EN; 27 28 // Copy the existing value 29 uint32_t CFG1 = UCPD1->CFG1; 30 // Force-disable UCPD1 before configuring 31 CFG1 &= ~UCPD_CFG1_UCPDEN; 32 // Configure UCPD1 33 CFG1 = USBPD_UCPD1_CFG1; 34 // Apply the changes 35 UCPD1->CFG1 = CFG1; 36 // Enable UCPD1 37 UCPD1->CFG1 |= UCPD_CFG1_UCPDEN; 38 39 // Copy the existing value 40 uint32_t CR = UCPD1->CR; 41 // Clear out ANASUBMODE (irrelevant as a sink device) 42 CR &= ~UCPD_CR_ANASUBMODE_Msk; 43 // Advertise our capabilities as a sink, with both CC lines enabled 44 CR |= UCPD_CR_ANAMODE | UCPD_CR_CCENABLE_Msk; 45 // Apply the changes 46 UCPD1->CR = CR; 47 48 // Disable dead-battery signals only after UCPD1 is configured to ensure 49 // that the transition does not go through any intermediate state without 50 // any pull-down resistance. 51 PWR->CR3 |= PWR_CR3_UCPD_DBDIS; 52 } 53 54 // Gets the current state of the USBPD allowance 55 __attribute__((weak)) usbpd_allowance_t usbpd_get_allowance(void) { 56 uint32_t CR = UCPD1->CR; 57 58 int ucpd_enabled = (UCPD1->CFG1 & UCPD_CFG1_UCPDEN_Msk) >> UCPD_CFG1_UCPDEN_Pos; 59 int anamode = (CR & UCPD_CR_ANAMODE_Msk) >> UCPD_CR_ANAMODE_Pos; 60 int cc_enabled = (CR & UCPD_CR_CCENABLE_Msk) >> UCPD_CR_CCENABLE_Pos; 61 62 if (ucpd_enabled && anamode && cc_enabled) { 63 uint32_t SR = UCPD1->SR; 64 int vstate_cc1 = (SR & UCPD_SR_TYPEC_VSTATE_CC1_Msk) >> UCPD_SR_TYPEC_VSTATE_CC1_Pos; 65 int vstate_cc2 = (SR & UCPD_SR_TYPEC_VSTATE_CC2_Msk) >> UCPD_SR_TYPEC_VSTATE_CC2_Pos; 66 int vstate_max = vstate_cc1 > vstate_cc2 ? vstate_cc1 : vstate_cc2; 67 switch (vstate_max) { 68 case 0: 69 case 1: 70 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. 71 case 2: 72 return USBPD_1500MA; 73 case 3: 74 return USBPD_3000MA; 75 } 76 } 77 78 return USBPD_500MA; 79 }