/* * TODO(crbug.com/505480): Setting muxes often involves I2C transcations, * which can block. Consider implementing an asynchronous task. */ void usb_mux_set(int port, enum typec_mux mux_mode, enum usb_switch usb_mode, int polarity) { const struct usb_mux *mux = &usb_muxes[port]; int res; mux_state_t mux_state; #ifdef CONFIG_USB_CHARGER /* Configure USB2.0 */ usb_charger_set_switches(port, usb_mode); #endif /* Configure superspeed lanes */ mux_state = polarity ? mux_mode | MUX_POLARITY_INVERTED : mux_mode; res = mux->driver->set(mux->port_addr, mux_state); if (res) { CPRINTS("Error setting mux port(%d): %d", port, res); return; } if (enable_debug_prints) CPRINTS( "usb/dp mux: port(%d) typec_mux(%d) usb2(%d) polarity(%d)", port, mux_mode, usb_mode, polarity); }
static void usb_charger_bc12_detect(int port) { int device_type, charger_status; struct charge_port_info charge; int type; charge.voltage = USB_CHARGER_VOLTAGE_MV; /* Read interrupt register to clear on chip */ pi3usb9281_get_interrupts(port); if (usb_charger_port_is_sourcing_vbus(port)) { /* If we're sourcing VBUS then we're not charging */ device_type = charger_status = 0; } else { /* Set device type */ device_type = pi3usb9281_get_device_type(port); charger_status = pi3usb9281_get_charger_status(port); } /* Debounce pin plug order if we detect a charger */ if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) { msleep(USB_CHG_DEBOUNCE_DELAY_MS); /* next operation might trigger a detach interrupt */ pi3usb9281_disable_interrupts(port); /* Ensure D+/D- are open before resetting */ pi3usb9281_set_switch_manual(port, 1); pi3usb9281_set_pins(port, 0); /* Let D+/D- relax to their idle state */ msleep(40); /* * Trigger chip reset to refresh detection registers. * WARNING: This reset is acceptable for samus_pd, * but may not be acceptable for devices that have * an OTG / device mode, as we may be interrupting * the connection. */ pi3usb9281_reset(port); /* * Restore data switch settings - switches return to * closed on reset until restored. */ usb_charger_set_switches(port, USB_SWITCH_RESTORE); /* Clear possible disconnect interrupt */ pi3usb9281_get_interrupts(port); /* Mask attach interrupt */ pi3usb9281_set_interrupt_mask(port, 0xff & ~PI3USB9281_INT_ATTACH); /* Re-enable interrupts */ pi3usb9281_enable_interrupts(port); msleep(USB_CHG_RESET_DELAY_MS); /* Clear possible attach interrupt */ pi3usb9281_get_interrupts(port); /* Re-enable attach interrupt */ pi3usb9281_set_interrupt_mask(port, 0xff); /* Re-read ID registers */ device_type = pi3usb9281_get_device_type(port); charger_status = pi3usb9281_get_charger_status(port); } /* Attachment: decode + update available charge */ if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) { if (PI3USB9281_CHG_STATUS_ANY(charger_status)) type = CHARGE_SUPPLIER_PROPRIETARY; else if (device_type & PI3USB9281_TYPE_CDP) type = CHARGE_SUPPLIER_BC12_CDP; else if (device_type & PI3USB9281_TYPE_DCP) type = CHARGE_SUPPLIER_BC12_DCP; else if (device_type & PI3USB9281_TYPE_SDP) type = CHARGE_SUPPLIER_BC12_SDP; else type = CHARGE_SUPPLIER_OTHER; charge.current = pi3usb9281_get_ilim(device_type, charger_status); charge_manager_update_charge(type, port, &charge); } else { /* Detachment: update available charge to 0 */ charge.current = 0; charge_manager_update_charge( CHARGE_SUPPLIER_PROPRIETARY, port, &charge); charge_manager_update_charge( CHARGE_SUPPLIER_BC12_CDP, port, &charge); charge_manager_update_charge( CHARGE_SUPPLIER_BC12_DCP, port, &charge); charge_manager_update_charge( CHARGE_SUPPLIER_BC12_SDP, port, &charge); charge_manager_update_charge( CHARGE_SUPPLIER_OTHER, port, &charge); } /* notify host of power info change */ pd_send_host_event(PD_EVENT_POWER_CHANGE); }