summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2016-05-12 16:06:05 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-05-13 23:34:51 -0700
commita4ef74039104fb7da4137960c2c023f45dda6924 (patch)
tree2b90444806902e130d41bbfca648ebb0a2afcfbc
parent7d8964614d85232b56b010853ab7f06f93229f57 (diff)
downloadchrome-ec-a4ef74039104fb7da4137960c2c023f45dda6924.tar.gz
usb_charger: Move part-specific code to usb_switch driver
Previously usb_charger.c supported only pi3usb9281, but now support for additional parts is required. Move pericom-specific code (including the usb_charger tasks that handles various quirks of that part) to the pi3usb9281 usb_switch driver. Going forward, usb_switch drivers must implement usb_charger_set_switches() and must have some method (such as a task or interrupt handler) to update charge_manager with information about attached chargers. BUG=chrome-os-partner:53363 BRANCH=None TEST=`make buildall -j` Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Change-Id: I4df74e043d8cf2e532d48c39c73b7dc2930f7d3b Reviewed-on: https://chromium-review.googlesource.com/344289 Commit-Ready: Shawn N <shawnn@chromium.org> Tested-by: Shawn N <shawnn@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--common/usb_charger.c195
-rw-r--r--driver/pi3usb9281.h19
-rw-r--r--driver/usb_switch_pi3usb9281.c216
-rw-r--r--include/config.h2
4 files changed, 204 insertions, 228 deletions
diff --git a/common/usb_charger.c b/common/usb_charger.c
index c56e0f4d0f..8e938233a3 100644
--- a/common/usb_charger.c
+++ b/common/usb_charger.c
@@ -4,40 +4,23 @@
*/
/*
- * USB charger / BC1.2 task. This code assumes that CONFIG_CHARGE_MANAGER
- * is defined and implemented. PI3USB9281 is the only charger detector
- * currently supported.
+ * USB charger interface routines. This code assumes that CONFIG_CHARGE_MANAGER
+ * is defined and implemented.
+ * usb_charger_set_switches() must be implemented by a companion
+ * usb_switch driver.
+ * In addition, USB switch-specific usb_charger task or interrupt routine
+ * is necessary to update charge_manager with detected charger attributes.
*/
#include "charge_manager.h"
#include "common.h"
#include "console.h"
-#include "ec_commands.h"
#include "gpio.h"
#include "hooks.h"
-#include "pi3usb9281.h"
#include "task.h"
-#include "timer.h"
#include "usb_charge.h"
#include "usb_pd.h"
-#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
-
-/* Wait after a charger is detected to debounce pin contact order */
-#define USB_CHG_DEBOUNCE_DELAY_MS 1000
-/*
- * Wait after reset, before re-enabling attach interrupt, so that the
- * spurious attach interrupt from certain ports is ignored.
- */
-#define USB_CHG_RESET_DELAY_MS 100
-
-/*
- * Store the state of our USB data switches so that they can be restored
- * after pericom reset.
- */
-static int usb_switch_state[CONFIG_USB_PD_PORT_COUNT];
-static struct mutex usb_switch_lock[CONFIG_USB_PD_PORT_COUNT];
-
static void update_vbus_supplier(int port, int vbus_level)
{
struct charge_port_info charge;
@@ -67,19 +50,6 @@ int usb_charger_port_is_sourcing_vbus(int port)
return 0;
}
-void usb_charger_set_switches(int port, enum usb_switch setting)
-{
- /* If switch is not changing then return */
- if (setting == usb_switch_state[port])
- return;
-
- mutex_lock(&usb_switch_lock[port]);
- if (setting != USB_SWITCH_RESTORE)
- usb_switch_state[port] = setting;
- pi3usb9281_set_switches(port, usb_switch_state[port]);
- mutex_unlock(&usb_switch_lock[port]);
-}
-
void usb_charger_vbus_change(int port, int vbus_level)
{
/* If VBUS has transitioned low, notify PD module directly */
@@ -94,159 +64,6 @@ void usb_charger_vbus_change(int port, int vbus_level)
#endif
}
-static void usb_charger_bc12_detect(int port)
-{
- int device_type, charger_status;
- struct charge_port_info charge;
- int type;
-
- charge.voltage = USB_CHARGER_VOLTAGE_MV;
-
- if (usb_charger_port_is_sourcing_vbus(port)) {
- /* If we're sourcing VBUS then we're not charging */
- device_type = charger_status = 0;
- } else {
- /* Set device type */
- device_type = pi3usb9281_get_device_type(port);
- charger_status = pi3usb9281_get_charger_status(port);
- }
-
- /* Debounce pin plug order if we detect a charger */
- if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) {
- /* next operation might trigger a detach interrupt */
- pi3usb9281_disable_interrupts(port);
- /*
- * Ensure D+/D- are open before resetting
- * Note: we can't simply call pi3usb9281_set_switches() because
- * another task might override it and set the switches closed.
- */
- pi3usb9281_set_switch_manual(port, 1);
- pi3usb9281_set_pins(port, 0);
-
- /* Delay to debounce pin attach order */
- msleep(USB_CHG_DEBOUNCE_DELAY_MS);
-
- /*
- * Trigger chip reset to refresh detection registers.
- * WARNING: This reset is acceptable for samus_pd,
- * but may not be acceptable for devices that have
- * an OTG / device mode, as we may be interrupting
- * the connection.
- */
- pi3usb9281_reset(port);
- /*
- * Restore data switch settings - switches return to
- * closed on reset until restored.
- */
- usb_charger_set_switches(port, USB_SWITCH_RESTORE);
- /* Clear possible disconnect interrupt */
- pi3usb9281_get_interrupts(port);
- /* Mask attach interrupt */
- pi3usb9281_set_interrupt_mask(port,
- 0xff &
- ~PI3USB9281_INT_ATTACH);
- /* Re-enable interrupts */
- pi3usb9281_enable_interrupts(port);
- msleep(USB_CHG_RESET_DELAY_MS);
-
- /* Clear possible attach interrupt */
- pi3usb9281_get_interrupts(port);
- /* Re-enable attach interrupt */
- pi3usb9281_set_interrupt_mask(port, 0xff);
-
- /* Re-read ID registers */
- device_type = pi3usb9281_get_device_type(port);
- charger_status = pi3usb9281_get_charger_status(port);
- }
-
- /* Attachment: decode + update available charge */
- if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) {
- if (PI3USB9281_CHG_STATUS_ANY(charger_status))
- type = CHARGE_SUPPLIER_PROPRIETARY;
- else if (device_type & PI3USB9281_TYPE_CDP)
- type = CHARGE_SUPPLIER_BC12_CDP;
- else if (device_type & PI3USB9281_TYPE_DCP)
- type = CHARGE_SUPPLIER_BC12_DCP;
- else if (device_type & PI3USB9281_TYPE_SDP)
- type = CHARGE_SUPPLIER_BC12_SDP;
- else
- type = CHARGE_SUPPLIER_OTHER;
-
- charge.current = pi3usb9281_get_ilim(device_type,
- charger_status);
- charge_manager_update_charge(type, port, &charge);
- } else { /* Detachment: update available charge to 0 */
- charge.current = 0;
- charge_manager_update_charge(
- CHARGE_SUPPLIER_PROPRIETARY,
- port,
- &charge);
- charge_manager_update_charge(
- CHARGE_SUPPLIER_BC12_CDP,
- port,
- &charge);
- charge_manager_update_charge(
- CHARGE_SUPPLIER_BC12_DCP,
- port,
- &charge);
- charge_manager_update_charge(
- CHARGE_SUPPLIER_BC12_SDP,
- port,
- &charge);
- charge_manager_update_charge(
- CHARGE_SUPPLIER_OTHER,
- port,
- &charge);
- }
-
- /* notify host of power info change */
- pd_send_host_event(PD_EVENT_POWER_CHANGE);
-}
-
-void usb_charger_task(void)
-{
- const int attach_mask = PI3USB9281_INT_ATTACH | PI3USB9281_INT_DETACH;
- int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1);
- int interrupt;
- uint32_t evt;
-
- /* Initialize chip and enable interrupts */
- pi3usb9281_init(port);
-
- usb_charger_bc12_detect(port);
-
- while (1) {
- /* Wait for interrupt */
- evt = task_wait_event(-1);
-
- /* Interrupt from the Pericom chip, determine charger type */
- if (evt & USB_CHG_EVENT_BC12) {
- /* Read interrupt register to clear on chip */
- pi3usb9281_get_interrupts(port);
- usb_charger_bc12_detect(port);
- } else if (evt & USB_CHG_EVENT_INTR) {
- /* Check the interrupt register, and clear on chip */
- interrupt = pi3usb9281_get_interrupts(port);
- if (interrupt & attach_mask)
- usb_charger_bc12_detect(port);
- }
-
- /*
- * Re-enable interrupts on pericom charger detector since the
- * chip may periodically reset itself, and come back up with
- * registers in default state. TODO(crosbug.com/p/33823): Fix
- * these unwanted resets.
- */
- if (evt & USB_CHG_EVENT_VBUS) {
- pi3usb9281_enable_interrupts(port);
-#ifndef CONFIG_USB_PD_TCPM_VBUS
- CPRINTS("VBUS p%d %d", port,
- pd_snk_is_vbus_provided(port));
-#endif
- }
- }
-}
-
static void usb_charger_init(void)
{
int i;
diff --git a/driver/pi3usb9281.h b/driver/pi3usb9281.h
index 929476c81b..fc642435c6 100644
--- a/driver/pi3usb9281.h
+++ b/driver/pi3usb9281.h
@@ -71,6 +71,7 @@ struct pi3usb9281_config {
/* Configuration struct defined at board level */
extern struct pi3usb9281_config pi3usb9281_chips[];
+/* TODO: Make many of these functions static after Oak board changes. */
/* Initialize chip and enable interrupts */
void pi3usb9281_init(int port);
@@ -80,9 +81,6 @@ int pi3usb9281_enable_interrupts(int port);
/* Disable all interrupts. */
int pi3usb9281_disable_interrupts(int port);
-/* Set interrupt mask. */
-int pi3usb9281_set_interrupt_mask(int port, uint8_t mask);
-
/* Get and clear current interrupt status. */
int pi3usb9281_get_interrupts(int port);
@@ -92,19 +90,4 @@ int pi3usb9281_get_device_type(int port);
/* Get attached charger status. */
int pi3usb9281_get_charger_status(int port);
-/* Get charger current limit based on device type and charger status. */
-int pi3usb9281_get_ilim(int device_type, int charger_status);
-
-/* Set switch configuration to manual. */
-int pi3usb9281_set_switch_manual(int port, int val);
-
-/* Set bits to enable pins in manual switch register. */
-int pi3usb9281_set_pins(int port, uint8_t mask);
-
-/* Set D+/D-/Vbus switches to open or closed/auto-control. */
-int pi3usb9281_set_switches(int port, int open);
-
-/* Reset PI3USB9281. */
-int pi3usb9281_reset(int port);
-
#endif /* __CROS_EC_PI3USB9281_H */
diff --git a/driver/usb_switch_pi3usb9281.c b/driver/usb_switch_pi3usb9281.c
index 063d7d3983..569438b761 100644
--- a/driver/usb_switch_pi3usb9281.c
+++ b/driver/usb_switch_pi3usb9281.c
@@ -5,13 +5,18 @@
* Pericom PI3USB3281 USB port switch driver.
*/
+#include "charge_manager.h"
+#include "common.h"
#include "console.h"
+#include "ec_commands.h"
#include "gpio.h"
#include "hooks.h"
#include "i2c.h"
+#include "pi3usb9281.h"
#include "task.h"
#include "timer.h"
-#include "pi3usb9281.h"
+#include "usb_charge.h"
+#include "usb_pd.h"
#include "util.h"
/* Console output macros */
@@ -24,6 +29,18 @@
/* Delay values */
#define PI3USB9281_SW_RESET_DELAY 20
+/* Wait after a charger is detected to debounce pin contact order */
+#define PI3USB9281_DETECT_DEBOUNCE_DELAY_MS 1000
+/*
+ * Wait after reset, before re-enabling attach interrupt, so that the
+ * spurious attach interrupt from certain ports is ignored.
+ */
+#define PI3USB9281_RESET_DEBOUNCE_DELAY_MS 100
+
+/* Store the state of our USB data switches so that they can be restored. */
+static int usb_switch_state[CONFIG_USB_PD_PORT_COUNT];
+static struct mutex usb_switch_lock[CONFIG_USB_PD_PORT_COUNT];
+
static void select_chip(int port)
{
struct pi3usb9281_config *chip = &pi3usb9281_chips[port];
@@ -81,6 +98,11 @@ static int pi3usb9281_write_ctrl(int port, uint8_t ctrl)
PI3USB9281_CTRL_RSVD_1);
}
+static int pi3usb9281_set_interrupt_mask(int port, uint8_t mask)
+{
+ return pi3usb9281_write(port, PI3USB9281_REG_INT_MASK, ~mask);
+}
+
void pi3usb9281_init(int port)
{
uint8_t dev_id;
@@ -118,11 +140,6 @@ int pi3usb9281_disable_interrupts(int port)
return rv;
}
-int pi3usb9281_set_interrupt_mask(int port, uint8_t mask)
-{
- return pi3usb9281_write(port, PI3USB9281_REG_INT_MASK, ~mask);
-}
-
int pi3usb9281_get_interrupts(int port)
{
return pi3usb9281_read(port, PI3USB9281_REG_INT);
@@ -138,7 +155,7 @@ int pi3usb9281_get_charger_status(int port)
return pi3usb9281_read(port, PI3USB9281_REG_CHG_STATUS) & 0x1f;
}
-int pi3usb9281_get_ilim(int device_type, int charger_status)
+static int pi3usb9281_get_ilim(int device_type, int charger_status)
{
/* Limit USB port current. 500mA for not listed types. */
int current_limit_ma = 500;
@@ -160,16 +177,7 @@ int pi3usb9281_get_ilim(int device_type, int charger_status)
return current_limit_ma;
}
-int pi3usb9281_get_vbus(int port)
-{
- int vbus = pi3usb9281_read(port, PI3USB9281_REG_VBUS);
- if (vbus == 0xee)
- return EC_ERROR_UNKNOWN;
-
- return !!(vbus & 0x2);
-}
-
-int pi3usb9281_reset(int port)
+static int pi3usb9281_reset(int port)
{
int rv = pi3usb9281_write(port, PI3USB9281_REG_RESET, 0x1);
@@ -180,7 +188,7 @@ int pi3usb9281_reset(int port)
return rv;
}
-int pi3usb9281_set_switch_manual(int port, int val)
+static int pi3usb9281_set_switch_manual(int port, int val)
{
uint8_t ctrl = pi3usb9281_read(port, PI3USB9281_REG_CONTROL);
@@ -195,12 +203,12 @@ int pi3usb9281_set_switch_manual(int port, int val)
return pi3usb9281_write_ctrl(port, ctrl);
}
-int pi3usb9281_set_pins(int port, uint8_t val)
+static int pi3usb9281_set_pins(int port, uint8_t val)
{
return pi3usb9281_write(port, PI3USB9281_REG_MANUAL, val);
}
-int pi3usb9281_set_switches(int port, int open)
+static int pi3usb9281_set_switches(int port, int open)
{
uint8_t ctrl = pi3usb9281_read(port, PI3USB9281_REG_CONTROL);
@@ -214,3 +222,171 @@ int pi3usb9281_set_switches(int port, int open)
return pi3usb9281_write_ctrl(port, ctrl);
}
+
+void usb_charger_set_switches(int port, enum usb_switch setting)
+{
+ /* If switch is not changing then return */
+ if (setting == usb_switch_state[port])
+ return;
+
+ mutex_lock(&usb_switch_lock[port]);
+ if (setting != USB_SWITCH_RESTORE)
+ usb_switch_state[port] = setting;
+
+ pi3usb9281_set_switches(port, usb_switch_state[port]);
+
+ mutex_unlock(&usb_switch_lock[port]);
+}
+
+static void bc12_detect(int port)
+{
+ int device_type, charger_status;
+ struct charge_port_info charge;
+ int type;
+
+ charge.voltage = USB_CHARGER_VOLTAGE_MV;
+
+ if (usb_charger_port_is_sourcing_vbus(port)) {
+ /* If we're sourcing VBUS then we're not charging */
+ device_type = charger_status = 0;
+ } else {
+ /* Set device type */
+ device_type = pi3usb9281_get_device_type(port);
+ charger_status = pi3usb9281_get_charger_status(port);
+ }
+
+ /* Debounce pin plug order if we detect a charger */
+ if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) {
+ /* next operation might trigger a detach interrupt */
+ pi3usb9281_disable_interrupts(port);
+ /*
+ * Ensure D+/D- are open before resetting
+ * Note: we can't simply call pi3usb9281_set_switches() because
+ * another task might override it and set the switches closed.
+ */
+ pi3usb9281_set_switch_manual(port, 1);
+ pi3usb9281_set_pins(port, 0);
+
+ /* Delay to debounce pin attach order */
+ msleep(PI3USB9281_DETECT_DEBOUNCE_DELAY_MS);
+
+ /*
+ * Trigger chip reset to refresh detection registers.
+ * WARNING: This reset is acceptable for samus_pd,
+ * but may not be acceptable for devices that have
+ * an OTG / device mode, as we may be interrupting
+ * the connection.
+ */
+ pi3usb9281_reset(port);
+ /*
+ * Restore data switch settings - switches return to
+ * closed on reset until restored.
+ */
+ usb_charger_set_switches(port, USB_SWITCH_RESTORE);
+ /* Clear possible disconnect interrupt */
+ pi3usb9281_get_interrupts(port);
+ /* Mask attach interrupt */
+ pi3usb9281_set_interrupt_mask(port,
+ 0xff &
+ ~PI3USB9281_INT_ATTACH);
+ /* Re-enable interrupts */
+ pi3usb9281_enable_interrupts(port);
+ msleep(PI3USB9281_RESET_DEBOUNCE_DELAY_MS);
+
+ /* Clear possible attach interrupt */
+ pi3usb9281_get_interrupts(port);
+ /* Re-enable attach interrupt */
+ pi3usb9281_set_interrupt_mask(port, 0xff);
+
+ /* Re-read ID registers */
+ device_type = pi3usb9281_get_device_type(port);
+ charger_status = pi3usb9281_get_charger_status(port);
+ }
+
+ /* Attachment: decode + update available charge */
+ if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) {
+ if (PI3USB9281_CHG_STATUS_ANY(charger_status))
+ type = CHARGE_SUPPLIER_PROPRIETARY;
+ else if (device_type & PI3USB9281_TYPE_CDP)
+ type = CHARGE_SUPPLIER_BC12_CDP;
+ else if (device_type & PI3USB9281_TYPE_DCP)
+ type = CHARGE_SUPPLIER_BC12_DCP;
+ else if (device_type & PI3USB9281_TYPE_SDP)
+ type = CHARGE_SUPPLIER_BC12_SDP;
+ else
+ type = CHARGE_SUPPLIER_OTHER;
+
+ charge.current = pi3usb9281_get_ilim(device_type,
+ charger_status);
+ charge_manager_update_charge(type, port, &charge);
+ } else { /* Detachment: update available charge to 0 */
+ charge.current = 0;
+ charge_manager_update_charge(
+ CHARGE_SUPPLIER_PROPRIETARY,
+ port,
+ &charge);
+ charge_manager_update_charge(
+ CHARGE_SUPPLIER_BC12_CDP,
+ port,
+ &charge);
+ charge_manager_update_charge(
+ CHARGE_SUPPLIER_BC12_DCP,
+ port,
+ &charge);
+ charge_manager_update_charge(
+ CHARGE_SUPPLIER_BC12_SDP,
+ port,
+ &charge);
+ charge_manager_update_charge(
+ CHARGE_SUPPLIER_OTHER,
+ port,
+ &charge);
+ }
+
+ /* notify host of power info change */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+}
+
+void usb_charger_task(void)
+{
+ const int attach_mask = PI3USB9281_INT_ATTACH | PI3USB9281_INT_DETACH;
+ int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1);
+ int interrupt;
+ uint32_t evt;
+
+ /* Initialize chip and enable interrupts */
+ pi3usb9281_init(port);
+
+ bc12_detect(port);
+
+ while (1) {
+ /* Wait for interrupt */
+ evt = task_wait_event(-1);
+
+ /* Interrupt from the Pericom chip, determine charger type */
+ if (evt & USB_CHG_EVENT_BC12) {
+ /* Read interrupt register to clear on chip */
+ pi3usb9281_get_interrupts(port);
+ bc12_detect(port);
+ } else if (evt & USB_CHG_EVENT_INTR) {
+ /* Check the interrupt register, and clear on chip */
+ interrupt = pi3usb9281_get_interrupts(port);
+ if (interrupt & attach_mask)
+ bc12_detect(port);
+ }
+
+ /*
+ * Re-enable interrupts on pericom charger detector since the
+ * chip may periodically reset itself, and come back up with
+ * registers in default state. TODO(crosbug.com/p/33823): Fix
+ * these unwanted resets.
+ */
+ if (evt & USB_CHG_EVENT_VBUS) {
+ pi3usb9281_enable_interrupts(port);
+#ifndef CONFIG_USB_PD_TCPM_VBUS
+ CPRINTS("VBUS p%d %d", port,
+ pd_snk_is_vbus_provided(port));
+#endif
+ }
+ }
+}
diff --git a/include/config.h b/include/config.h
index 73c42f08d5..709ee2e41e 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1947,7 +1947,7 @@
/* Support USB blob handler. */
#undef CONFIG_USB_BLOB
-/* Common USB / BC1.2 charger task */
+/* Common USB / BC1.2 charger detection routines */
#undef CONFIG_USB_CHARGER
/* Enable USB serial console module. */