diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2014-11-13 20:51:00 -0800 |
---|---|---|
committer | Alec Berg <alecaberg@chromium.org> | 2015-01-10 23:45:31 +0000 |
commit | 4cbb3941b188beaf04ffaa2473e65e352aee6254 (patch) | |
tree | 1b536186cf7ad32048bf7fdfda73800d6a55b480 /board/zinger/usb_pd_policy.c | |
parent | cf8f65d34af0aff42e66bd395a74adf2874bd200 (diff) | |
download | chrome-ec-4cbb3941b188beaf04ffaa2473e65e352aee6254.tar.gz |
zinger: do an intermediate step when discharging from 20V to 5Vstabilize-storm-6683.B
If we discharge directly the output voltage from 20V to 5V under load,
an undershot happens and we dip below the 5V UVP threshold.
So when doing a down voltage transition from 20V to 5V, split it into 2
steps : a 20V->12V transition then once we are reached 12V, a 12V->5V
transition.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=samus
BUG=chrome-os-partner:33794
TEST=connect Zinger to a Firefly and an electronic load.
Using Firefly, ask for 20V->5V, 12V->5V and 20V->12V
transitions, check the VBUS waveforms on the scope.
Change-Id: Ie1e091ae6f1fee1fb7d4e3bd72edbe7491acd5ea
Reviewed-on: https://chromium-review.googlesource.com/229732
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Commit-Queue: Alec Berg <alecaberg@chromium.org>
Tested-by: Alec Berg <alecaberg@chromium.org>
Diffstat (limited to 'board/zinger/usb_pd_policy.c')
-rw-r--r-- | board/zinger/usb_pd_policy.c | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c index 9559ec92b8..50661a1c57 100644 --- a/board/zinger/usb_pd_policy.c +++ b/board/zinger/usb_pd_policy.c @@ -152,13 +152,23 @@ static void discharge_voltage(int target_volt) #define PDO_FIXED_FLAGS (PDO_FIXED_EXTERNAL | PDO_FIXED_DATA_SWAP) +/* Voltage indexes for the PDOs */ +enum volt_idx { + PDO_IDX_5V = 0, + PDO_IDX_12V = 1, + PDO_IDX_20V = 2, + + PDO_IDX_COUNT +}; + /* Power Delivery Objects */ const uint32_t pd_src_pdo[] = { - PDO_FIXED(5000, RATED_CURRENT, PDO_FIXED_FLAGS), - PDO_FIXED(12000, RATED_CURRENT, PDO_FIXED_FLAGS), - PDO_FIXED(20000, RATED_CURRENT, PDO_FIXED_FLAGS), + [PDO_IDX_5V] = PDO_FIXED(5000, RATED_CURRENT, PDO_FIXED_FLAGS), + [PDO_IDX_12V] = PDO_FIXED(12000, RATED_CURRENT, PDO_FIXED_FLAGS), + [PDO_IDX_20V] = PDO_FIXED(20000, RATED_CURRENT, PDO_FIXED_FLAGS), }; const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo); +BUILD_ASSERT(ARRAY_SIZE(pd_src_pdo) == PDO_IDX_COUNT); /* PDO voltages (should match the table above) */ static const struct { @@ -167,14 +177,19 @@ static const struct { int ovp; /* over-voltage limit in mV */ int ovp_rec;/* over-voltage recovery threshold in mV */ } voltages[ARRAY_SIZE(pd_src_pdo)] = { - {VO_5V, UVP_MV(5000), OVP_MV(5000), OVP_REC_MV(5000)}, - {VO_12V, UVP_MV(12000), OVP_MV(12000), OVP_REC_MV(12000)}, - {VO_20V, UVP_MV(20000), OVP_MV(20000), OVP_REC_MV(20000)}, + [PDO_IDX_5V] = {VO_5V, UVP_MV(5000), OVP_MV(5000), + OVP_REC_MV(5000)}, + [PDO_IDX_12V] = {VO_12V, UVP_MV(12000), OVP_MV(12000), + OVP_REC_MV(12000)}, + [PDO_IDX_20V] = {VO_20V, UVP_MV(20000), OVP_MV(20000), + OVP_REC_MV(20000)}, }; /* current and previous selected PDO entry */ static int volt_idx; static int last_volt_idx; +/* target voltage at the end of discharge */ +static int discharge_volt_idx; /* output current measurement */ int vbus_amp; @@ -211,12 +226,18 @@ int pd_check_requested_voltage(uint32_t rdo) void pd_transition_voltage(int idx) { - if (idx - 1 < volt_idx) { /* down voltage transition */ + last_volt_idx = volt_idx; + volt_idx = idx - 1; + if (volt_idx < last_volt_idx) { /* down voltage transition */ /* Stop OCP monitoring */ adc_disable_watchdog(); - discharge_voltage(voltages[idx - 1].ovp); - } else if (idx - 1 > volt_idx) { /* up voltage transition */ + discharge_volt_idx = volt_idx; + /* from 20V : do an intermediate step at 12V */ + if (volt_idx == PDO_IDX_5V && last_volt_idx == PDO_IDX_20V) + volt_idx = PDO_IDX_12V; + discharge_voltage(voltages[volt_idx].ovp); + } else if (volt_idx > last_volt_idx) { /* up voltage transition */ if (discharge_is_enabled()) { /* Make sure discharging is disabled */ discharge_disable(); @@ -225,8 +246,6 @@ void pd_transition_voltage(int idx) MAX_CURRENT_FAST, 0); } } - last_volt_idx = volt_idx; - volt_idx = idx - 1; set_output_voltage(voltages[volt_idx].select); } @@ -248,16 +267,21 @@ void pd_power_supply_reset(int port) int need_discharge = (volt_idx > 0) || discharge_is_enabled(); output_disable(); - volt_idx = 0; - set_output_voltage(VO_5V); + last_volt_idx = volt_idx; + /* from 20V : do an intermediate step at 12V */ + volt_idx = volt_idx == PDO_IDX_20V ? PDO_IDX_12V : PDO_IDX_5V; + set_output_voltage(voltages[volt_idx].select); /* TODO transition delay */ /* Stop OCP monitoring to save power */ adc_disable_watchdog(); /* discharge voltage to 5V ? */ - if (need_discharge) - discharge_voltage(voltages[0].ovp); + if (need_discharge) { + /* final target : 5V */ + discharge_volt_idx = PDO_IDX_5V; + discharge_voltage(voltages[volt_idx].ovp); + } } int pd_check_data_swap(int port, int data_role) @@ -371,6 +395,9 @@ int pd_board_checks(void) /* the discharge did not work properly */ if (discharge_is_enabled() && (get_time().val > discharge_deadline.val)) { + /* ensure we always finish a 2-step discharge */ + volt_idx = discharge_volt_idx; + set_output_voltage(voltages[volt_idx].select); /* stop it */ discharge_disable(); /* enable over-current monitoring */ @@ -402,10 +429,18 @@ void pd_adc_interrupt(void) /* Clear flags */ STM32_ADC_ISR = 0x8e; - if (discharge_is_enabled()) { /* discharge completed */ - discharge_disable(); - /* enable over-current monitoring */ - adc_enable_watchdog(ADC_CH_A_SENSE, MAX_CURRENT_FAST, 0); + if (discharge_is_enabled()) { + if (discharge_volt_idx != volt_idx) { + /* first step of the discharge completed: now 12V->5V */ + volt_idx = PDO_IDX_5V; + set_output_voltage(VO_5V); + discharge_voltage(voltages[PDO_IDX_5V].ovp); + } else { /* discharge complete */ + discharge_disable(); + /* enable over-current monitoring */ + adc_enable_watchdog(ADC_CH_A_SENSE, + MAX_CURRENT_FAST, 0); + } } else {/* Over-current detection */ /* cut the power output */ pd_power_supply_reset(0); |