/** * Update charge ceiling for a given port. The ceiling can be set independently * for several requestors, and the min. ceil will be enforced. * * @param port Charge port to update. * @param requestor Charge ceiling requestor. * @param ceil Charge ceiling (mA). */ void charge_manager_set_ceil(int port, enum ceil_requestor requestor, int ceil) { ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT && requestor >= 0 && requestor < CEIL_REQUESTOR_COUNT); if (charge_ceil[port][requestor] != ceil) { charge_ceil[port][requestor] = ceil; if (port == charge_port && charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); } }
/** * Select an 'override port', a port which is always the preferred charge port. * Returns EC_SUCCESS on success, ec_error_list status on failure. * * @param port Charge port to select as override, or * OVERRIDE_OFF to select no override port, * or OVERRIDE_DONT_CHARGE to specifc that no * charge port should be selected. */ int charge_manager_set_override(int port) { int retval = EC_SUCCESS; ASSERT(port >= OVERRIDE_DONT_CHARGE && port < CONFIG_USB_PD_PORT_COUNT); CPRINTS("Charge Override: %d", port); /* Supersede any pending delayed overrides. */ if (delayed_override_port != OVERRIDE_OFF) { if (delayed_override_port != port) charge_manager_cleanup_override_port( delayed_override_port); delayed_override_port = OVERRIDE_OFF; hook_call_deferred( charge_override_timeout, -1); } /* Set the override port if it's a sink. */ if (port < 0 || pd_get_role(port) == PD_ROLE_SINK) { if (override_port != port) { charge_manager_cleanup_override_port(override_port); override_port = port; if (charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); } } /* * If the attached device is capable of being a sink, request a * power swap and set the delayed override for swap completion. */ else if (pd_get_role(port) != PD_ROLE_SINK && dualrole_capability[port] == CAP_DUALROLE) { delayed_override_deadline.val = get_time().val + POWER_SWAP_TIMEOUT; delayed_override_port = port; hook_call_deferred( charge_override_timeout, POWER_SWAP_TIMEOUT); pd_request_power_swap(port); /* Can't charge from requested port -- return error. */ } else retval = EC_ERROR_INVAL; return retval; }
/** * Select an 'override port', a port which is always the preferred charge port. * Returns EC_SUCCESS on success, ec_error_list status on failure. * * @param port Charge port to select as override, or * OVERRIDE_OFF to select no override port, * or OVERRIDE_DONT_CHARGE to specifc that no * charge port should be selected. */ int charge_manager_set_override(int port) { int retval = EC_SUCCESS; ASSERT(port >= OVERRIDE_DONT_CHARGE && port < CONFIG_USB_PD_PORT_COUNT); CPRINTS("Charge Override: %d", port); /* * If attempting to change the override port, then return * error. Since we may be in the middle of a power swap on * the original override port, it's too complicated to * guarantee that the original override port is switched back * to source. */ if (delayed_override_port != OVERRIDE_OFF) return EC_ERROR_BUSY; /* Set the override port if it's a sink. */ if (port < 0 || pd_get_role(port) == PD_ROLE_SINK) { if (override_port != port) { override_port = port; if (charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); } } /* * If the attached device is capable of being a sink, request a * power swap and set the delayed override for swap completion. */ else if (pd_get_role(port) != PD_ROLE_SINK && dualrole_capability[port] == CAP_DUALROLE) { delayed_override_deadline.val = get_time().val + POWER_SWAP_TIMEOUT; delayed_override_port = port; hook_call_deferred( charge_override_timeout, POWER_SWAP_TIMEOUT); pd_request_power_swap(port); /* Can't charge from requested port -- return error. */ } else retval = EC_ERROR_INVAL; return retval; }
static void charge_manager_make_change(enum charge_manager_change_type change, int supplier, int port, struct charge_port_info *charge) { int i; int clear_override = 0; /* Determine if this is a change which can affect charge status */ switch (change) { case CHANGE_CHARGE: /* Ignore changes where charge is identical */ if (available_charge[supplier][port].current == charge->current && available_charge[supplier][port].voltage == charge->voltage) return; if (charge->current > 0 && available_charge[supplier][port].current == 0) clear_override = 1; #ifdef CONFIG_USB_PD_LOGGING save_log[port] = 1; #endif break; case CHANGE_DUALROLE: /* * Ignore all except for transition to non-dualrole, * which may occur some time after we see a charge */ #ifndef CONFIG_CHARGE_MANAGER_DRP_CHARGING if (dualrole_capability[port] != CAP_DEDICATED) #endif return; /* Clear override only if a charge is present on the port */ for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) if (available_charge[i][port].current > 0) { clear_override = 1; break; } /* * If there is no charge present on the port, the dualrole * change is meaningless to charge_manager. */ if (!clear_override) return; break; } /* Remove override when a charger is plugged */ if (clear_override && override_port != port #ifndef CONFIG_CHARGE_MANAGER_DRP_CHARGING /* only remove override when it's a dedicated charger */ && dualrole_capability[port] == CAP_DEDICATED #endif ) { override_port = OVERRIDE_OFF; if (delayed_override_port != OVERRIDE_OFF) { delayed_override_port = OVERRIDE_OFF; hook_call_deferred( charge_override_timeout, -1); } } if (change == CHANGE_CHARGE) { available_charge[supplier][port].current = charge->current; available_charge[supplier][port].voltage = charge->voltage; registration_time[port] = get_time(); /* * If we have a charge on our delayed override port within * the deadline, make it our override port. */ if (port == delayed_override_port && charge->current > 0 && pd_get_role(delayed_override_port) == PD_ROLE_SINK && get_time().val < delayed_override_deadline.val) { delayed_override_port = OVERRIDE_OFF; hook_call_deferred(charge_override_timeout, -1); charge_manager_set_override(port); } } /* * Don't call charge_manager_refresh unless all ports + * suppliers have reported in. We don't want to make changes * to our charge port until we are certain we know what is * attached. */ if (charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); }