Browse Source

Support Type-C Current as a fallback

Type-C Current is a mechanism defined in the USB Type-C spec for
indicating high-current modes at 5 V using nothing other than a voltage
on the CC line.  The FUSB302B maps the voltage to one of the four ranges
we care about, so it's easy to see if 1.5 A or 3 A is available at 5 V
even in systems that don't support PD.

Now, when the PD Buddy Sink is connected to a system without Power
Delivery support, after all attempts at PD communications fail, it falls
back to Type-C Current.  If the Sink is configured for 5 V, it will
monitor the CC line's voltage to see if enough Type-C Current is
available.  If so, the output is turned on.
Clara Hobbs 7 years ago
parent
commit
4f6578d609
6 changed files with 105 additions and 8 deletions
  1. 31
    0
      src/device_policy_manager.c
  2. 9
    1
      src/device_policy_manager.h
  3. 13
    0
      src/fusb302b.c
  4. 15
    0
      src/fusb302b.h
  5. 3
    0
      src/pd.h
  6. 34
    7
      src/policy_engine.c

+ 31
- 0
src/device_policy_manager.c View File

@@ -25,6 +25,7 @@
25 25
 #include "led.h"
26 26
 #include "storage.h"
27 27
 #include "pd.h"
28
+#include "fusb302b.h"
28 29
 
29 30
 
30 31
 /* Whether or not the power supply is unconstrained */
@@ -113,6 +114,36 @@ void pdb_dpm_get_sink_capability(union pd_msg *cap)
113 114
         | PD_POWERROLE_SINK | PD_NUMOBJ(numobj);
114 115
 }
115 116
 
117
+bool pdb_dpm_evaluate_typec_current(void)
118
+{
119
+    /* Get the current configuration */
120
+    struct pdb_config *cfg = pdb_config_flash_read();
121
+
122
+    /* If we have no configuration or don't want 5 V, Type-C Current can't
123
+     * possibly satisfy our needs */
124
+    if (cfg == NULL || cfg->v != 100) {
125
+        return false;
126
+    }
127
+
128
+    /* Get the present Type-C Current advertisement */
129
+    enum fusb_typec_current tcc = fusb_get_typec_current();
130
+
131
+    /* If 1.5 A is available and we want no more than that, great. */
132
+    if (tcc == OnePointFiveAmps && cfg->i <= 150) {
133
+        return true;
134
+    }
135
+    /* If 3 A is available and we want no more than that, that's great too. */
136
+    if (tcc == ThreePointZeroAmps && cfg->i <= 300) {
137
+        return true;
138
+    }
139
+    /* We're overly cautious if USB default current is available, since that
140
+     * could mean different things depending on the port we're connected to,
141
+     * and since we're really supposed to enumerate in order to request more
142
+     * than 100 mA.  This could be changed in the future. */
143
+
144
+    return false;
145
+}
146
+
116 147
 void pdb_dpm_pd_start(void)
117 148
 {
118 149
     chEvtSignal(pdb_led_thread, PDB_EVT_LED_FAST_BLINK);

+ 9
- 1
src/device_policy_manager.h View File

@@ -27,7 +27,7 @@
27 27
 /*
28 28
  * Create a Request message based on the given Source_Capabilities message.
29 29
  *
30
- * Returns false if sufficient power is not available, true if it is.
30
+ * Returns true if sufficient power is available, false otherwise.
31 31
  */
32 32
 bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg *request);
33 33
 
@@ -36,6 +36,14 @@ bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg
36 36
  */
37 37
 void pdb_dpm_get_sink_capability(union pd_msg *cap);
38 38
 
39
+/*
40
+ * Evaluate whether or not the currently offered Type-C Current can fulfill our
41
+ * power needs.
42
+ *
43
+ * Returns true if sufficient power is available, false otherwise.
44
+ */
45
+bool pdb_dpm_evaluate_typec_current(void);
46
+
39 47
 /*
40 48
  * Indicate that power negotiations are starting.
41 49
  */

+ 13
- 0
src/fusb302b.c View File

@@ -188,6 +188,19 @@ void fusb_get_status(union fusb_status *status)
188 188
     i2cReleaseBus(&I2CD2);
189 189
 }
190 190
 
191
+enum fusb_typec_current fusb_get_typec_current(void)
192
+{
193
+    i2cAcquireBus(&I2CD2);
194
+
195
+    /* Read the BC_LVL into a variable */
196
+    enum fusb_typec_current bc_lvl = fusb_read_byte(FUSB_STATUS0)
197
+        & FUSB_STATUS0_BC_LVL;
198
+
199
+    i2cReleaseBus(&I2CD2);
200
+
201
+    return bc_lvl;
202
+}
203
+
191 204
 void fusb_reset(void)
