summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2019-03-18 17:47:51 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2019-04-02 00:29:13 +0000
commitadd38b392e3d2f0e94629e91f77cf5ccd57a8418 (patch)
treefd679670da688ef99e32b1a6f5c644231410579c
parent1eab95a838445a79364723fe48ef2b3abc4cbc90 (diff)
downloadchrome-ec-add38b392e3d2f0e94629e91f77cf5ccd57a8418.tar.gz
servo_v4: detect SBU more reliably
SBU orientation was detected in a one-shot check, that didn't ensure that the line was idle. Change to detect SBU orientation independently of PD state, and only while it's disconnected from the host. Delete keepalive and ccd_enable as they aren't meaningful for the new mechanism. BUG=b:128646723, chromium:942130 BRANCH=servo TEST=unplug a lot of times, orientation always correct. Signed-off-by: Nick Sanders <nsanders@chromium.org> Change-Id: I16c770b9d8d7a0c2d90aa214cb8cdec4c36a7303 Reviewed-on: https://chromium-review.googlesource.com/1529724 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Todd Broch <tbroch@chromium.org> (cherry picked from commit 0490e8afde1b90cb600e68630a1ebe08a88cb681) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1545083
-rw-r--r--board/servo_v4/board.c197
1 files changed, 93 insertions, 104 deletions
diff --git a/board/servo_v4/board.c b/board/servo_v4/board.c
index 982ed9ccfb..656808c767 100644
--- a/board/servo_v4/board.c
+++ b/board/servo_v4/board.c
@@ -268,128 +268,114 @@ static void init_ioexpander(void)
i2c_write8(1, GPIOX_I2C_ADDR, GPIOX_DIR_PORT_B, 0x18);
}
-/* Define voltage thresholds for SBU USB detection */
-#define GND_MAX_MV 350
-#define USB_HIGH_MV 1500
+/*
+ * Define voltage thresholds for SBU USB detection.
+ *
+ * Max observed USB low across sampled systems: 666mV
+ * Min observed USB high across sampled systems: 3026mV
+ */
+#define GND_MAX_MV 700
+#define USB_HIGH_MV 2500
+#define SBU_DIRECT 0
+#define SBU_FLIP 1
+
+#define MODE_SBU_DISCONNECT 0
+#define MODE_SBU_CONNECT 1
+#define MODE_SBU_FLIP 2
+#define MODE_SBU_OTHER 3
static void ccd_measure_sbu(void);
DECLARE_DEFERRED(ccd_measure_sbu);
-
static void ccd_measure_sbu(void)
{
int sbu1;
int sbu2;
+ int mux_en;
+ static int count /* = 0 */;
+ static int last /* = 0 */;
+ static int polarity /* = 0 */;
/* Read sbu voltage levels */
sbu1 = adc_read_channel(ADC_SBU1_DET);
sbu2 = adc_read_channel(ADC_SBU2_DET);
+ mux_en = gpio_get_level(GPIO_SBU_MUX_EN);
- /* 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);
- msleep(10);
- CPRINTS("CCD: connected flip");
- } else if ((sbu2 > USB_HIGH_MV) &&
- (sbu1 < GND_MAX_MV)) {
- /* SBU flip = 0 */
- write_ioexpander(0, 2, 0);
- msleep(10);
- CPRINTS("CCD: connected noflip");
+ /*
+ * While SBU_MUX is disabled (SuzyQ unplugged), we'll poll the SBU lines
+ * to check if an idling, unconfigured USB device is present.
+ * USB FS pulls one line high for connect request.
+ * If so, and it persists for 500ms, we'll enable the SuzyQ in that
+ * orientation.
+ */
+ if ((!mux_en) && (sbu1 > USB_HIGH_MV) && (sbu2 < GND_MAX_MV)) {
+ /* Check flip connection polarity. */
+ if (last != MODE_SBU_FLIP) {
+ last = MODE_SBU_FLIP;
+ polarity = SBU_FLIP;
+ count = 0;
+ } else {
+ count++;
+ }
+ } else if ((!mux_en) && (sbu2 > USB_HIGH_MV) && (sbu1 < GND_MAX_MV)) {
+ /* Check direct connection polarity. */
+ if (last != MODE_SBU_CONNECT) {
+ last = MODE_SBU_CONNECT;
+ polarity = SBU_DIRECT;
+ count = 0;
+ } else {
+ count++;
+ }
+ /*
+ * If SuzyQ is enabled, we'll poll for a persistent no-signal for
+ * 500ms. Since USB is differential, we should never see GND/GND
+ * while the device is connected.
+ * If disconnected, electrically remove SuzyQ.
+ */
+ } else if ((mux_en) && (sbu1 < GND_MAX_MV) && (sbu2 < GND_MAX_MV)) {
+ /* Check for SBU disconnect if connected. */
+ if (last != MODE_SBU_DISCONNECT) {
+ last = MODE_SBU_DISCONNECT;
+ count = 0;
+ } else {
+ count++;
+ }
} else {
- /* Measure again after 100 msec */
- hook_call_deferred(&ccd_measure_sbu_data, 100 * MSEC);
+ /* Didn't find anything, reset state. */
+ last = MODE_SBU_OTHER;
+ count = 0;
}
-}
-
-static uint8_t ccd_keepalive_enabled;
-static int command_keepalive(int argc, char **argv)
-{
- int val;
- if (argc > 2)
- return EC_ERROR_PARAM_COUNT;
-
- if (argc == 2) {
- if (!parse_bool(argv[1], &val))
- return EC_ERROR_PARAM1;
-
- ccd_keepalive_enabled = val;
+ /*
+ * We have seen a new state continuously for 500ms.
+ * Let's update the mux to enable/disable SuzyQ appropriately.
+ */
+ if (count > 5) {
+ if (mux_en) {
+ /* Disable mux as it's disconnected now. */
+ gpio_set_level(GPIO_SBU_MUX_EN, 0);
+ msleep(10);
+ CPRINTS("CCD: disconnected.");
+ } else {
+ /* SBU flip = polarity */
+ write_ioexpander(0, 2, polarity);
+ gpio_set_level(GPIO_SBU_MUX_EN, 1);
+ msleep(10);
+ CPRINTS("CCD: connected %s",
+ polarity ? "noflip" : "flip");
+ }
}
- ccprintf("ccd_keepalive: %sabled\n",
- ccd_keepalive_enabled ? "en" : "dis");
- return EC_SUCCESS;
+ /* Measure every 100ms, forever. */
+ hook_call_deferred(&ccd_measure_sbu_data, 100 * MSEC);
}
-DECLARE_CONSOLE_COMMAND(keepalive, command_keepalive, "[enable | disable]",
- "Enable CCD keepalive. Prevents SBU sampling.");
-
-static void check_for_disconnect(void);
-DECLARE_DEFERRED(check_for_disconnect);
-static void check_for_disconnect(void)
-{
- static uint8_t entries;
- int dut_is_connected = pd_is_connected(1);
-
- entries++;
-
- if (dut_is_connected) {
- entries = 0;
- return;
- } else if ((entries < 3) && !dut_is_connected) {
- /* Hmm, it's still not connected? Let's keep checking. */
- hook_call_deferred(&check_for_disconnect_data, 100 * MSEC);
- return;
- }
- /*
- * Hmm, okay. Maybe the DUT is actually disconnected. Clear
- * the CCD keepalive such that the auto flip orientation
- * detection will work upon a plug in.
- */
- CPRINTS("DUT seems disconnected. Clearing CCD keepalive.");
- entries = 0;
- ccd_keepalive_enabled = 0;
-}
void ccd_enable(int enable)
{
- if (enable) {
- /*
- * Unfortunately the polarity detect is designed for real plug
- * events, and only accurately detects pre-connect idle. If
- * there's active traffic on the line (like while EC is
- * rebooting) this could pretty much go either way. Therefore,
- * if CCD keepalive is enabled, let's not measure the SBU lines
- * and leave the mux alone. Most likely nothing has changed.
- *
- * NOTE: Once CCD keepalive has been enabled, it will remained
- * enabled until the DUT is seen disconnected for at least
- * 900ms.
- */
- if (!ccd_keepalive_enabled)
- /* Allow some time following turning on of VBUS */
- hook_call_deferred(&ccd_measure_sbu_data,
- PD_POWER_SUPPLY_TURN_ON_DELAY);
- } else {
- /* We are not connected to anything */
-
- /* Disable ccd_measure_sbu deferred call always */
- hook_call_deferred(&ccd_measure_sbu_data, -1);
-
- /*
- * In a bit, start checking to see if we're still
- * disconnected.
- */
- hook_call_deferred(&check_for_disconnect_data, 600 * MSEC);
-
- /*
- * The DUT port has detected a detach event. Don't want to
- * disconnect the SBU mux here so that the H1 USB console can
- * remain connected.
- */
- CPRINTS("CCD: TypeC detach, no change to SBU mux");
- }
+ /*
+ * We may use this if displayport is ever enabled.
+ * For now, CCD is always enabled on SBU.
+ */
}
int board_get_version(void)
@@ -441,16 +427,19 @@ static void board_init(void)
system_set_bbram(SYSTEM_BBRAM_IDX_PD1, 0);
/*
- * Enable SBU mux. The polarity is set each time a new PD attach event
- * occurs. But, the SBU mux is not disabled on detach so that the H1 USB
- * console will survie a DUT EC reset.
+ * Disable SBU mux. The polarity is set each time a presense is detected
+ * on SBU, and wired thorugh. On missing voltage on SBU. SBU wires are
+ * disconnected.
*/
- gpio_set_level(GPIO_SBU_MUX_EN, 1);
+ gpio_set_level(GPIO_SBU_MUX_EN, 0);
/*
* Voltage transition needs to occur in lockstep between the CHG and
* DUT ports, so initially limit voltage to 5V.
*/
pd_set_max_voltage(PD_MIN_MV);
+
+ hook_call_deferred(&ccd_measure_sbu_data, 1000 * MSEC);
+
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);