diff options
author | Alec Berg <alecaberg@chromium.org> | 2015-07-17 17:41:54 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-07-22 18:04:29 +0000 |
commit | 0115834bb637f95c7bb0d9d882a09dd1c4349d15 (patch) | |
tree | 060aa843b5b171eed6fb254d66fd41aeb792d56d /board | |
parent | 2f4a59037990891570af032f7ce41397b499347a (diff) | |
download | chrome-ec-0115834bb637f95c7bb0d9d882a09dd1c4349d15.tar.gz |
plankton: allow use of double CC cable
Add ability for Plankton to detect whether a single or double
CC cable is used to connect to DUT. This is done by toggling
the active CC line until a connection is detected, then toggling
once more and checking if we still have a connection. If we
can connect to the DUT in both CC polarities, then it is a
double CC cable. Before we know the cable type, keep PD
communication disabled to avoid partially negotiating and then
disconnecting. Note, this increases the time it takes for
us to connect a form a stable PD contract with the DUT.
When we detect a double CC cable, the cable flip button actually
flips the active CC polarity, thus testing all pins in the
opposite polarity.
BUG=chrome-os-partner:42569
BRANCH=smaug
TEST=test with plankton and samus. test that we form a PD
contract with both single and double CC cables as both sink
and source. also test the cable flip button for both cables.
Change-Id: I522369302848d4cdbb70c55a40af3ad0b7c3fb8a
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/286589
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'board')
-rw-r--r-- | board/plankton/board.c | 288 | ||||
-rw-r--r-- | board/plankton/board.h | 13 | ||||
-rw-r--r-- | board/plankton/usb_pd_config.h | 8 |
3 files changed, 204 insertions, 105 deletions
diff --git a/board/plankton/board.c b/board/plankton/board.c index 64f23549ec..d8b8dcd56c 100644 --- a/board/plankton/board.c +++ b/board/plankton/board.c @@ -29,6 +29,18 @@ static volatile uint64_t hpd_prev_ts; static volatile int hpd_prev_level; static volatile int hpd_possible_irq; +/* Detect the type of cable used (either single CC or double) */ +enum typec_cable { + TYPEC_CABLE_NONE, + TYPEC_CABLE_CHECK, + TYPEC_CABLE_SINGLE_CC, + TYPEC_CABLE_DOUBLE_CC +}; +static enum typec_cable cable; + +static int active_cc; +static int host_mode; + static int sn75dp130_dpcd_init(void); /** @@ -101,7 +113,7 @@ static enum gpio_signal button_pressed; static int fake_pd_disconnected; static int fake_pd_host_mode; -static int fake_pd_disconnect_duration_ms; +static int fake_pd_disconnect_duration_us; enum usbc_action { USBC_ACT_5V_TO_DUT, @@ -126,6 +138,109 @@ enum board_src_cap src_cap_mapping[USBC_ACT_COUNT] = [USBC_ACT_20V_TO_DUT] = SRC_CAP_20V, }; +/** + * Set the active CC line. The non-active CC line will be left in + * High-Z, and we will fake the ADC reading for it. + */ +static void set_active_cc(int cc) +{ + active_cc = cc; + + /* High Z for no pull-up or pull-down resistor on CC1 */ + gpio_set_flags_by_mask(GPIO_A, (1 << 2) | (1 << 9), GPIO_INPUT); + /* High Z for no pull-up or pull-down resistor on CC2 */ + gpio_set_flags_by_mask(GPIO_B, (1 << 6) | (1 << 7), GPIO_INPUT); + + if (cc) { + if (host_mode) + /* Pull-up on CC2 */ + gpio_set_flags_by_mask(GPIO_B, (1 << 6), GPIO_OUT_HIGH); + else + /* Pull-down on CC2 */ + gpio_set_flags_by_mask(GPIO_B, (1 << 7), GPIO_OUT_LOW); + } else { + if (host_mode) + /* Pull-up on CC1 */ + gpio_set_flags_by_mask(GPIO_A, (1 << 2), GPIO_OUT_HIGH); + else + /* Pull-down on CC1 */ + gpio_set_flags_by_mask(GPIO_A, (1 << 9), GPIO_OUT_LOW); + } +} + +/** + * Detect type-C cable type. Toggle the active CC line until a type-C connection + * is detected. If a type-C connection can be made in both polarities, then we + * have a double CC cable, otherwise we have a single CC cable. + */ +static void detect_cc_cable(void) +{ + /* + * Delay long enough to guarantee a type-C disconnect will be seen and + * a new connection will be made made. + */ + hook_call_deferred(detect_cc_cable, PD_T_CC_DEBOUNCE + PD_T_SAFE_0V); + + switch (cable) { + case TYPEC_CABLE_NONE: + /* When no cable attached, toggle active CC line */ + if (pd_is_connected(0)) + cable = TYPEC_CABLE_CHECK; + set_active_cc(!active_cc); + break; + case TYPEC_CABLE_CHECK: + /* If we still have a connection, we have a double CC cable */ + cable = pd_is_connected(0) ? TYPEC_CABLE_DOUBLE_CC : + TYPEC_CABLE_SINGLE_CC; + /* Flip back to original polarity and enable PD comms */ + set_active_cc(!active_cc); + pd_comm_enable(1); + break; + case TYPEC_CABLE_SINGLE_CC: + case TYPEC_CABLE_DOUBLE_CC: + /* Check for disconnection and disable PD comms */ + if (!pd_is_connected(0)) { + cable = TYPEC_CABLE_NONE; + pd_comm_enable(0); + } + break; + } +} +DECLARE_DEFERRED(detect_cc_cable); + +static void fake_disconnect_end(void) +{ + fake_pd_disconnected = 0; + board_pd_set_host_mode(fake_pd_host_mode); + + /* Restart CC cable detection */ + hook_call_deferred(detect_cc_cable, 500*MSEC); +} +DECLARE_DEFERRED(fake_disconnect_end); + +static void fake_disconnect_start(void) +{ + /* Cancel detection of CC cable */ + hook_call_deferred(detect_cc_cable, -1); + + /* Record the current host mode */ + fake_pd_host_mode = !gpio_get_level(GPIO_USBC_CHARGE_EN); + /* Disable VBUS */ + gpio_set_level(GPIO_VBUS_CHARGER_EN, 0); + gpio_set_level(GPIO_USBC_VSEL_0, 0); + gpio_set_level(GPIO_USBC_VSEL_1, 0); + /* High Z for no pull-up or pull-down resistor on CC1 */ + gpio_set_flags_by_mask(GPIO_A, (1 << 2) | (1 << 9), GPIO_INPUT); + /* High Z for no pull-up or pull-down resistor on CC2 */ + gpio_set_flags_by_mask(GPIO_B, (1 << 6) | (1 << 7), GPIO_INPUT); + + fake_pd_disconnected = 1; + + hook_call_deferred(fake_disconnect_end, + fake_pd_disconnect_duration_us); +} +DECLARE_DEFERRED(fake_disconnect_start); + static void set_usbc_action(enum usbc_action act) { int need_soft_reset; @@ -168,9 +283,26 @@ static void set_usbc_action(enum usbc_action act) gpio_set_level(GPIO_USBC_SS_USB_MODE, 0); break; case USBC_ACT_MUX_FLIP: - pd_send_vdm(0, USB_VID_GOOGLE, VDO_CMD_FLIP, NULL, 0); - gpio_set_level(GPIO_USBC_POLARITY, - !gpio_get_level(GPIO_USBC_POLARITY)); + /* + * For a single CC cable, send custom VDM to flip + * USB polarity only. For double CC cable, actually + * disconnect and reconnect with opposite polarity. + */ + if (cable == TYPEC_CABLE_SINGLE_CC) { + pd_send_vdm(0, USB_VID_GOOGLE, VDO_CMD_FLIP, NULL, 0); + gpio_set_level(GPIO_USBC_POLARITY, + !gpio_get_level(GPIO_USBC_POLARITY)); + } else if (cable == TYPEC_CABLE_DOUBLE_CC) { + /* + * Fake a disconnection for long enough to guarantee + * that we disconnect. + */ + hook_call_deferred(fake_disconnect_start, -1); + hook_call_deferred(fake_disconnect_end, -1); + fake_pd_disconnect_duration_us = PD_T_SAFE_0V; + hook_call_deferred(fake_disconnect_start, 0); + set_active_cc(!active_cc); + } break; case USBC_ACT_CABLE_POLARITY0: gpio_set_level(GPIO_USBC_POLARITY, 0); @@ -354,31 +486,6 @@ static int sn75dp130_redriver_init(void) return rv; } -static void board_init(void) -{ - timestamp_t now = get_time(); - hpd_prev_level = gpio_get_level(GPIO_DPSRC_HPD); - hpd_prev_ts = now.val; - gpio_enable_interrupt(GPIO_DPSRC_HPD); - - /* Enable interrupts on VBUS transitions. */ - gpio_enable_interrupt(GPIO_VBUS_WAKE); - - /* Enable button interrupts. */ - gpio_enable_interrupt(GPIO_DBG_5V_TO_DUT_L); - gpio_enable_interrupt(GPIO_DBG_12V_TO_DUT_L); - gpio_enable_interrupt(GPIO_DBG_CHG_TO_DEV_L); - gpio_enable_interrupt(GPIO_DBG_USB_TOGGLE_L); - gpio_enable_interrupt(GPIO_DBG_MUX_FLIP_L); - - /* TODO(crosbug.com/33761): poll DBG_20V_TO_DUT_L */ - enable_dbg20v_poll(); - - ina2xx_init(0, 0x399f, INA2XX_CALIB_1MA(10 /* mOhm */)); - sn75dp130_redriver_init(); -} -DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); - static int cmd_usbc_action(int argc, char *argv[]) { enum usbc_action act; @@ -463,12 +570,31 @@ static void board_usb_hub_reset_no_return(void) } DECLARE_DEFERRED(board_usb_hub_reset_no_return); -static void board_init_usb_hub(void) +static int board_pd_fake_disconnected(void) { - if (system_get_reset_flags() & RESET_FLAG_POWER_ON) - hook_call_deferred(board_usb_hub_reset_no_return, 500 * MSEC); + return fake_pd_disconnected; +} + +int board_fake_pd_adc_read(int cc) +{ + if (fake_pd_disconnected) { + /* Always disconnected */ + return fake_pd_host_mode ? 3000 : 0; + } else { + /* Only read the active CC line, fake disconnected on other */ + if (active_cc == cc) + return adc_read_channel(cc ? ADC_CH_CC2_PD : + ADC_CH_CC1_PD); + else + return host_mode ? 3000 : 0; + } +} + +/* Set fake PD pull-up/pull-down */ +static void board_update_fake_adc_value(int host_mode) +{ + fake_pd_host_mode = host_mode; } -DECLARE_HOOK(HOOK_INIT, board_init_usb_hub, HOOK_PRIO_DEFAULT); void board_pd_set_host_mode(int enable) { @@ -479,83 +605,63 @@ void board_pd_set_host_mode(int enable) return; } + /* if host mode changed, reset cable type */ + if (host_mode != enable) { + host_mode = enable; + cable = TYPEC_CABLE_NONE; + } + if (enable) { /* Source mode, disable charging */ gpio_set_level(GPIO_USBC_CHARGE_EN, 0); - /* High Z for no pull-down resistor on CC1 */ - gpio_set_flags_by_mask(GPIO_A, (1 << 9), GPIO_INPUT); - /* Set pull-up resistor on CC1 */ - gpio_set_flags_by_mask(GPIO_A, (1 << 2), GPIO_OUT_HIGH); - /* High Z for no pull-down resistor on CC2 */ - gpio_set_flags_by_mask(GPIO_B, (1 << 7), GPIO_INPUT); - /* Set pull-up resistor on CC2 */ - gpio_set_flags_by_mask(GPIO_B, (1 << 6), GPIO_OUT_HIGH); + + /* Set CC lines */ + set_active_cc(active_cc); } else { /* Device mode, disable VBUS */ gpio_set_level(GPIO_VBUS_CHARGER_EN, 0); gpio_set_level(GPIO_USBC_VSEL_0, 0); gpio_set_level(GPIO_USBC_VSEL_1, 0); - /* High Z for no pull-up resistor on CC1 */ - gpio_set_flags_by_mask(GPIO_A, (1 << 2), GPIO_INPUT); - /* Set pull-down resistor on CC1 */ - gpio_set_flags_by_mask(GPIO_A, (1 << 9), GPIO_OUT_LOW); - /* High Z for no pull-up resistor on CC2 */ - gpio_set_flags_by_mask(GPIO_B, (1 << 6), GPIO_INPUT); - /* Set pull-down resistor on CC2 */ - gpio_set_flags_by_mask(GPIO_B, (1 << 7), GPIO_OUT_LOW); - /* Set charge enable */ + + /* Set CC lines */ + set_active_cc(active_cc); + + /* Enable charging */ gpio_set_level(GPIO_USBC_CHARGE_EN, 1); } } -int board_pd_fake_disconnected(void) +static void board_init(void) { - return fake_pd_disconnected; -} + timestamp_t now = get_time(); + hpd_prev_level = gpio_get_level(GPIO_DPSRC_HPD); + hpd_prev_ts = now.val; + gpio_enable_interrupt(GPIO_DPSRC_HPD); -int board_fake_pd_adc_read(void) -{ - if (fake_pd_host_mode) - return 3000; /* mV */ - else - return 0; /* mV */ -} + /* Enable interrupts on VBUS transitions. */ + gpio_enable_interrupt(GPIO_VBUS_WAKE); -void board_update_fake_adc_value(int host_mode) -{ - fake_pd_host_mode = host_mode; -} + /* Enable button interrupts. */ + gpio_enable_interrupt(GPIO_DBG_5V_TO_DUT_L); + gpio_enable_interrupt(GPIO_DBG_12V_TO_DUT_L); + gpio_enable_interrupt(GPIO_DBG_CHG_TO_DEV_L); + gpio_enable_interrupt(GPIO_DBG_USB_TOGGLE_L); + gpio_enable_interrupt(GPIO_DBG_MUX_FLIP_L); -static void fake_disconnect_end(void) -{ - fake_pd_disconnected = 0; - board_pd_set_host_mode(fake_pd_host_mode); -} -DECLARE_DEFERRED(fake_disconnect_end); + /* TODO(crosbug.com/33761): poll DBG_20V_TO_DUT_L */ + enable_dbg20v_poll(); -static void fake_disconnect_start(void) -{ - /* Record the current host mode */ - fake_pd_host_mode = !gpio_get_level(GPIO_USBC_CHARGE_EN); - /* Disable VBUS */ - gpio_set_level(GPIO_VBUS_CHARGER_EN, 0); - gpio_set_level(GPIO_USBC_VSEL_0, 0); - gpio_set_level(GPIO_USBC_VSEL_1, 0); - /* High Z for no pull-up resistor on CC1 */ - gpio_set_flags_by_mask(GPIO_A, (1 << 2), GPIO_INPUT); - /* High Z for no pull-up resistor on CC2 */ - gpio_set_flags_by_mask(GPIO_B, (1 << 6), GPIO_INPUT); - /* High Z for no pull-down resistor on CC1 */ - gpio_set_flags_by_mask(GPIO_A, (1 << 9), GPIO_INPUT); - /* High Z for no pull-down resistor on CC2 */ - gpio_set_flags_by_mask(GPIO_B, (1 << 7), GPIO_INPUT); + ina2xx_init(0, 0x399f, INA2XX_CALIB_1MA(10 /* mOhm */)); + sn75dp130_redriver_init(); - fake_pd_disconnected = 1; + /* Initialize USB hub */ + if (system_get_reset_flags() & RESET_FLAG_POWER_ON) + hook_call_deferred(board_usb_hub_reset_no_return, 500 * MSEC); - hook_call_deferred(fake_disconnect_end, - fake_pd_disconnect_duration_ms * MSEC); + /* Start detecting CC cable type */ + hook_call_deferred(detect_cc_cable, SECOND); } -DECLARE_DEFERRED(fake_disconnect_start); +DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); static int cmd_fake_disconnect(int argc, char *argv[]) { @@ -576,7 +682,7 @@ static int cmd_fake_disconnect(int argc, char *argv[]) hook_call_deferred(fake_disconnect_start, -1); hook_call_deferred(fake_disconnect_end, -1); - fake_pd_disconnect_duration_ms = duration_ms; + fake_pd_disconnect_duration_us = duration_ms * MSEC; hook_call_deferred(fake_disconnect_start, delay_ms * MSEC); ccprintf("Fake disconnect for %d ms starting in %d ms.\n", diff --git a/board/plankton/board.h b/board/plankton/board.h index 43ca20fc1e..33f9165583 100644 --- a/board/plankton/board.h +++ b/board/plankton/board.h @@ -19,6 +19,8 @@ #define CONFIG_STM_HWTIMER32 #define CONFIG_USB_POWER_DELIVERY #define CONFIG_USB_PD_ALT_MODE +#undef CONFIG_USB_PD_COMM_ENABLED +#define CONFIG_USB_PD_COMM_ENABLED 0 #define CONFIG_USB_PD_CUSTOM_VDM #define CONFIG_USB_PD_DUAL_ROLE #define CONFIG_USB_PD_DYNAMIC_SRC_CAP @@ -50,6 +52,9 @@ */ #define CONFIG_SYSTEM_UNLOCKED +#undef DEFERRABLE_MAX_COUNT +#define DEFERRABLE_MAX_COUNT 9 + #ifndef __ASSEMBLER__ /* Timer selection */ @@ -95,14 +100,8 @@ void board_set_source_cap(enum board_src_cap cap); /* Reset USB hub if USB hub is switched to type-C port */ void board_maybe_reset_usb_hub(void); -/* Whether faking PD disconnected or not */ -int board_pd_fake_disconnected(void); - /* Get fake ADC reading */ -int board_fake_pd_adc_read(void); - -/* Set fake PD pull-up/pull-down */ -void board_update_fake_adc_value(int host_mode); +int board_fake_pd_adc_read(int cc); /* Set pull-up/pull-down on CC lines */ void board_pd_set_host_mode(int enable); diff --git a/board/plankton/usb_pd_config.h b/board/plankton/usb_pd_config.h index 07eda3a035..74855344e2 100644 --- a/board/plankton/usb_pd_config.h +++ b/board/plankton/usb_pd_config.h @@ -152,13 +152,7 @@ static inline void pd_config_init(int port, uint8_t power_role) static inline int pd_adc_read(int port, int cc) { - if (board_pd_fake_disconnected()) - return board_fake_pd_adc_read(); - - if (cc == 0) - return adc_read_channel(ADC_CH_CC1_PD); - else - return adc_read_channel(ADC_CH_CC2_PD); + return board_fake_pd_adc_read(cc); } #endif /* __CROS_EC_USB_PD_CONFIG_H */ |