pd: charge_manager: make new VBUS charge supplier

Make new VBUS charge supplier for Samus and Ryu which allows
default 500mA charging when VBUS is present. Before this was
accomplished via the type-C supplier, but type-C supplier should
only be used for 1.5A and 3A pull-up. VBUS supplier is lowest
priority so that any other supplier will take precedence over
the default charging rate.

This work is done in preparation for charge_ramp module where
we don't want to ramp for typeC supplier.

BUG=chrome-os-partner:34946
BRANCH=samus
TEST=make sure we can boot without battery on samus, and test
other chargers including legacy chargers, zinger, and donette.

Change-Id: I89f1e9520e4bf9e5debbaf8dd2de1262154eecf8
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/250312
Reviewed-by: Shawn N <shawnn@chromium.org>
This commit is contained in:
Alec Berg
2015-02-16 11:27:58 -08:00
committed by ChromeOS Commit Bot
parent f41d33b1d7
commit ac5f11bf84
5 changed files with 109 additions and 64 deletions

View File

@@ -33,6 +33,9 @@
#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
/* Default input current limit when VBUS is present */
#define DEFAULT_CURR_LIMIT 500 /* mA */
static void vbus_log(void)
{
CPRINTS("VBUS %d", gpio_get_level(GPIO_CHGR_ACOK));
@@ -41,6 +44,19 @@ DECLARE_DEFERRED(vbus_log);
void vbus_evt(enum gpio_signal signal)
{
struct charge_port_info charge;
int vbus_level = gpio_get_level(signal);
/*
* If VBUS is low, or VBUS is high and we are not outputting VBUS
* ourselves, then update the VBUS supplier.
*/
if (!vbus_level || !gpio_get_level(GPIO_USBC_5V_EN)) {
charge.voltage = USB_BC12_CHARGE_VOLTAGE;
charge.current = vbus_level ? DEFAULT_CURR_LIMIT : 0;
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, &charge);
}
hook_call_deferred(vbus_log, 0);
if (task_start_called())
task_wake(TASK_ID_PD);
@@ -163,18 +179,28 @@ BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
/* Initialize board. */
static void board_init(void)
{
struct charge_port_info charge;
struct charge_port_info charge_none, charge_vbus;
/* Initialize all pericom charge suppliers to 0 */
charge.voltage = USB_BC12_CHARGE_VOLTAGE;
charge.current = 0;
charge_none.voltage = USB_BC12_CHARGE_VOLTAGE;
charge_none.current = 0;
charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY,
0,
&charge);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, 0, &charge);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, 0, &charge);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, 0, &charge);
charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, 0, &charge);
&charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, 0, &charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, 0, &charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, 0, &charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, 0, &charge_none);
/* Initialize VBUS supplier based on whether or not VBUS is present */
charge_vbus.voltage = USB_BC12_CHARGE_VOLTAGE;
charge_vbus.current = DEFAULT_CURR_LIMIT;
if (gpio_get_level(GPIO_CHGR_ACOK))
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0,
&charge_vbus);
else
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0,
&charge_none);
/* Enable pericom BC1.2 interrupts. */
gpio_enable_interrupt(GPIO_USBC_BC12_INT_L);
@@ -230,7 +256,8 @@ const int supplier_priority[] = {
[CHARGE_SUPPLIER_BC12_DCP] = 1,
[CHARGE_SUPPLIER_BC12_CDP] = 2,
[CHARGE_SUPPLIER_BC12_SDP] = 3,
[CHARGE_SUPPLIER_OTHER] = 3
[CHARGE_SUPPLIER_OTHER] = 3,
[CHARGE_SUPPLIER_VBUS] = 4
};
BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT);
@@ -333,9 +360,10 @@ DECLARE_DEFERRED(board_charge_manager_override_timeout);
int board_set_active_charge_port(int charge_port)
{
int ret = EC_SUCCESS;
/* check if we are source vbus on that port */
int source = gpio_get_level(GPIO_USBC_5V_EN);
if (charge_port >= 0 && charge_port < PD_PORT_COUNT &&
pd_get_role(charge_port) != PD_ROLE_SINK) {
if (charge_port >= 0 && charge_port < PD_PORT_COUNT && source) {
CPRINTS("Port %d is not a sink, skipping enable", charge_port);
charge_port = CHARGE_PORT_NONE;
ret = EC_ERROR_INVAL;

View File

@@ -140,6 +140,7 @@ enum charge_supplier {
CHARGE_SUPPLIER_BC12_SDP,
CHARGE_SUPPLIER_PROPRIETARY,
CHARGE_SUPPLIER_OTHER,
CHARGE_SUPPLIER_VBUS,
CHARGE_SUPPLIER_COUNT
};

View File

@@ -32,6 +32,9 @@
/* Amount to offset the input current limit when sending to EC */
#define INPUT_CURRENT_LIMIT_OFFSET_MA 192
/* Default input current limit when VBUS is present */
#define DEFAULT_CURR_LIMIT 500 /* mA */
/* Chipset power state */
static enum power_state ps;
@@ -66,7 +69,8 @@ const int supplier_priority[] = {
[CHARGE_SUPPLIER_BC12_DCP] = 1,
[CHARGE_SUPPLIER_BC12_CDP] = 2,
[CHARGE_SUPPLIER_BC12_SDP] = 3,
[CHARGE_SUPPLIER_OTHER] = 3
[CHARGE_SUPPLIER_OTHER] = 3,
[CHARGE_SUPPLIER_VBUS] = 4
};
BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT);
@@ -86,6 +90,19 @@ DECLARE_DEFERRED(pericom_port1_reenable_interrupts);
void vbus0_evt(enum gpio_signal signal)
{
struct charge_port_info charge;
int vbus_level = gpio_get_level(signal);
/*
* If VBUS is low, or VBUS is high and we are not outputting VBUS
* ourselves, then update the VBUS supplier.
*/
if (!vbus_level || !gpio_get_level(GPIO_USB_C0_5V_EN)) {
charge.voltage = USB_BC12_CHARGE_VOLTAGE;
charge.current = vbus_level ? DEFAULT_CURR_LIMIT : 0;
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, &charge);
}
/*
* Re-enable interrupts on pericom charger detector since the
* chip may periodically reset itself, and come back up with
@@ -99,6 +116,19 @@ void vbus0_evt(enum gpio_signal signal)
void vbus1_evt(enum gpio_signal signal)
{
struct charge_port_info charge;
int vbus_level = gpio_get_level(signal);
/*
* If VBUS is low, or VBUS is high and we are not outputting VBUS
* ourselves, then update the VBUS supplier.
*/
if (!vbus_level || !gpio_get_level(GPIO_USB_C1_5V_EN)) {
charge.voltage = USB_BC12_CHARGE_VOLTAGE;
charge.current = vbus_level ? DEFAULT_CURR_LIMIT : 0;
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 1, &charge);
}
/*
* Re-enable interrupts on pericom charger detector since the
* chip may periodically reset itself, and come back up with
@@ -359,7 +389,7 @@ static void board_init(void)
int pd_enable, i;
int slp_s5 = gpio_get_level(GPIO_PCH_SLP_S5_L);
int slp_s3 = gpio_get_level(GPIO_PCH_SLP_S3_L);
struct charge_port_info charge;
struct charge_port_info charge_none, charge_vbus;
/*
* Enable CC lines after all GPIO have been initialized. Note, it is
@@ -373,26 +403,43 @@ static void board_init(void)
gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE);
/* Initialize all pericom charge suppliers to 0 */
charge.voltage = USB_BC12_CHARGE_VOLTAGE;
charge.current = 0;
charge_none.voltage = USB_BC12_CHARGE_VOLTAGE;
charge_none.current = 0;
for (i = 0; i < PD_PORT_COUNT; i++) {
charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY,
i,
&charge);
&charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP,
i,
&charge);
&charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP,
i,
&charge);
&charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP,
i,
&charge);
&charge_none);
charge_manager_update_charge(CHARGE_SUPPLIER_OTHER,
i,
&charge);
&charge_none);
}
/* Initialize VBUS supplier based on whether or not VBUS is present */
charge_vbus.voltage = USB_BC12_CHARGE_VOLTAGE;
charge_vbus.current = DEFAULT_CURR_LIMIT;
if (gpio_get_level(GPIO_USB_C0_VBUS_WAKE))
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0,
&charge_vbus);
else
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0,
&charge_none);
if (gpio_get_level(GPIO_USB_C1_VBUS_WAKE))
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 1,
&charge_vbus);
else
charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 1,
&charge_none);
/* Enable pericom BC1.2 interrupts. */
gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L);
gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L);
@@ -621,8 +668,11 @@ int board_set_active_charge_port(int charge_port)
{
/* charge port is a realy physical port */
int is_real_port = (charge_port >= 0 && charge_port < PD_PORT_COUNT);
/* check if we are source vbus on that port */
int source = gpio_get_level(charge_port == 0 ? GPIO_USB_C0_5V_EN :
GPIO_USB_C1_5V_EN);
if (is_real_port && pd_get_role(charge_port) != PD_ROLE_SINK) {
if (is_real_port && source) {
CPRINTS("Skip enable p%d", charge_port);
return EC_ERROR_INVAL;
}

View File

@@ -107,6 +107,7 @@ enum charge_supplier {
CHARGE_SUPPLIER_BC12_SDP,
CHARGE_SUPPLIER_PROPRIETARY,
CHARGE_SUPPLIER_OTHER,
CHARGE_SUPPLIER_VBUS,
CHARGE_SUPPLIER_COUNT
};

View File

@@ -228,7 +228,6 @@ static int pd_src_cap_cnt[PD_PORT_COUNT];
#define PD_FLAGS_PREVIOUS_PD_CONN (1 << 8) /* previously PD connected */
#define PD_FLAGS_CHECK_PR_ROLE (1 << 9) /* check power role in READY */
#define PD_FLAGS_CHECK_DR_ROLE (1 << 10)/* check data role in READY */
#define PD_FLAGS_VBUS_PRESENT (1 << 11)/* vbus present in sink disconn. */
/* Flags to clear on a disconnect */
#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \
PD_FLAGS_PARTNER_DR_DATA | \
@@ -238,8 +237,7 @@ static int pd_src_cap_cnt[PD_PORT_COUNT];
PD_FLAGS_EXPLICIT_CONTRACT | \
PD_FLAGS_PREVIOUS_PD_CONN | \
PD_FLAGS_CHECK_PR_ROLE | \
PD_FLAGS_CHECK_DR_ROLE | \
PD_FLAGS_VBUS_PRESENT)
PD_FLAGS_CHECK_DR_ROLE)
static struct pd_protocol {
/* current port power role (SOURCE or SINK) */
@@ -387,14 +385,12 @@ static inline void set_state(int port, enum pd_states next_state)
#ifdef CONFIG_USB_PD_DUAL_ROLE
if (next_state == PD_STATE_SRC_DISCONNECTED ||
next_state == PD_STATE_SNK_DISCONNECTED) {
if (pd[port].flags & PD_FLAGS_VBUS_PRESENT) {
/* Clear the input current limit */
pd_set_input_current_limit(port, 0, 0);
/* Clear the input current limit */
pd_set_input_current_limit(port, 0, 0);
#ifdef CONFIG_CHARGE_MANAGER
typec_set_input_current_limit(port, 0, 0);
charge_manager_set_ceil(port, CHARGE_CEIL_NONE);
typec_set_input_current_limit(port, 0, 0);
charge_manager_set_ceil(port, CHARGE_CEIL_NONE);
#endif
}
#else /* CONFIG_USB_PD_DUAL_ROLE */
if (next_state == PD_STATE_SRC_DISCONNECTED) {
#endif
@@ -1134,7 +1130,6 @@ static void handle_ctrl_request(int port, uint16_t head,
/* reset message ID and swap roles */
pd[port].msg_id = 0;
pd[port].power_role = PD_ROLE_SINK;
pd[port].flags |= PD_FLAGS_VBUS_PRESENT;
set_state(port, PD_STATE_SNK_DISCOVERY);
} else if (pd[port].task_state == PD_STATE_SNK_DISCOVERY) {
/* Don't know what power source is ready. Reset. */
@@ -1714,8 +1709,6 @@ static inline int get_typec_current_limit(int cc_voltage)
charge = 3000;
else if (cc_voltage > TYPE_C_SRC_1500_THRESHOLD)
charge = 1500;
else if (cc_voltage > PD_SNK_VA)
charge = 500;
else
charge = 0;
@@ -1798,19 +1791,10 @@ void pd_task(void)
#endif
#ifdef CONFIG_CHARGE_MANAGER
/* Initialize PD supplier current limit to 0 */
/* Initialize PD and type-C supplier current limits to 0 */
pd_set_input_current_limit(port, 0, 0);
typec_set_input_current_limit(port, 0, 0);
charge_manager_update_dualrole(port, CAP_UNKNOWN);
#ifdef CONFIG_USB_PD_DUAL_ROLE
/* If sink, set initial type-C current limit based on vbus */
if (pd_snk_is_vbus_provided(port)) {
typec_set_input_current_limit(port, 500, TYPE_C_VOLTAGE);
pd[port].flags |= PD_FLAGS_VBUS_PRESENT;
} else {
typec_set_input_current_limit(port, 0, 0);
pd[port].flags &= ~PD_FLAGS_VBUS_PRESENT;
}
#endif
#endif
while (1) {
@@ -2303,24 +2287,6 @@ void pd_task(void)
case PD_STATE_SNK_DISCONNECTED:
timeout = 10*MSEC;
#ifdef CONFIG_CHARGE_MANAGER
/*
* If VBUS, use default 500mA limit, otherwise
* set current limit to 0. This is necessary for
* an accessory that provides power with no Rp.
*/
if (pd_snk_is_vbus_provided(port) &&
!(pd[port].flags & PD_FLAGS_VBUS_PRESENT)) {
typec_set_input_current_limit(port, 500,
TYPE_C_VOLTAGE);
pd[port].flags |= PD_FLAGS_VBUS_PRESENT;
} else if (!pd_snk_is_vbus_provided(port) &&
(pd[port].flags & PD_FLAGS_VBUS_PRESENT)) {
typec_set_input_current_limit(port, 0, 0);
pd[port].flags &= ~PD_FLAGS_VBUS_PRESENT;
}
#endif
/* Source connection monitoring */
cc1_volt = pd_adc_read(port, 0);
cc2_volt = pd_adc_read(port, 1);
@@ -2385,8 +2351,7 @@ void pd_task(void)
port, typec_curr, TYPE_C_VOLTAGE);
#endif
pd[port].flags |= PD_FLAGS_CHECK_PR_ROLE |
PD_FLAGS_CHECK_DR_ROLE |
PD_FLAGS_VBUS_PRESENT;
PD_FLAGS_CHECK_DR_ROLE;
set_state(port, PD_STATE_SNK_DISCOVERY);
timeout = 10*MSEC;
hook_call_deferred(