Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions drivers/usb/typec/tipd/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)

static void tps6598x_drop_partner(struct tps6598x *tps, u32 status)
{
if (tps->partner_altmode_dp) {
typec_altmode_update_active(tps->partner_altmode_dp, false);
typec_unregister_altmode(tps->partner_altmode_dp);
tps->partner_altmode_dp = NULL;
}
if (!IS_ERR(tps->partner))
typec_unregister_partner(tps->partner);
tps->partner = NULL;
Expand Down Expand Up @@ -1171,6 +1176,11 @@ static void cd321x_update_work(struct work_struct *work)

/* Process partner disconnection or change */
if (!new_connected || partner_changed) {
if (tps->partner_altmode_dp) {
typec_altmode_update_active(tps->partner_altmode_dp, false);
typec_unregister_altmode(tps->partner_altmode_dp);
tps->partner_altmode_dp = NULL;
}
if (!IS_ERR(tps->partner))
typec_unregister_partner(tps->partner);
tps->partner = NULL;
Expand Down Expand Up @@ -1245,6 +1255,29 @@ static void cd321x_update_work(struct work_struct *work)
typec_partner_set_identity(tps->partner);
}

/* The CD321x firmware owns VDM discovery and Enter Mode. Publish the
* discovered DP mode only after it reports an entered DP connection;
* keep Linux's DP Alt Mode driver from issuing a second Enter Mode.
*/
if (dp_connected && !tps->partner_altmode_dp) {
struct typec_altmode_desc desc = {
.svid = USB_TYPEC_DP_SID,
.mode = USB_TYPEC_DP_MODE,
.vdo = le32_to_cpu(st.dp_sid_status.mode_data),
.mode_selection = true,
};

tps->partner_altmode_dp = typec_partner_register_altmode(tps->partner,
&desc);
if (IS_ERR(tps->partner_altmode_dp)) {
ret = PTR_ERR(tps->partner_altmode_dp);
tps->partner_altmode_dp = NULL;
goto retry;
}
}
if (tps->partner_altmode_dp)
typec_altmode_update_active(tps->partner_altmode_dp, dp_connected);

/* Update the TypeC MUX/PHY state */
if (dp_route_was_active && dp_connected && !was_disconnected && !dp_mode_changed &&
st.dp_sid_event) {
Expand Down Expand Up @@ -1997,7 +2030,8 @@ static int cd321x_register_port_altmodes(struct cd321x *cd321x)
memset(&desc, 0, sizeof(desc));
desc.svid = USB_TYPEC_DP_SID;
desc.mode = USB_TYPEC_DP_MODE;
desc.vdo = DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D));
desc.vdo = DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) |
BIT(DP_PIN_ASSIGN_D) | BIT(DP_PIN_ASSIGN_E));
desc.vdo |= DP_CAP_DFP_D;
amode = typec_port_register_altmode(cd321x->tps.port, &desc);
if (IS_ERR(amode))
Expand Down Expand Up @@ -2111,6 +2145,7 @@ EXPORT_SYMBOL_IF_KUNIT(cd321x_init_work);
static int
cd321x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
{
struct fwnode_handle *connector_fwnode;
struct cd321x *cd321x = container_of(tps, struct cd321x, tps);
int ret;

Expand All @@ -2130,9 +2165,12 @@ cd321x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
goto err_unregister_altmodes;
}

cd321x->connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0);
if (IS_ERR(cd321x->connector_fwnode))
cd321x->connector_fwnode = NULL;
if (fwnode_property_present(fwnode, "displayport"))
connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0);
else
connector_fwnode = fwnode_handle_get(fwnode);
if (!IS_ERR_OR_NULL(connector_fwnode))
cd321x->connector_fwnode = connector_fwnode;

cd321x->tbt_switch = cd321x_tbt_switch_get(tps->dev, fwnode);
if (IS_ERR(cd321x->tbt_switch)) {
Expand Down
9 changes: 7 additions & 2 deletions drivers/usb/typec/tipd/spmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,14 @@ static int sn201202x_probe(struct spmi_device *device)
return ret;

ret = tipd_init(tps);
if (ret)
if (ret) {
spmi_command_sleep(device);
return ret;
return ret;
}

/* Events can latch before the IRQ is registered. Consume that state now. */
tps->data->irq_handler(tps->irq, tps);
return 0;
}

static void sn201202x_remove(struct spmi_device *device)
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/typec/tipd/tps6598x.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ struct tps6598x {
const struct tipd_data *data;

struct tipd_debugfs *debugfs;
struct typec_altmode *partner_altmode_dp;
};

/* TPS_REG_USB4_STATUS */
Expand Down