192 205
 {
193 206
     i2cAcquireBus(&I2CD2);

+ 15
- 0
src/fusb302b.h View File

@@ -251,6 +251,16 @@ union fusb_status {
251 251
     };
252 252
 };
253 253
 
254
+/*
255
+ * FUSB Type-C Current level enum
256
+ */
257
+enum fusb_typec_current {
258
+    None = 0,
259
+    Default = 1,
260
+    OnePointFiveAmps = 2,
261
+    ThreePointZeroAmps = 3
262
+};
263
+
254 264
 
255 265
 /* FUSB functions */
256 266
 
@@ -274,6 +284,11 @@ void fusb_send_hardrst(void);
274 284
  */
275 285
 void fusb_get_status(union fusb_status *status);
276 286
 
287
+/*
288
+ * Read the FUSB302B BC_LVL as an enum fusb_typec_current
289
+ */
290
+enum fusb_typec_current fusb_get_typec_current(void);
291
+
277 292
 /*
278 293
  * Initialization routine for the FUSB302B
279 294
  */

+ 3
- 0
src/pd.h View File

@@ -214,6 +214,9 @@
214 214
 #define PD_T_PS_TRANSITION MS2ST(500)
215 215
 #define PD_T_SENDER_RESPONSE MS2ST(27)
216 216
 #define PD_T_TYPEC_SINK_WAIT_CAP MS2ST(465)
217
+/* This is actually a Type-C time value, not a Power Delivery time value, but
218
+ * who cares? */
219
+#define PD_T_PD_DEBOUNCE MS2ST(15)
217 220
 
218 221
 
219 222
 /*

+ 34
- 7
src/policy_engine.c View File

@@ -44,7 +44,8 @@ enum policy_engine_state {
44 44
     PESinkTransitionDefault,
45 45
     PESinkSoftReset,
46 46
     PESinkSendSoftReset,
47
-    PESinkSendReject
47
+    PESinkSendReject,
48
+    PESinkSourceUnresponsive
48 49
 };
49 50
 
50 51
 /* The received message we're currently working with */
@@ -364,13 +365,10 @@ static enum policy_engine_state pe_sink_give_sink_cap(void)
364 365
 
365 366
 static enum policy_engine_state pe_sink_hard_reset(void)
366 367
 {
367
-    /* If we've already sent the maximum number of hard resets, give up */
368
+    /* If we've already sent the maximum number of hard resets, assume the
369
+     * source is unresponsive. */
368 370
     if (hard_reset_counter > PD_N_HARD_RESET_COUNT) {
369
-        pdb_dpm_output_off();
370
-        /* TODO: Fall back to Type-C Current if configured for 5 V. */
371
-        while (true) {
372
-            chThdSleepMilliseconds(1000);
373
-        }
371
+        return PESinkSourceUnresponsive;
374 372
     }
375 373
 
376 374
     /* Generate a hard reset signal */
@@ -503,6 +501,32 @@ static enum policy_engine_state pe_sink_send_reject(void)
503 501
     return PESinkReady;
504 502
 }
505 503
 
504
+/*
505
+ * When Power Delivery is unresponsive, fall back to Type-C Current
506
+ */
507
+static enum policy_engine_state pe_sink_source_unresponsive(void)
508
+{
509
+    static int old_tcc_match = -1;
510
+    int tcc_match = pdb_dpm_evaluate_typec_current();
511
+
512
+    /* If the last two readings are the same, set the output */
513
+    if (old_tcc_match == tcc_match) {
514
+        if (tcc_match) {
515
+            pdb_dpm_output_on();
516
+        } else {
517
+            pdb_dpm_output_off();
518
+        }
519
+    }
520
+
521
+    /* Remember whether or not the last measurement succeeded */
522
+    old_tcc_match = tcc_match;
523
+
524
+    /* Wait tPDDebounce between measurements */
525
+    chThdSleep(PD_T_PD_DEBOUNCE);
526
+
527
+    return PESinkSourceUnresponsive;
528
+}
529
+
506 530
 /*
507 531
  * Policy Engine state machine thread
508 532
  */
@@ -558,6 +582,9 @@ static THD_FUNCTION(PolicyEngine, arg) {
558 582
             case PESinkSendReject:
559 583
                 state = pe_sink_send_reject();
560 584
                 break;
585
+            case PESinkSourceUnresponsive:
586
+                state = pe_sink_source_unresponsive();
587
+                break;
561 588
             default:
562 589
                 /* This is an error.  It really shouldn't happen.  We might
563 590
                  * want to handle it anyway, though. */

Loading…
Cancel
Save