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
+ // Disable dead-battery signals
26
+ PWR -> CR3 |= PWR_CR3_UCPD_DBDIS ;
27
+ // Enable the clock for the UCPD1 peripheral
28
+ RCC -> APB1ENR2 |= RCC_APB1ENR2_UCPD1EN ;
29
+
30
+ // Copy the existing value
31
+ uint32_t CFG1 = UCPD1 -> CFG1 ;
32
+ // Force-disable UCPD1 before configuring
33
+ CFG1 &= ~UCPD_CFG1_UCPDEN ;
34
+ // Configure UCPD1
35
+ CFG1 = USBPD_UCPD1_CFG1 ;
36
+ // Apply the changes
37
+ UCPD1 -> CFG1 = CFG1 ;
38
+ // Enable UCPD1
39
+ UCPD1 -> CFG1 |= UCPD_CFG1_UCPDEN ;
40
+
41
+ // Copy the existing value
42
+ uint32_t CR = UCPD1 -> CR ;
43
+ // Clear out ANASUBMODE (irrelevant as a sink device)
44
+ CR &= ~UCPD_CR_ANASUBMODE_Msk ;
45
+ // Advertise our capabilities as a sink, with both CC lines enabled
46
+ CR |= UCPD_CR_ANAMODE | UCPD_CR_CCENABLE_Msk ;
47
+ // Apply the changes
48
+ UCPD1 -> CR = CR ;
49
+ }
50
+
51
+ // Gets the current state of the USBPD allowance
52
+ __attribute__((weak )) usbpd_allowance_t usbpd_get_allowance (void ) {
53
+ uint32_t CR = UCPD1 -> CR ;
54
+
55
+ int ucpd_enabled = (UCPD1 -> CFG1 & UCPD_CFG1_UCPDEN_Msk ) >> UCPD_CFG1_UCPDEN_Pos ;
56
+ int anamode = (CR & UCPD_CR_ANAMODE_Msk ) >> UCPD_CR_ANAMODE_Pos ;
57
+ int cc_enabled = (CR & UCPD_CR_CCENABLE_Msk ) >> UCPD_CR_CCENABLE_Pos ;
58
+
59
+ if (ucpd_enabled && anamode && cc_enabled ) {
60
+ uint32_t SR = UCPD1 -> SR ;
61
+ int vstate_cc1 = (SR & UCPD_SR_TYPEC_VSTATE_CC1_Msk ) >> UCPD_SR_TYPEC_VSTATE_CC1_Pos ;
62
+ int vstate_cc2 = (SR & UCPD_SR_TYPEC_VSTATE_CC2_Msk ) >> UCPD_SR_TYPEC_VSTATE_CC2_Pos ;
63
+ int vstate_max = vstate_cc1 > vstate_cc2 ? vstate_cc1 : vstate_cc2 ;
64
+ switch (vstate_max ) {
65
+ case 0 :
66
+ case 1 :
67
+ 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.
68
+ case 2 :
69
+ return USBPD_1500MA ;
70
+ case 3 :
71
+ return USBPD_3000MA ;
72
+ }
73
+ }
74
+
75
+ return USBPD_500MA ;
76
+ }
0 commit comments