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
 #include "led.h"
25
 #include "led.h"
26
 #include "storage.h"
26
 #include "storage.h"
27
 #include "pd.h"
27
 #include "pd.h"
28
+#include "fusb302b.h"
28
 
29
 
29
 
30
 
30
 /* Whether or not the power supply is unconstrained */
31
 /* Whether or not the power supply is unconstrained */
113
         | PD_POWERROLE_SINK | PD_NUMOBJ(numobj);
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
 void pdb_dpm_pd_start(void)
147
 void pdb_dpm_pd_start(void)
117
 {
148
 {
118
     chEvtSignal(pdb_led_thread, PDB_EVT_LED_FAST_BLINK);
149
     chEvtSignal(pdb_led_thread, PDB_EVT_LED_FAST_BLINK);

+ 9
- 1
src/device_policy_manager.h View File

27
 /*
27
 /*
28
  * Create a Request message based on the given Source_Capabilities message.
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
 bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg *request);
32
 bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg *request);
33
 
33
 
36
  */
36
  */
37
 void pdb_dpm_get_sink_capability(union pd_msg *cap);
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
  * Indicate that power negotiations are starting.
48
  * Indicate that power negotiations are starting.
41
  */
49
  */

+ 13
- 0
src/fusb302b.c View File

188
     i2cReleaseBus(&I2CD2);
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
 void fusb_reset(void)
204
 void fusb_reset(void)
192
 {
205
 {
193
     i2cAcquireBus(&I2CD2);
206
     i2cAcquireBus(&I2CD2);

+ 15
- 0
src/fusb302b.h View File

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
 /* FUSB functions */
265
 /* FUSB functions */
256
 
266
 
274
  */
284
  */
275
 void fusb_get_status(union fusb_status *status);
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
  * Initialization routine for the FUSB302B
293
  * Initialization routine for the FUSB302B
279
  */
294
  */

+ 3
- 0
src/pd.h View File

214
 #define PD_T_PS_TRANSITION MS2ST(500)
214
 #define PD_T_PS_TRANSITION MS2ST(500)
215
 #define PD_T_SENDER_RESPONSE MS2ST(27)
215
 #define PD_T_SENDER_RESPONSE MS2ST(27)
216
 #define PD_T_TYPEC_SINK_WAIT_CAP MS2ST(465)
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
     PESinkTransitionDefault,
44
     PESinkTransitionDefault,
45
     PESinkSoftReset,
45
     PESinkSoftReset,
46
     PESinkSendSoftReset,
46
     PESinkSendSoftReset,
47
-    PESinkSendReject
47
+    PESinkSendReject,
48
+    PESinkSourceUnresponsive
48
 };
49
 };
49
 
50
 
50
 /* The received message we're currently working with */
51
 /* The received message we're currently working with */
364
 
365
 
365
 static enum policy_engine_state pe_sink_hard_reset(void)
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
     if (hard_reset_counter > PD_N_HARD_RESET_COUNT) {
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
     /* Generate a hard reset signal */
374
     /* Generate a hard reset signal */
503
     return PESinkReady;
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
  * Policy Engine state machine thread
531
  * Policy Engine state machine thread
508
  */
532
  */
558
             case PESinkSendReject:
582
             case PESinkSendReject:
559
                 state = pe_sink_send_reject();
583
                 state = pe_sink_send_reject();
560
                 break;
584
                 break;
585
+            case PESinkSourceUnresponsive:
586
+                state = pe_sink_source_unresponsive();
587
+                break;
561
             default:
588
             default:
562
                 /* This is an error.  It really shouldn't happen.  We might
589
                 /* This is an error.  It really shouldn't happen.  We might
563
                  * want to handle it anyway, though. */
590
                  * want to handle it anyway, though. */

Loading…
Cancel
Save