summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2017-11-06 11:39:06 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-11-07 15:25:22 -0800
commit0354ad02cba910c90fd0c0e622c3b0b698802a1c (patch)
treecdfacae90ce79bbdff81b82278e874022d52ac02
parentbdb3f44ef2df844c97fcf02730a6433675778595 (diff)
downloadchrome-ec-0354ad02cba910c90fd0c0e622c3b0b698802a1c.tar.gz
bd9995x: Leave USB data switches closed on PD power swap
In order for BC1.2 detection to succeed, USB data switches must be open. Previously we performed BC1.2 detection whenever VBUS transitioned up to 5V, including on power swap. In fact, there is no need to do BC1.2 detection on a PD-capable port, since we will always charge using the USB-C or PD negotiated ILIM. Skip BC1.2 detection on power swap (and more generally when a partner port is known to speak PD) by manually triggering BC1.2 detection. In addition, manage USB switch state differently, so that "auto mode" is only enabled during BC1.2 detection. BUG=chromium:780905 BRANCH=gru TEST=Attach USB-PD phone capable of role swap. Verify USB 2.0 device is enumerated on plug, and not re-enumerated through a series of "pd # swap power" commands on the EC console. Also verify BC1.2 charging and PD charging are still functional on kevin. Change-Id: I1d7d4dee3bc8d2e7885e7adb49ded84b4f515ad5 Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/755878 Commit-Ready: Shawn N <shawnn@chromium.org> Tested-by: Shawn N <shawnn@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--driver/charger/bd9995x.c80
-rw-r--r--driver/charger/bd9995x.h11
2 files changed, 56 insertions, 35 deletions
diff --git a/driver/charger/bd9995x.c b/driver/charger/bd9995x.c
index 9e35f273ee..cd9b60d759 100644
--- a/driver/charger/bd9995x.c
+++ b/driver/charger/bd9995x.c
@@ -52,6 +52,7 @@ static const struct charger_info bd9995x_charger_info = {
/* Charge command code map */
static enum bd9995x_command charger_map_cmd = BD9995X_INVALID_COMMAND;
+/* Mutex for active register set control. */
static struct mutex bd9995x_map_mutex;
#ifdef HAS_TASK_USB_CHG
@@ -307,6 +308,8 @@ static int bd9995x_get_charger_op_status(int *status)
#ifdef HAS_TASK_USB_CHG
static int bc12_detected_type[CONFIG_USB_PD_PORT_COUNT];
+/* Mutex for UCD_SET regsiters, lock before read / mask / write. */
+static struct mutex ucd_set_mutex[BD9995X_CHARGE_PORT_COUNT];
static int bd9995x_get_bc12_device_type(int port)
{
@@ -337,25 +340,32 @@ static int bd9995x_get_bc12_device_type(int port)
}
}
-static int bd9995x_enable_usb_switch(int port, enum usb_switch setting)
+/*
+ * Do safe read / mask / write of BD9995X_CMD_*_UCD_SET register.
+ * The USB charger task owns all bits of this register, except for bit 0
+ * (BD9995X_CMD_UCD_SET_USB_SW), which is controlled by
+ * usb_charger_set_switches().
+ */
+static int bd9995x_update_ucd_set_reg(int port, uint16_t mask, int set)
{
int rv;
int reg;
- int port_reg;
-
- port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ?
+ int port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ?
BD9995X_CMD_VBUS_UCD_SET : BD9995X_CMD_VCC_UCD_SET;
+ mutex_lock(&ucd_set_mutex[port]);
rv = ch_raw_read16(port_reg, &reg, BD9995X_EXTENDED_COMMAND);
- if (rv)
- return rv;
+ if (!rv) {
+ if (set)
+ reg |= mask;
+ else
+ reg &= ~mask;
- if (setting == USB_SWITCH_CONNECT)
- reg |= BD9995X_CMD_UCD_SET_USB_SW_EN;
- else
- reg &= ~BD9995X_CMD_UCD_SET_USB_SW_EN;
+ rv = ch_raw_write16(port_reg, reg, BD9995X_EXTENDED_COMMAND);
+ }
- return ch_raw_write16(port_reg, reg, BD9995X_EXTENDED_COMMAND);
+ mutex_unlock(&ucd_set_mutex[port]);
+ return rv;
}
static int bd9995x_bc12_check_type(int port)
@@ -473,6 +483,20 @@ static int bd9995x_get_interrupts(int port)
return reg;
}
+/*
+ * Set or clear registers necessary to do one-time BC1.2 detection.
+ * Pass enable = 1 to trigger BC1.2 detection, and enable = 0 once
+ * BC1.2 detection has completed.
+ */
+static int bd9995x_bc12_detect(int port, int enable)
+{
+ return bd9995x_update_ucd_set_reg(port,
+ BD9995X_CMD_UCD_SET_BCSRETRY |
+ BD9995X_CMD_UCD_SET_USBDETEN |
+ BD9995X_CMD_UCD_SET_USB_SW_EN,
+ enable);
+}
+
static int usb_charger_process(int port)
{
int vbus_provided = bd9995x_is_vbus_provided(port) &&
@@ -481,8 +505,12 @@ static int usb_charger_process(int port)
/* Inform other modules about VBUS level */
usb_charger_vbus_change(port, vbus_provided);
- /* Do BC1.2 detection */
- if (vbus_provided) {
+ /*
+ * Do BC1.2 detection, if we have VBUS and our port is not known
+ * to speak PD.
+ */
+ if (vbus_provided && !pd_capable(port)) {
+ bd9995x_bc12_detect(port, 1);
/*
* Need to give the charger time (~312 mSec) before the
* bc12_type is available. The main task loop will schedule a
@@ -491,6 +519,9 @@ static int usb_charger_process(int port)
return 1;
}
+ /* Reset BC1.2 regs so we don't do auto-detection. */
+ bd9995x_bc12_detect(port, 0);
+
/*
* VBUS is no longer being provided, if the bc12_type had been
* previously determined, then need to detach.
@@ -817,24 +848,6 @@ static void bd9995x_init(void)
{
int reg;
- /* Enable BC1.2 detection on VCC */
- if (ch_raw_read16(BD9995X_CMD_VCC_UCD_SET, &reg,
- BD9995X_EXTENDED_COMMAND))
- return;
- reg |= BD9995X_CMD_UCD_SET_USBDETEN;
- reg &= ~BD9995X_CMD_UCD_SET_USB_SW_EN;
- ch_raw_write16(BD9995X_CMD_VCC_UCD_SET, reg,
- BD9995X_EXTENDED_COMMAND);
-
- /* Enable BC1.2 detection on VBUS */
- if (ch_raw_read16(BD9995X_CMD_VBUS_UCD_SET, &reg,
- BD9995X_EXTENDED_COMMAND))
- return;
- reg |= BD9995X_CMD_UCD_SET_USBDETEN;
- reg &= ~BD9995X_CMD_UCD_SET_USB_SW_EN;
- ch_raw_write16(BD9995X_CMD_VBUS_UCD_SET, reg,
- BD9995X_EXTENDED_COMMAND);
-
/*
* Disable charging trigger by BC1.2 on VCC & VBUS and
* automatic limitation of the input current.
@@ -1119,7 +1132,8 @@ void usb_charger_set_switches(int port, enum usb_switch setting)
? CONFIG_BD9995X_POWER_SAVE_MODE : BD9995X_PWR_SAVE_OFF);
#endif
- bd9995x_enable_usb_switch(port, usb_switch_state[port]);
+ bd9995x_update_ucd_set_reg(port, BD9995X_CMD_UCD_SET_USB_SW,
+ usb_switch_state[port] == USB_SWITCH_CONNECT);
}
void bd9995x_vbus_interrupt(enum gpio_signal signal)
@@ -1191,6 +1205,8 @@ void usb_charger_task(void *u)
bc12_det_mark[port] =
bd9995x_bc12_check_type(port) ?
get_time().val + 100 * MSEC : 0;
+ /* Reset BC1.2 regs to skip auto-detection. */
+ bd9995x_bc12_detect(port, 0);
}
/*
diff --git a/driver/charger/bd9995x.h b/driver/charger/bd9995x.h
index 7b10dbde99..f9fb092b24 100644
--- a/driver/charger/bd9995x.h
+++ b/driver/charger/bd9995x.h
@@ -180,9 +180,14 @@ enum bd9995x_charge_port {
#define BD9995X_CMD_IOUT_DACIN_VAL 0x27
#define BD9995X_CMD_VCC_UCD_SET 0x28
/* Bits for both VCC_UCD_SET and VBUS_UCD_SET regs */
-#define BD9995X_CMD_UCD_SET_BCSRETRY (1 << 12)
-#define BD9995X_CMD_UCD_SET_USBDETEN (1 << 7)
-#define BD9995X_CMD_UCD_SET_USB_SW_EN (1 << 1)
+/* Retry BC1.2 detection on set */
+#define BD9995X_CMD_UCD_SET_BCSRETRY (1 << 12)
+/* Enable BC1.2 detection, will automatically occur on VBUS detect */
+#define BD9995X_CMD_UCD_SET_USBDETEN (1 << 7)
+/* USB switch state auto-control */
+#define BD9995X_CMD_UCD_SET_USB_SW_EN (1 << 1)
+/* USB switch state, 1 = ON, only meaningful when USB_SW_EN = 0 */
+#define BD9995X_CMD_UCD_SET_USB_SW (1 << 0)
#define BD9995X_CMD_VCC_UCD_STATUS 0x29
/* Bits for both VCC_UCD_STATUS and VBUS_UCD_STATUS regs */