void chg_ramp_charge_supplier_change(int port, int supplier, int current, timestamp_t registration_time) { /* * If the last active port was a valid port and the port * has changed, then this may have been an over-current. */ if (active_port != CHARGE_PORT_NONE && port != active_port) { if (oc_info_idx[active_port] == RAMP_COUNT - 1) oc_info_idx[active_port] = 0; else oc_info_idx[active_port]++; ACTIVE_OC_INFO.ts = get_time(); ACTIVE_OC_INFO.sup = active_sup; ACTIVE_OC_INFO.icl = active_icl; } /* Set new active port, set ramp state, and wake ramp task */ active_port = port; active_sup = supplier; /* Set min and max input current limit based on if ramp is allowed */ if (board_is_ramp_allowed(active_sup)) { min_icl = RAMP_CURR_START_MA; max_icl = board_get_ramp_current_limit(active_sup, current); } else { min_icl = max_icl = current; } reg_time = registration_time; if (ramp_st != CHG_RAMP_STABILIZE) { ramp_st = (active_port == CHARGE_PORT_NONE) ? CHG_RAMP_DISCONNECTED : CHG_RAMP_CHARGE_DETECT_DELAY; CPRINTS("Ramp reset: st%d", ramp_st); task_wake(TASK_ID_CHG_RAMP); } }
/** * Charge manager refresh -- responsible for selecting the active charge port * and charge power. Called as a deferred task. */ static void charge_manager_refresh(void) { int new_supplier, new_port; int new_charge_current, new_charge_current_uncapped; int new_charge_voltage, i; int updated_new_port = CHARGE_PORT_NONE; int updated_old_port = CHARGE_PORT_NONE; int ceil; /* Hunt for an acceptable charge port */ while (1) { charge_manager_get_best_charge_port(&new_port, &new_supplier); /* * If the port or supplier changed, make an attempt to switch to * the port. We will re-set the active port on a supplier change * to give the board-level function another chance to reject * the port, for example, if the port has become a charge * source. */ if ((new_port == charge_port && new_supplier == charge_supplier) || board_set_active_charge_port(new_port) == EC_SUCCESS) break; /* 'Dont charge' request must be accepted */ ASSERT(new_port != CHARGE_PORT_NONE); /* * Zero the available charge on the rejected port so that * it is no longer chosen. */ for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) available_charge[i][new_port].current = 0; } /* * Clear override if it wasn't selected as the 'best' port -- it means * that no charge is available on the port, or the port was rejected. */ if (override_port >= 0 && override_port != new_port) override_port = OVERRIDE_OFF; if (new_supplier == CHARGE_SUPPLIER_NONE) { new_charge_current = 0; new_charge_current_uncapped = 0; new_charge_voltage = 0; } else { new_charge_current_uncapped = available_charge[new_supplier][new_port].current; #ifdef CONFIG_CHARGE_RAMP_HW /* * Allow to set the maximum current value, so the hardware can * know the range of acceptable current values for its ramping. */ if (board_is_ramp_allowed(new_supplier)) new_charge_current_uncapped = board_get_ramp_current_limit(new_supplier, new_charge_current_uncapped); #endif /* CONFIG_CHARGE_RAMP_HW */ /* Enforce port charge ceiling. */ ceil = charge_manager_get_ceil(new_port); if (ceil != CHARGE_CEIL_NONE) new_charge_current = MIN(ceil, new_charge_current_uncapped); else new_charge_current = new_charge_current_uncapped; new_charge_voltage = available_charge[new_supplier][new_port].voltage; } /* Change the charge limit + charge port/supplier if modified. */ if (new_port != charge_port || new_charge_current != charge_current || new_supplier != charge_supplier) { #ifdef HAS_TASK_CHG_RAMP chg_ramp_charge_supplier_change( new_port, new_supplier, new_charge_current, registration_time[new_port]); #else #ifdef CONFIG_CHARGE_RAMP_HW /* Enable or disable charge ramp */ charger_set_hw_ramp(board_is_ramp_allowed(new_supplier)); #endif board_set_charge_limit(new_charge_current); #endif CPRINTS("CL: p%d s%d i%d v%d", new_port, new_supplier, new_charge_current, new_charge_voltage); } /* * Signal new power request only if the port changed, the voltage * on the same port changed, or the actual uncapped current * on the same port changed (don't consider ceil). */ if (new_port != CHARGE_PORT_NONE && (new_port != charge_port || new_charge_current_uncapped != charge_current_uncapped || new_charge_voltage != charge_voltage)) updated_new_port = new_port; /* If charge port changed, cleanup old port */ if (charge_port != new_port && charge_port != CHARGE_PORT_NONE) { /* Check if need power swap */ charge_manager_switch_to_source(charge_port); /* Signal new power request on old port */ updated_old_port = charge_port; } /* Update globals to reflect current state. */ charge_current = new_charge_current; charge_current_uncapped = new_charge_current_uncapped; charge_voltage = new_charge_voltage; charge_supplier = new_supplier; charge_port = new_port; #ifdef CONFIG_USB_PD_LOGGING /* * Write a log under the following conditions: * 1. A port becomes active or * 2. A port becomes inactive or * 3. The active charge port power limit changes or * 4. Any supplier change on an inactive port */ if (updated_new_port != CHARGE_PORT_NONE) save_log[updated_new_port] = 1; /* Don't log non-meaningful changes on charge port */ else if (charge_port != CHARGE_PORT_NONE) save_log[charge_port] = 0; if (updated_old_port != CHARGE_PORT_NONE) save_log[updated_old_port] = 1; for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; ++i) if (save_log[i]) charge_manager_save_log(i); #endif /* New power requests must be set only after updating the globals. */ if (updated_new_port != CHARGE_PORT_NONE) pd_set_new_power_request(updated_new_port); if (updated_old_port != CHARGE_PORT_NONE) pd_set_new_power_request(updated_old_port); }
/** * Fills passed power_info structure with current info about the passed port. */ static void charge_manager_fill_power_info(int port, struct ec_response_usb_pd_power_info *r) { int sup = CHARGE_SUPPLIER_NONE; int i; /* Determine supplier information to show. */ if (port == charge_port) sup = charge_supplier; else /* Find highest priority supplier */ for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) if (available_charge[i][port].current > 0 && available_charge[i][port].voltage > 0 && (sup == CHARGE_SUPPLIER_NONE || supplier_priority[i] < supplier_priority[sup] || (supplier_priority[i] == supplier_priority[sup] && POWER(available_charge[i][port]) > POWER(available_charge[sup] [port])))) sup = i; /* Fill in power role */ if (charge_port == port) r->role = USB_PD_PORT_POWER_SINK; else if (pd_is_connected(port) && pd_get_role(port) == PD_ROLE_SOURCE) r->role = USB_PD_PORT_POWER_SOURCE; else if (sup != CHARGE_SUPPLIER_NONE) r->role = USB_PD_PORT_POWER_SINK_NOT_CHARGING; else r->role = USB_PD_PORT_POWER_DISCONNECTED; /* Is port partner dual-role capable */ r->dualrole = (dualrole_capability[port] == CAP_DUALROLE); if (sup == CHARGE_SUPPLIER_NONE || r->role == USB_PD_PORT_POWER_SOURCE) { r->type = USB_CHG_TYPE_NONE; r->meas.voltage_max = 0; r->meas.voltage_now = r->role == USB_PD_PORT_POWER_SOURCE ? 5000 : 0; r->meas.current_max = 0; r->max_power = 0; } else { #if defined(HAS_TASK_CHG_RAMP) || defined(CONFIG_CHARGE_RAMP_HW) /* Read ramped current if active charging port */ int use_ramp_current = (charge_port == port); #else const int use_ramp_current = 0; #endif switch (sup) { case CHARGE_SUPPLIER_PD: r->type = USB_CHG_TYPE_PD; break; case CHARGE_SUPPLIER_TYPEC: r->type = USB_CHG_TYPE_C; break; case CHARGE_SUPPLIER_PROPRIETARY: r->type = USB_CHG_TYPE_PROPRIETARY; break; case CHARGE_SUPPLIER_BC12_DCP: r->type = USB_CHG_TYPE_BC12_DCP; break; case CHARGE_SUPPLIER_BC12_CDP: r->type = USB_CHG_TYPE_BC12_CDP; break; case CHARGE_SUPPLIER_BC12_SDP: r->type = USB_CHG_TYPE_BC12_SDP; break; case CHARGE_SUPPLIER_VBUS: r->type = USB_CHG_TYPE_VBUS; break; default: r->type = USB_CHG_TYPE_OTHER; } r->meas.voltage_max = available_charge[sup][port].voltage; if (use_ramp_current) { /* * If charge_ramp has not detected charger yet, * then charger type is unknown. */ if (!chg_ramp_is_detected()) r->type = USB_CHG_TYPE_UNKNOWN; /* Current limit is output of ramp module */ r->meas.current_lim = chg_ramp_get_current_limit(); /* * If ramp is allowed, then the max current depends * on if ramp is stable. If ramp is stable, then * max current is same as input current limit. If * ramp is not stable, then we report the maximum * current we could ramp up to for this supplier. * If ramp is not allowed, max current is just the * available charge current. */ if (board_is_ramp_allowed(sup)) { r->meas.current_max = chg_ramp_is_stable() ? r->meas.current_lim : board_get_ramp_current_limit( sup, available_charge[sup][port].current); } else { r->meas.current_max = available_charge[sup][port].current; } r->max_power = r->meas.current_max * r->meas.voltage_max; } else { r->meas.current_max = r->meas.current_lim = available_charge[sup][port].current; r->max_power = POWER(available_charge[sup][port]); } /* * If we are sourcing power, or sinking but not charging, then * VBUS must be 5V. If we are charging, then read VBUS ADC. */ if (r->role == USB_PD_PORT_POWER_SINK_NOT_CHARGING) r->meas.voltage_now = 5000; else if (ADC_VBUS >= 0) r->meas.voltage_now = adc_read_channel(ADC_VBUS); else /* No VBUS ADC channel - voltage is unknown */ r->meas.voltage_now = 0; } }