summaryrefslogtreecommitdiff
path: root/board/servo_v4/board.c
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2016-08-24 16:25:04 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-10-14 16:05:54 -0700
commit26cacee37f9baa6cc674c3aaeac8031b225d1e17 (patch)
treeec6acfd121a7fa11a6b215730b024fb087932e10 /board/servo_v4/board.c
parentc926d7dc7c4df52c7d3c82c86bae9ac6e8a6b758 (diff)
downloadchrome-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.c216
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");