Skip to content

Commit 7e7877c

Browse files
RD Babieragregkh
authored andcommitted
usb: typec: tcpm: add alt mode enter/exit/vdm support for sop'
Add tcpm_cable_ops for enter, exit, and vdm to the tcpm, which are registered after registering port alt modes through typec_port_register_cable_ops. Enter Mode on SOP' now sends Exit Mode upon failure to report to the driver. tcpm_queue_vdm_unlocked now takes sop type as input. Proper adev_actions in tcpm_pd_svdm are selected for SOP' messages. Signed-off-by: RD Babiera <[email protected]> Reviewed-by: Heikki Krogerus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 41d9d75 commit 7e7877c

File tree

1 file changed

+106
-20
lines changed

1 file changed

+106
-20
lines changed

drivers/usb/typec/tcpm/tcpm.c

Lines changed: 106 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,7 +1556,7 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
15561556
}
15571557

15581558
static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header,
1559-
const u32 *data, int cnt)
1559+
const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
15601560
{
15611561
mutex_lock(&port->lock);
15621562
tcpm_queue_vdm(port, header, data, cnt, TCPC_TX_SOP);
@@ -2144,14 +2144,28 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
21442144
}
21452145
break;
21462146
case CMD_ENTER_MODE:
2147-
if (adev && pdev)
2148-
*adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
2147+
*response_tx_sop_type = rx_sop_type;
2148+
if (rx_sop_type == TCPC_TX_SOP) {
2149+
if (adev && pdev) {
2150+
typec_altmode_update_active(pdev, true);
2151+
*adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
2152+
}
2153+
} else if (rx_sop_type == TCPC_TX_SOP_PRIME) {
2154+
if (adev && pdev_prime) {
2155+
typec_altmode_update_active(pdev_prime, true);
2156+
*adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
2157+
}
2158+
}
21492159
return 0;
21502160
case CMD_EXIT_MODE:
2151-
if (adev && pdev) {
2152-
/* Back to USB Operation */
2153-
*adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
2154-
return 0;
2161+
*response_tx_sop_type = rx_sop_type;
2162+
if (rx_sop_type == TCPC_TX_SOP) {
2163+
if (adev && pdev) {
2164+
typec_altmode_update_active(pdev, false);
2165+
/* Back to USB Operation */
2166+
*adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
2167+
return 0;
2168+
}
21552169
}
21562170
break;
21572171
case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15):
@@ -2284,19 +2298,37 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
22842298
typec_altmode_vdm(adev, p[0], &p[1], cnt);
22852299
break;
22862300
case ADEV_QUEUE_VDM:
2287-
typec_altmode_vdm(adev, p[0], &p[1], cnt);
2301+
if (response_tx_sop_type == TCPC_TX_SOP_PRIME)
2302+
typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt);
2303+
else
2304+
typec_altmode_vdm(adev, p[0], &p[1], cnt);
22882305
break;
22892306
case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL:
2290-
if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
2291-
int svdm_version = typec_get_negotiated_svdm_version(
2292-
port->typec_port);
2293-
if (svdm_version < 0)
2294-
break;
2307+
if (response_tx_sop_type == TCPC_TX_SOP_PRIME) {
2308+
if (typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P,
2309+
p[0], &p[1], cnt)) {
2310+
int svdm_version = typec_get_cable_svdm_version(
2311+
port->typec_port);
2312+
if (svdm_version < 0)
2313+
break;
22952314

2296-
response[0] = VDO(adev->svid, 1, svdm_version,
2297-
CMD_EXIT_MODE);
2298-
response[0] |= VDO_OPOS(adev->mode);
2299-
rlen = 1;
2315+
response[0] = VDO(adev->svid, 1, svdm_version,
2316+
CMD_EXIT_MODE);
2317+
response[0] |= VDO_OPOS(adev->mode);
2318+
rlen = 1;
2319+
}
2320+
} else {
2321+
if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
2322+
int svdm_version = typec_get_negotiated_svdm_version(
2323+
port->typec_port);
2324+
if (svdm_version < 0)
2325+
break;
2326+
2327+
response[0] = VDO(adev->svid, 1, svdm_version,
2328+
CMD_EXIT_MODE);
2329+
response[0] |= VDO_OPOS(adev->mode);
2330+
rlen = 1;
2331+
}
23002332
}
23012333
break;
23022334
case ADEV_ATTENTION:
@@ -2731,7 +2763,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
27312763
header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
27322764
header |= VDO_OPOS(altmode->mode);
27332765

2734-
tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0);
2766+
tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
27352767
return 0;
27362768
}
27372769

@@ -2748,7 +2780,7 @@ static int tcpm_altmode_exit(struct typec_altmode *altmode)
27482780
header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE);
27492781
header |= VDO_OPOS(altmode->mode);
27502782

2751-
tcpm_queue_vdm_unlocked(port, header, NULL, 0);
2783+
tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP);
27522784
return 0;
27532785
}
27542786

@@ -2757,7 +2789,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode,
27572789
{
27582790
struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
27592791

2760-
tcpm_queue_vdm_unlocked(port, header, data, count - 1);
2792+
tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP);
27612793

27622794
return 0;
27632795
}
@@ -2768,6 +2800,58 @@ static const struct typec_altmode_ops tcpm_altmode_ops = {
27682800
.vdm = tcpm_altmode_vdm,
27692801
};
27702802

2803+
2804+
static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop,
2805+
u32 *vdo)
2806+
{
2807+
struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
2808+
int svdm_version;
2809+
u32 header;
2810+
2811+
svdm_version = typec_get_cable_svdm_version(port->typec_port);
2812+
if (svdm_version < 0)
2813+
return svdm_version;
2814+
2815+
header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
2816+
header |= VDO_OPOS(altmode->mode);
2817+
2818+
tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);
2819+
return 0;
2820+
}
2821+
2822+
static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop)
2823+
{
2824+
struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
2825+
int svdm_version;
2826+
u32 header;
2827+
2828+
svdm_version = typec_get_cable_svdm_version(port->typec_port);
2829+
if (svdm_version < 0)
2830+
return svdm_version;
2831+
2832+
header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE);
2833+
header |= VDO_OPOS(altmode->mode);
2834+
2835+
tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME);
2836+
return 0;
2837+
}
2838+
2839+
static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop,
2840+
u32 header, const u32 *data, int count)
2841+
{
2842+
struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
2843+
2844+
tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME);
2845+
2846+
return 0;
2847+
}
2848+
2849+
static const struct typec_cable_ops tcpm_cable_ops = {
2850+
.enter = tcpm_cable_altmode_enter,
2851+
.exit = tcpm_cable_altmode_exit,
2852+
.vdm = tcpm_cable_altmode_vdm,
2853+
};
2854+
27712855
/*
27722856
* PD (data, control) command handling functions
27732857
*/
@@ -7507,6 +7591,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
75077591
typec_port_register_altmodes(port->typec_port,
75087592
&tcpm_altmode_ops, port,
75097593
port->port_altmode, ALTMODE_DISCOVERY_MAX);
7594+
typec_port_register_cable_ops(port->port_altmode, ARRAY_SIZE(port->port_altmode),
7595+
&tcpm_cable_ops);
75107596
port->registered = true;
75117597

75127598
mutex_lock(&port->lock);

0 commit comments

Comments
 (0)