summaryrefslogtreecommitdiff
path: root/common/usb_charger.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usb_charger.c')
-rw-r--r--common/usb_charger.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/common/usb_charger.c b/common/usb_charger.c
new file mode 100644
index 0000000000..bb85fc3c7f
--- /dev/null
+++ b/common/usb_charger.c
@@ -0,0 +1,138 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * USB charger / BC1.2 task. This code assumes that CONFIG_CHARGE_MANAGER
+ * is defined and implemented. PI3USB9281 is the only charger detector
+ * currently supported.
+ */
+
+#include "charge_manager.h"
+#include "common.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "pi3usb9281.h"
+#include "task.h"
+#include "timer.h"
+#include "usb_pd.h"
+
+/* 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
+
+void usb_charger_task(void)
+{
+ int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1);
+#if (CONFIG_USB_PD_PORT_COUNT == 1)
+ int vbus_source = GPIO_USB_C0_5V_EN;
+#else
+ int vbus_source = (port == 0 ? GPIO_USB_C0_5V_EN : GPIO_USB_C1_5V_EN);
+#endif
+ int device_type, charger_status;
+ struct charge_port_info charge;
+ int type;
+ charge.voltage = USB_BC12_CHARGE_VOLTAGE;
+
+ while (1) {
+ /* Read interrupt register to clear on chip */
+ pi3usb9281_get_interrupts(port);
+
+ if (gpio_get_level(vbus_source)) {
+ /* 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)) {
+ 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.
+ */
+ board_set_usb_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);
+
+ /* Wait for interrupt */
+ task_wait_event(-1);
+ }
+}