summaryrefslogtreecommitdiff
path: root/driver/bc12/pi3usb9201.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/bc12/pi3usb9201.c')
-rw-r--r--driver/bc12/pi3usb9201.c410
1 files changed, 0 insertions, 410 deletions
diff --git a/driver/bc12/pi3usb9201.c b/driver/bc12/pi3usb9201.c
deleted file mode 100644
index 2a9986f823..0000000000
--- a/driver/bc12/pi3usb9201.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/* Copyright 2019 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.
- */
-
-/* PI3USB9201 USB BC 1.2 Charger Detector driver. */
-
-#include "pi3usb9201.h"
-#include "charge_manager.h"
-#include "chipset.h"
-#include "common.h"
-#include "console.h"
-#include "gpio.h"
-#include "power.h"
-#include "task.h"
-#include "timer.h"
-#include "usb_charge.h"
-#include "usb_pd.h"
-#include "util.h"
-
-#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
-
-enum pi3usb9201_client_sts {
- CHG_OTHER = 0,
- CHG_2_4A,
- CHG_2_0A,
- CHG_1_0A,
- CHG_RESERVED,
- CHG_CDP,
- CHG_SDP,
- CHG_DCP,
-};
-
-struct bc12_status {
- enum charge_supplier supplier;
- int current_limit;
-};
-
-/* Used to store last BC1.2 detection result */
-static enum charge_supplier bc12_supplier[CONFIG_USB_PD_PORT_MAX_COUNT];
-
-/*
- * The USB Type-C specification limits the maximum amount of current from BC 1.2
- * suppliers to 1.5A. Technically, proprietary methods are not allowed, but we
- * will continue to allow those.
- */
-static const struct bc12_status bc12_chg_limits[] = {
- [CHG_OTHER] = {CHARGE_SUPPLIER_OTHER, 500},
- [CHG_2_4A] = {CHARGE_SUPPLIER_PROPRIETARY, USB_CHARGER_MAX_CURR_MA},
- [CHG_2_0A] = {CHARGE_SUPPLIER_PROPRIETARY, USB_CHARGER_MAX_CURR_MA},
- [CHG_1_0A] = {CHARGE_SUPPLIER_PROPRIETARY, 1000},
- [CHG_RESERVED] = {CHARGE_SUPPLIER_NONE, 0},
- [CHG_CDP] = {CHARGE_SUPPLIER_BC12_CDP, USB_CHARGER_MAX_CURR_MA},
- [CHG_SDP] = {CHARGE_SUPPLIER_BC12_SDP, 500},
-#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
- /*
- * If ramping is supported, then for DCP set the current limit to be the
- * max supported for the port by the board or 1.5A (whichever is lower).
- * Although, the BC 1.2 specification allows DCP suppliers to ramp to
- * much higher currents, the USB Type-C specification limits the
- * maximum current allowed for BC 1.2 suppliers to 1.5A.
- */
- [CHG_DCP] = {CHARGE_SUPPLIER_BC12_DCP, USB_CHARGER_MAX_CURR_MA},
-#else
- [CHG_DCP] = {CHARGE_SUPPLIER_BC12_DCP, 500},
-#endif
-};
-
-static inline int raw_read8(int port, int offset, int *value)
-{
- return i2c_read8(pi3usb9201_bc12_chips[port].i2c_port,
- pi3usb9201_bc12_chips[port].i2c_addr_flags,
- offset, value);
-}
-
-static int pi3usb9201_raw(int port, int reg, int mask, int val)
-{
- /* Clear mask and then set val in i2c reg value */
- return i2c_field_update8(pi3usb9201_bc12_chips[port].i2c_port,
- pi3usb9201_bc12_chips[port].i2c_addr_flags,
- reg, mask, val);
-}
-
-static int pi3usb9201_interrupt_mask(int port, int enable)
-{
- return pi3usb9201_raw(port, PI3USB9201_REG_CTRL_1,
- PI3USB9201_REG_CTRL_1_INT_MASK,
- enable);
-}
-
-static int pi3usb9201_bc12_detect_ctrl(int port, int enable)
-{
- return pi3usb9201_raw(port, PI3USB9201_REG_CTRL_2,
- PI3USB9201_REG_CTRL_2_START_DET,
- enable ? PI3USB9201_REG_CTRL_2_START_DET : 0);
-}
-
-static int pi3usb9201_set_mode(int port, int desired_mode)
-{
- return pi3usb9201_raw(port, PI3USB9201_REG_CTRL_1,
- PI3USB9201_REG_CTRL_1_MODE_MASK,
- desired_mode << PI3USB9201_REG_CTRL_1_MODE_SHIFT);
-}
-
-static int pi3usb9201_get_mode(int port, int *mode)
-{
- int rv;
-
- rv = raw_read8(port, PI3USB9201_REG_CTRL_1, mode);
- if (rv)
- return rv;
-
- *mode &= PI3USB9201_REG_CTRL_1_MODE_MASK;
- *mode >>= PI3USB9201_REG_CTRL_1_MODE_SHIFT;
-
- return EC_SUCCESS;
-}
-
-static int pi3usb9201_get_status(int port, int *client, int *host)
-{
- int rv;
- int status;
-
- rv = raw_read8(port, PI3USB9201_REG_CLIENT_STS, &status);
- if (client)
- *client = status;
- rv |= raw_read8(port, PI3USB9201_REG_HOST_STS, &status);
- if (host)
- *host = status;
-
- return rv;
-}
-
-static void bc12_update_supplier(enum charge_supplier supplier, int port,
- struct charge_port_info *new_chg)
-{
- /*
- * If most recent supplier type is not CHARGE_SUPPLIER_NONE, then the
- * charge manager table entry for that supplier type needs to be cleared
- * out.
- */
- if (bc12_supplier[port] != CHARGE_SUPPLIER_NONE)
- charge_manager_update_charge(bc12_supplier[port], port, NULL);
- /* Now update the current supplier type */
- bc12_supplier[port] = supplier;
- /* If new supplier type != NONE, then notify charge manager */
- if (supplier != CHARGE_SUPPLIER_NONE)
- charge_manager_update_charge(supplier, port, new_chg);
-}
-
-static void bc12_update_charge_manager(int port, int client_status)
-{
- struct charge_port_info new_chg;
- enum charge_supplier supplier;
- int bit_pos;
-
- /* Set charge voltage to 5V */
- new_chg.voltage = USB_CHARGER_VOLTAGE_MV;
-
- /*
- * Find set bit position. Note that this funciton is only called if a
- * bit was set in client_status, so bit_pos won't be negative.
- */
- bit_pos = __builtin_ffs(client_status) - 1;
-
- new_chg.current = bc12_chg_limits[bit_pos].current_limit;
- supplier = bc12_chg_limits[bit_pos].supplier;
-
- CPRINTS("pi3usb9201[p%d]: sts = 0x%x, lim = %d mA, supplier = %d",
- port, client_status, new_chg.current, supplier);
- /* bc1.2 is complete and start bit does not auto clear */
- pi3usb9201_bc12_detect_ctrl(port, 0);
- /* Inform charge manager of new supplier type and current limit */
- bc12_update_supplier(supplier, port, &new_chg);
-}
-
-static int bc12_detect_start(int port)
-{
- int rv;
-
- /*
- * Read both status registers to ensure that all interrupt indications
- * are cleared prior to starting bc1.2 detection.
- */
- pi3usb9201_get_status(port, NULL, NULL);
-
- /* Put pi3usb9201 into client mode */
- rv = pi3usb9201_set_mode(port, PI3USB9201_CLIENT_MODE);
- if (rv)
- return rv;
- /* Have pi3usb9201 start bc1.2 detection */
- rv = pi3usb9201_bc12_detect_ctrl(port, 1);
- if (rv)
- return rv;
- /* Unmask interrupt to wake task when detection completes */
- return pi3usb9201_interrupt_mask(port, 0);
-}
-
-static void bc12_power_down(int port)
-{
- /* Put pi3usb9201 into its power down mode */
- pi3usb9201_set_mode(port, PI3USB9201_POWER_DOWN);
- /* The start bc1.2 bit does not auto clear */
- pi3usb9201_bc12_detect_ctrl(port, 0);
- /* Mask interrupts unitl next bc1.2 detection event */
- pi3usb9201_interrupt_mask(port, 1);
- /*
- * Let charge manager know there's no more charge available for the
- * supplier type that was most recently detected.
- */
- bc12_update_supplier(CHARGE_SUPPLIER_NONE, port, NULL);
-
- /* There's nothing else to do if the part is always powered. */
- if (pi3usb9201_bc12_chips[port].flags & PI3USB9201_ALWAYS_POWERED)
- return;
-
-#if defined(CONFIG_POWER_PP5000_CONTROL) && defined(HAS_TASK_CHIPSET)
- /* Indicate PP5000_A rail is not required by USB_CHG task. */
- power_5v_enable(task_get_current(), 0);
-#endif
-}
-
-static void bc12_power_up(int port)
-{
- if (IS_ENABLED(CONFIG_POWER_PP5000_CONTROL) &&
- IS_ENABLED(HAS_TASK_CHIPSET) &&
- !(pi3usb9201_bc12_chips[port].flags & PI3USB9201_ALWAYS_POWERED)) {
- /* Turn on the 5V rail to allow the chip to be powered. */
- power_5v_enable(task_get_current(), 1);
- /*
- * Give the pi3usb9201 time so it's ready to receive i2c
- * messages
- */
- msleep(1);
- }
-
- pi3usb9201_interrupt_mask(port, 1);
-}
-
-static void pi3usb9201_usb_charger_task(const int port)
-{
- uint32_t evt;
- int i;
-
- /*
- * Set most recent bc1.2 detection supplier result to
- * CHARGE_SUPPLIER_NONE for all ports.
- */
- for (i = 0; i < board_get_usb_pd_port_count(); i++)
- bc12_supplier[port] = CHARGE_SUPPLIER_NONE;
-
- /*
- * The is no specific initialization required for the pi3usb9201 other
- * than enabling the interrupt mask.
- */
- pi3usb9201_interrupt_mask(port, 1);
-
- while (1) {
- /* Wait for interrupt */
- evt = task_wait_event(-1);
-
- /* Interrupt from the Pericom chip, determine charger type */
- if (evt & USB_CHG_EVENT_BC12) {
- int client;
- int host;
- int rv;
-
- rv = pi3usb9201_get_status(port, &client, &host);
- if (!rv && client)
- /*
- * Any bit set in client status register
- * indicates that BC1.2 detection has
- * completed.
- */
- bc12_update_charge_manager(port, client);
- if (!rv && host) {
- /*
- * Switch to SDP after device is plugged in to
- * avoid noise (pulse on D-) causing USB
- * disconnect (b/156014140).
- */
- if (host & PI3USB9201_REG_HOST_STS_DEV_PLUG)
- pi3usb9201_set_mode(port,
- PI3USB9201_SDP_HOST_MODE);
- /*
- * Switch to CDP after device is unplugged so
- * we advertise higher power available for next
- * device.
- */
- if (host & PI3USB9201_REG_HOST_STS_DEV_UNPLUG)
- pi3usb9201_set_mode(port,
- PI3USB9201_CDP_HOST_MODE);
- }
- /*
- * TODO(b/124061702): Use host status to allocate power
- * more intelligently.
- */
- }
-
-#ifndef CONFIG_USB_PD_VBUS_DETECT_TCPC
- if (evt & USB_CHG_EVENT_VBUS)
- CPRINTS("VBUS p%d %d", port,
- pd_snk_is_vbus_provided(port));
-#endif
-
- if (evt & USB_CHG_EVENT_DR_UFP) {
- bc12_power_up(port);
- if (bc12_detect_start(port)) {
- struct charge_port_info new_chg;
-
- /*
- * VBUS is present, but starting bc1.2 detection
- * failed for some reason. So limit charge
- * current to default 500 mA for this case.
- */
-
- new_chg.voltage = USB_CHARGER_VOLTAGE_MV;
- new_chg.current = USB_CHARGER_MIN_CURR_MA;
- /* Save supplier type and notify chg manager */
- bc12_update_supplier(CHARGE_SUPPLIER_OTHER,
- port, &new_chg);
- CPRINTS("pi3usb9201[p%d]: bc1.2 failed use "
- "defaults", port);
- }
- }
-
- if (evt & USB_CHG_EVENT_DR_DFP) {
- int mode;
- int rv;
-
- /*
- * Update the charge manager if bc1.2 client mode is
- * currently active.
- */
- bc12_update_supplier(CHARGE_SUPPLIER_NONE, port, NULL);
- /*
- * If the port is in DFP mode, then need to set mode to
- * CDP_HOST which will auto close D+/D- switches.
- */
- bc12_power_up(port);
- rv = pi3usb9201_get_mode(port, &mode);
- if (!rv && (mode != PI3USB9201_CDP_HOST_MODE)) {
- CPRINTS("pi3usb9201[p%d]: CDP_HOST mode", port);
- /*
- * Read both status registers to ensure that all
- * interrupt indications are cleared prior to
- * starting DFP CDP host mode.
- */
- pi3usb9201_get_status(port, NULL, NULL);
- pi3usb9201_set_mode(port,
- PI3USB9201_CDP_HOST_MODE);
- /*
- * Unmask interrupt to wake task when host
- * status changes.
- */
- pi3usb9201_interrupt_mask(port, 0);
- }
- }
-
- if (evt & USB_CHG_EVENT_CC_OPEN)
- bc12_power_down(port);
- }
-}
-
-#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
-static int pi3usb9201_ramp_allowed(int supplier)
-{
- /* Don't allow ramp if charge supplier is OTHER, SDP, or NONE */
- return !(supplier == CHARGE_SUPPLIER_OTHER ||
- supplier == CHARGE_SUPPLIER_BC12_SDP ||
- supplier == CHARGE_SUPPLIER_NONE);
-}
-
-static int pi3usb9201_ramp_max(int supplier, int sup_curr)
-{
- /*
- * Use the level from the bc12_chg_limits table above except for
- * proprietary or CDP and in those cases the charge current from the
- * charge manager is already set at the max determined by bc1.2
- * detection.
- */
- switch (supplier) {
- case CHARGE_SUPPLIER_BC12_DCP:
- return USB_CHARGER_MAX_CURR_MA;
- case CHARGE_SUPPLIER_BC12_CDP:
- case CHARGE_SUPPLIER_PROPRIETARY:
- return sup_curr;
- case CHARGE_SUPPLIER_BC12_SDP:
- default:
- return 500;
- }
-}
-#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */
-
-const struct bc12_drv pi3usb9201_drv = {
- .usb_charger_task = pi3usb9201_usb_charger_task,
-#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
- .ramp_allowed = pi3usb9201_ramp_allowed,
- .ramp_max = pi3usb9201_ramp_max,
-#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */
-};
-
-#ifdef CONFIG_BC12_SINGLE_DRIVER
-/* provide a default bc12_ports[] for backward compatibility */
-struct bc12_config bc12_ports[CHARGE_PORT_COUNT] = {
- [0 ... (CHARGE_PORT_COUNT - 1)] = {
- .drv = &pi3usb9201_drv,
- }
-};
-#endif /* CONFIG_BC12_SINGLE_DRIVER */