diff options
author | Nick Sanders <nsanders@chromium.org> | 2016-08-24 16:25:04 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-10-14 16:05:54 -0700 |
commit | 26cacee37f9baa6cc674c3aaeac8031b225d1e17 (patch) | |
tree | ec6acfd121a7fa11a6b215730b024fb087932e10 /board/servo_v4/board.c | |
parent | c926d7dc7c4df52c7d3c82c86bae9ac6e8a6b758 (diff) | |
download | chrome-ec-26cacee37f9baa6cc674c3aaeac8031b225d1e17.tar.gz |
servo_v4: support autodetect of CCD
This allows a servo_v4 to export case closed debugging
automatically, if it detects that it's been plugged into
a ccd device.
BUG=chromium:571476
TEST=Connect to reef in both orientations.
BRANCH=None
Change-Id: I8e2781056b22e834132bc4bb839ef2763fa0b4b8
Signed-off-by: Nick Sanders <nsanders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/375359
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Diffstat (limited to 'board/servo_v4/board.c')
-rw-r--r-- | board/servo_v4/board.c | 216 |
1 files changed, 214 insertions, 2 deletions
diff --git a/board/servo_v4/board.c b/board/servo_v4/board.c index 03410442db..6b742d3ebd 100644 --- a/board/servo_v4/board.c +++ b/board/servo_v4/board.c @@ -28,6 +28,9 @@ #include "util.h" +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) + + /****************************************************************************** * Build GPIO tables and expose a subset of the GPIOs over USB. */ @@ -62,12 +65,12 @@ GPIO_USB_DET_PP_CHG, GPIO_USB_DUT_CC2_RPUSB, GPIO_USB_DUT_CC2_RD, GPIO_USB_DUT_CC2_RA, /* 20 */ -GPIO_USB_DUT_CC1_PR3A0, +GPIO_USB_DUT_CC1_RP3A0, GPIO_USB_DUT_CC1_RP1A5, GPIO_USB_DUT_CC1_RPUSB, GPIO_USB_DUT_CC1_RD, GPIO_USB_DUT_CC1_RA, /* 25 */ -GPIO_USB_DUT_CC2_PR3A0, +GPIO_USB_DUT_CC2_RP3A0, GPIO_USB_DUT_CC2_RP1A5, }; @@ -266,6 +269,187 @@ static void init_ioexpander(void) i2c_write8(1, 0x40, 0x7, 0x0); } +/* State of CC lines presented to DUT */ +/* Dual Rd pulldown, classic debug device. */ +#define CCD_ID_RDRD 0 +/* RpUSB + Rp1A5, indicates a self powered dongle. */ +#define CCD_ID_RPUSB 1 +/* One Rd. Device w/o CCD */ +#define CCD_ID_NONE 4 + +static int ccd_id = CCD_ID_NONE; + +/* Set CC values according to requested mode. */ +static void init_ccd(int mode) +{ + int cc1_rd = GPIO_INPUT; + int cc2_rd = GPIO_INPUT; + int cc1_rpusb = GPIO_INPUT; + int cc2_rpusb = GPIO_INPUT; + int cc1_rp1a5 = GPIO_INPUT; + int cc2_rp1a5 = GPIO_INPUT; + int cc1_rp3a0 = GPIO_INPUT; + int cc2_rp3a0 = GPIO_INPUT; + + switch (mode) { + case CCD_ID_RDRD: + cc1_rd = GPIO_OUT_LOW; + cc2_rd = GPIO_OUT_LOW; + break; + + case CCD_ID_RPUSB: + cc1_rpusb = GPIO_OUT_HIGH; + cc2_rp1a5 = GPIO_OUT_HIGH; + break; + + default: + cc1_rd = GPIO_OUT_LOW; + mode = CCD_ID_NONE; + break; + } + + gpio_set_flags(GPIO_USB_DUT_CC1_RD, cc1_rd); + gpio_set_flags(GPIO_USB_DUT_CC2_RD, cc2_rd); + gpio_set_flags(GPIO_USB_DUT_CC1_RPUSB, cc1_rpusb); + gpio_set_flags(GPIO_USB_DUT_CC2_RPUSB, cc2_rpusb); + gpio_set_flags(GPIO_USB_DUT_CC1_RP1A5, cc1_rp1a5); + gpio_set_flags(GPIO_USB_DUT_CC2_RP1A5, cc2_rp1a5); + gpio_set_flags(GPIO_USB_DUT_CC1_RP3A0, cc1_rp3a0); + gpio_set_flags(GPIO_USB_DUT_CC2_RP3A0, cc2_rp3a0); + + /* Disable CCD until we can detect orientation */ + gpio_set_level(GPIO_SBU_MUX_EN, 0); + write_ioexpander(0, 0, 0); + + ccd_id = mode; +} + + +/* Define voltage thresholds for CCD and SBU USB detection */ +#define GND_MAX_MV 350 +#define PULL_0V35_MV 350 +#define PULL_0V55_MV 550 +#define PULL_0V9_MV 900 +#define PULL_1V1_MV 1100 +#define PULL_2V0_MV 2000 +#define POWER_MIN_MV 3000 +#define USB_HIGH_MV 1500 + +/* Check if presented CCD was accepted by the device */ +static int check_ccd_request(int cc1, int cc2) +{ + if ((ccd_id == CCD_ID_RDRD) && + (cc1 > PULL_0V35_MV) && (cc1 < PULL_0V55_MV) && + (cc2 > PULL_0V35_MV) && (cc2 < PULL_0V55_MV)) + return 1; + + if ((ccd_id == CCD_ID_RPUSB) && + (cc1 > PULL_0V35_MV) && (cc1 < PULL_0V55_MV) && + (cc2 > PULL_0V9_MV) && (cc2 < PULL_1V1_MV)) + return 1; + + return 0; +} + +/* Check if CC lines indicate an unplug event */ +static int check_usb_disconnect(int cc1, int cc2) +{ + if ((cc1 < GND_MAX_MV) && (cc2 < GND_MAX_MV)) + return 1; + + if ((cc1 > POWER_MIN_MV) && (cc2 > POWER_MIN_MV)) + return 1; + + return 0; +} + + +/* Current mode for CCD USB line connection */ +/* Cable not plugged in */ +#define CCD_MODE_DISCONNECTED 0 +/* Cable plugged in, CCD detected in default orientation */ +#define CCD_MODE_CONNECTED 1 +/* Cable plugged in, CCD detected in flip orientation */ +#define CCD_MODE_CONNECTED_FLIP 2 +/* Cable plugged in, nothing detected on SBU lines */ +#define CCD_MODE_CONNECTED_NONE 3 +/* No type-c cable in servo. */ +#define CCD_MODE_USBA 4 + +static int mode = CCD_MODE_DISCONNECTED; + +/* + * We don't have an available interrupt, so we'll just check this + * every second. Update state every tick if necessary. + */ +static void usb_sbu_tick(void) +{ + int cc1, cc2; + + /* Check if we have a CCD cable */ + if ((mode == CCD_MODE_USBA) || !gpio_get_level(GPIO_DONGLE_DET)) { + mode = CCD_MODE_USBA; + return; + } + + /* Check CC lines via ADC */ + cc1 = adc_read_channel(ADC_DUT_CC1_PD); + cc2 = adc_read_channel(ADC_DUT_CC2_PD); + + if (mode == CCD_MODE_DISCONNECTED) { + /* Check if both CC lines are pulled, and we are connected */ + if (check_ccd_request(cc1, cc2)) { + int sbu1; + int sbu2; + + /* + * Give the onboard CCD micro 100ms + * to notice and enable USB, then check adc levels. + */ + usleep(100000); + sbu1 = adc_read_channel(ADC_SBU1_DET); + sbu2 = adc_read_channel(ADC_SBU2_DET); + + CPRINTS("CCD: Plug detect cc1:%d cc2:%d " + "sbu1:%d, sbu2:%d", + cc1, cc2, sbu1, sbu2); + + /* USB FS pulls one line high for connect request */ + if ((sbu1 > USB_HIGH_MV) && (sbu2 < GND_MAX_MV)) { + /* SBU flip = 1 */ + write_ioexpander(0, 2, 1); + usleep(10000); + gpio_set_level(GPIO_SBU_MUX_EN, 1); + mode = CCD_MODE_CONNECTED; + CPRINTS("CCD: connected flip"); + } else if ((sbu2 > USB_HIGH_MV) && + (sbu1 < GND_MAX_MV)) { + /* SBU flip = 0 */ + write_ioexpander(0, 2, 0); + usleep(10000); + gpio_set_level(GPIO_SBU_MUX_EN, 1); + mode = CCD_MODE_CONNECTED_FLIP; + CPRINTS("CCD: connected noflip"); + } else { + mode = CCD_MODE_CONNECTED_NONE; + CPRINTS("CCD: connected none"); + } + } + } else { + /* mode == CCD_MODE_CONNECTED[_FLIP] */ + if (check_usb_disconnect(cc1, cc2)) { + /* We are not connected to anything */ + + /* Turn off CCD */ + gpio_set_level(GPIO_SBU_MUX_EN, 0); + CPRINTS("CCD: disconnect"); + mode = CCD_MODE_DISCONNECTED; + } + } +} +DECLARE_HOOK(HOOK_TICK, usb_sbu_tick, HOOK_PRIO_DEFAULT); + + static void board_init(void) { /* USB to serial queues */ @@ -288,5 +472,33 @@ static void board_init(void) /* Enable uservo USB by default. */ init_ioexpander(); init_uservo_port(); + + /* Enable CCD if type-c */ + if (gpio_get_level(GPIO_DONGLE_DET)) + init_ccd(CCD_ID_RPUSB); } DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); + +static int command_ccd(int argc, char **argv) +{ + int mode = CCD_ID_NONE; + + if (argc < 2) + return EC_ERROR_PARAM_COUNT; + + /* Handle requested mode */ + if (!strcasecmp(argv[1], "rdrd")) + mode = CCD_ID_RDRD; + else if (!strcasecmp(argv[1], "rpusb")) + mode = CCD_ID_RPUSB; + else if (!strcasecmp(argv[1], "off")) + mode = CCD_ID_NONE; + else + return EC_ERROR_PARAM1; + + init_ccd(mode); + ccprintf("DUT CC lines set to %s\n", argv[1]); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(ccd, command_ccd, + "[rdrd|rpusb|off]", "Set pullups or pulldowns to indicate CCD"); |