diff options
Diffstat (limited to 'driver/bc12/pi3usb9201.c')
-rw-r--r-- | driver/bc12/pi3usb9201.c | 410 |
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 */ |