staging: typec: tcpm: set port type callback
PATCH v3 1/11 staging: typec: tcpm: set port type callback
The port type callback call enquires the tcpc_dev if the requested port type is supported. If supported, then performs a tcpm reset if required after setting the tcpm internal port_type variable.
Check against the tcpm port_type instead of checking against caps.type as port_type reflects the current configuration.
---
Changelog since v1:
- Corrected tag
Changelog since v2:
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 52 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 11 deletions(-)
drivers/staging/typec/tcpm.c +41 -11
@@ -197,6 +197,7 @@ struct tcpm_port {bool attached;bool connected; +enum typec_port_type port_type;bool vbus_present;bool vbus_never_low;bool vbus_source;
@@ -334,7 +335,7 @@ struct pd_rx_event {static enum tcpm_state tcpm_default_state (struct tcpm_port *port) { -if (port->typec_caps.type ==TYPEC_PORT_DRP ) { +if (port->port_type ==TYPEC_PORT_DRP ) {if (port->try_role ==TYPEC_SINK )return SNK_UNATTACHED ;else if (port->try_role ==TYPEC_SOURCE )
@@ -342,7 +343,7 @@ static enum tcpm_state tcpm_default_state(struct tcpm_port *port)else if (port->tcpc->config->default_role ==TYPEC_SINK )return SNK_UNATTACHED ;/* Fall through to return SRC_UNATTACHED */ - }else if (port->typec_caps.type ==TYPEC_PORT_UFP ) { + }else if (port->port_type ==TYPEC_PORT_UFP ) {return SNK_UNATTACHED ; }return SRC_UNATTACHED ;
@@ -1458,7 +1459,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,tcpm_set_state (port,SOFT_RESET ,0 );break ;case PD_CTRL_DR_SWAP : -if (port->typec_caps.type !=TYPEC_PORT_DRP ) { +if (port->port_type !=TYPEC_PORT_DRP ) {tcpm_queue_message (port,PD_MSG_CTRL_REJECT );break ; }
@@ -1478,7 +1479,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, }break ;case PD_CTRL_PR_SWAP : -if (port->typec_caps.type !=TYPEC_PORT_DRP ) { +if (port->port_type !=TYPEC_PORT_DRP ) {tcpm_queue_message (port,PD_MSG_CTRL_REJECT );break ; }
@@ -1853,7 +1854,7 @@ static bool tcpm_start_drp_toggling(struct tcpm_port *port)int ret;if (port->tcpc->start_drp_toggling && - port->typec_caps.type ==TYPEC_PORT_DRP ) { + port->port_type ==TYPEC_PORT_DRP ) {tcpm_log_force (port,"Start DRP toggling" ); ret = port->tcpc->start_drp_toggling (port->tcpc,tcpm_rp_cc (port));
@@ -2163,7 +2164,7 @@ static void run_state_machine(struct tcpm_port *port)break ; }tcpm_set_cc (port,tcpm_rp_cc (port)); -if (port->typec_caps.type ==TYPEC_PORT_DRP ) +if (port->port_type ==TYPEC_PORT_DRP )tcpm_set_state (port,SNK_UNATTACHED ,PD_T_DRP_SNK );break ;case SRC_ATTACH_WAIT :
@@ -2320,7 +2321,7 @@ static void run_state_machine(struct tcpm_port *port)break ; }tcpm_set_cc (port,TYPEC_CC_RD ); -if (port->typec_caps.type ==TYPEC_PORT_DRP ) +if (port->port_type ==TYPEC_PORT_DRP )tcpm_set_state (port,SRC_UNATTACHED ,PD_T_DRP_SRC );break ;case SNK_ATTACH_WAIT :
@@ -2411,7 +2412,7 @@ static void run_state_machine(struct tcpm_port *port)* see USB power delivery specification, section 8.3.3.6.1.5.1). */ tcpm_set_state (port,hard_reset_state (port), - port->typec_caps.type ==TYPEC_PORT_DRP ? + port->port_type ==TYPEC_PORT_DRP ?PD_T_DB_DETECT :PD_T_NO_RESPONSE );break ;case SNK_DISCOVERY_DEBOUNCE :
@@ -3167,7 +3168,7 @@ static int tcpm_dr_set(const struct typec_capability *cap,mutex_lock (&port->swap_lock);mutex_lock (&port->lock); -if (port->typec_caps.type !=TYPEC_PORT_DRP ) { +if (port->port_type !=TYPEC_PORT_DRP ) { ret = -EINVAL ; goto port_unlock; }
@@ -3235,7 +3236,7 @@ static int tcpm_pr_set(const struct typec_capability *cap,mutex_lock (&port->swap_lock);mutex_lock (&port->lock); -if (port->typec_caps.type !=TYPEC_PORT_DRP ) { +if (port->port_type !=TYPEC_PORT_DRP ) { ret = -EINVAL ; goto port_unlock; }
@@ -3357,6 +3358,34 @@ static void tcpm_init(struct tcpm_port *port)tcpm_set_state (port,PORT_RESET ,0 ); } +static int tcpm_port_type_set (const struct typec_capability *cap, +enum typec_port_type type) +{ +struct tcpm_port *port =typec_cap_to_tcpm (cap); + +mutex_lock (&port->lock); +if (type == port->port_type) + goto port_unlock; + + port->port_type = type; + +if (!port->connected) { +tcpm_set_state (port,PORT_RESET ,0 ); + }else if (type ==TYPEC_PORT_UFP ) { +if (!(port->pwr_role ==TYPEC_SINK && + port->data_role ==TYPEC_DEVICE )) +tcpm_set_state (port,PORT_RESET ,0 ); + }else if (type ==TYPEC_PORT_DFP ) { +if (!(port->pwr_role ==TYPEC_SOURCE && + port->data_role ==TYPEC_HOST )) +tcpm_set_state (port,PORT_RESET ,0 ); + } + +port_unlock: +mutex_unlock (&port->lock); +return 0 ; +} +void tcpm_tcpc_reset (struct tcpm_port *port) {mutex_lock (&port->lock);
@@ -3504,9 +3533,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->typec_caps.pr_set = tcpm_pr_set; port->typec_caps.vconn_set = tcpm_vconn_set; port->typec_caps.try_role = tcpm_try_role; + port->typec_caps.port_type_set = tcpm_port_type_set; port->partner_desc.identity = &port->partner_ident; - + port->port_type = tcpc->config->type;/* * TODO: * - alt_modes, set_alt_mode
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 2/11 staging: typec: tcpm: Check for port type for Try.SRC/Try.SNK
Enable Try.SRC or Try.SNK only when port_type is DRP. Try.SRC or Try.SNK state machines are not valid for SRC only or SNK only ports.
---
Changelog since v1:
- Corrected tag
Changelog since v2:
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/staging/typec/tcpm.c +4 -2
@@ -328,10 +328,12 @@ struct pd_rx_event { (tcpm_cc_is_audio((port)->cc2) && tcpm_cc_is_open((port)->cc1)))#define tcpm_try_snk (port) \ - ((port)->try_snk_count == 0 && (port)->try_role == TYPEC_SINK) + ((port)->try_snk_count == 0 && (port)->try_role == TYPEC_SINK && \ + (port)->port_type == TYPEC_PORT_DRP)#define tcpm_try_src (port) \ - ((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE) + ((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE && \ + (port)->port_type == TYPEC_PORT_DRP)static enum tcpm_state tcpm_default_state (struct tcpm_port *port) {
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 3/11 staging: typec: tcpm: Prevent TCPM from looping in SRC_TRYWAIT
In reply to Badhri Jagan SridharanAccording to the spec the following is the condition for exiting TryWait.SRC:
"The port shall transition to Attached.SRC when V BUS is at vSafe0V and the SRC.Rd state is detected on exactly one of the CC pins for at least tCCDebounce. The port shall transition to Unattached.SNK after tDRPTry if neither of the CC1 or CC2 pins are in the SRC.Rd state"
TCPM at present keeps re-entering the SRC_TRYWAIT and keeps restarting tDRPTry if the CC presents Rp and disconnects within tCCDebounce.
For example:
[ 447.164308] pending state change SRC_TRYWAIT -> SRC_ATTACHED @ 200 ms [ 447.164386] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected] [ 447.164406] state change SRC_TRYWAIT -> SRC_TRYWAIT [ 447.164573] cc:=3 [ 447.191408] pending state change SRC_TRYWAIT -> SRC_TRYWAIT_UNATTACHED @ 100 ms [ 447.191478] CC1: 0 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected] [ 447.207261] CC1: 0 -> 2, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, connected] [ 447.207306] state change SRC_TRYWAIT -> SRC_TRYWAIT [ 447.207485] cc:=3 [ 447.237283] pending state change SRC_TRYWAIT -> SRC_ATTACHED @ 200 ms [ 447.237357] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected] [ 447.237379] state change SRC_TRYWAIT -> SRC_TRYWAIT [ 447.237532] cc:=3 [ 447.263219] pending state change SRC_TRYWAIT -> SRC_TRYWAIT_UNATTACHED @ 100 ms [ 447.263289] CC1: 0 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected] [ 447.280926] CC1: 0 -> 2, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, connected] [ 447.280970] state change SRC_TRYWAIT -> SRC_TRYWAIT [ 447.281158] cc:=3 [ 447.307767] pending state change SRC_TRYWAIT -> SRC_ATTACHED @ 200 ms [ 447.307838] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected] [ 447.307858] state change SRC_TRYWAIT -> SRC_TRYWAIT
In TCPM, tDRPTry is set tp 100ms (min 75ms and max 150ms) and tCCdebounce is set to 200ms (min 100ms and max 200ms). To overcome the issue, record the time at which the port enters TryWait.SRC(SRC_TRYWAIT) and re-enter SRC_TRYWAIT only when CC keeps debouncing within tDRPTry.
---
Changelog since v1:
- Corrected tag
Changelog since v2:
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 45 ++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-)
drivers/staging/typec/tcpm.c +29 -16
@@ -17,6 +17,7 @@#include <linux/completion.h> #include <linux/debugfs.h> #include <linux/device.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h>
@@ -105,6 +106,7 @@S (SNK_TRY ), \S (SNK_TRY_WAIT ), \S (SRC_TRYWAIT ), \ +S (SRC_TRYWAIT_DEBOUNCE ), \S (SRC_TRYWAIT_UNATTACHED ), \ \ S(SRC_TRY), \
@@ -284,6 +286,9 @@ struct tcpm_port {struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX ];struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX ]; +/* Deadline in jiffies to exit src_try_wait state */ +unsigned long max_wait; +#ifdef CONFIG_DEBUG_FS struct dentry *dentry;struct mutex logbuffer_lock;/* log buffer access lock */
@@ -2204,6 +2209,7 @@ static void run_state_machine(struct tcpm_port *port)if (!tcpm_port_is_sink (port)) {tcpm_set_state (port,SRC_TRYWAIT ,PD_T_PD_DEBOUNCE ); + port->max_wait =0 ;break ; }/* No vbus, cc state is sink or open */
@@ -2211,11 +2217,22 @@ static void run_state_machine(struct tcpm_port *port)break ;case SRC_TRYWAIT :tcpm_set_cc (port,tcpm_rp_cc (port)); -if (!port->vbus_present &&tcpm_port_is_source (port)) -tcpm_set_state (port,SRC_ATTACHED ,PD_T_CC_DEBOUNCE ); -else +if (port->max_wait ==0 ) { + port->max_wait = jiffies + +msecs_to_jiffies (PD_T_DRP_TRY );tcpm_set_state (port,SRC_TRYWAIT_UNATTACHED ,PD_T_DRP_TRY ); + }else { +if (time_is_after_jiffies (port->max_wait)) +tcpm_set_state (port,SRC_TRYWAIT_UNATTACHED , +jiffies_to_msecs (port->max_wait - + jiffies)); +else +tcpm_set_state (port,SNK_UNATTACHED ,0 ); + } +break ; +case SRC_TRYWAIT_DEBOUNCE : +tcpm_set_state (port,SRC_ATTACHED ,PD_T_CC_DEBOUNCE );break ;case SRC_TRYWAIT_UNATTACHED :tcpm_set_state (port,SNK_UNATTACHED ,0 );
@@ -2898,11 +2915,10 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,case SRC_TRYWAIT :/* Hand over to state machine if needed */ if (!port->vbus_present &&tcpm_port_is_source (port)) - new_state =SRC_ATTACHED ; -else - new_state =SRC_TRYWAIT_UNATTACHED ; - -if (new_state != port->delayed_state) +tcpm_set_state (port,SRC_TRYWAIT_DEBOUNCE ,0 ); +break ; +case SRC_TRYWAIT_DEBOUNCE : +if (port->vbus_present || !tcpm_port_is_source (port))tcpm_set_state (port,SRC_TRYWAIT ,0 );break ;case SNK_TRY_WAIT :
@@ -2990,9 +3006,10 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)/* Do nothing, waiting for timeout */ break ;case SRC_TRYWAIT : -/* Hand over to state machine if needed */ -if (port->delayed_state !=SRC_TRYWAIT_UNATTACHED ) -tcpm_set_state (port,SRC_TRYWAIT ,0 ); +/* Do nothing, Waiting for Rd to be detected */ +break ; +case SRC_TRYWAIT_DEBOUNCE : +tcpm_set_state (port,SRC_TRYWAIT ,0 );break ;case SNK_TRY_WAIT :if (tcpm_port_is_sink (port)) {
@@ -3039,11 +3056,7 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)case SRC_TRYWAIT :/* Hand over to state machine if needed */ if (tcpm_port_is_source (port)) - new_state =SRC_ATTACHED ; -else - new_state =SRC_TRYWAIT_UNATTACHED ; -if (new_state != port->delayed_state) -tcpm_set_state (port,SRC_TRYWAIT ,0 ); +tcpm_set_state (port,SRC_TRYWAIT_DEBOUNCE ,0 );break ;case SNK_TRY_WAIT :if (!tcpm_port_is_sink (port))
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 4/11 staging: usb: tcpm: usb: type-c: tcpm: Check for Rp for tPDDebounce
In reply to Badhri Jagan SridharanAccording the spec, the following is the conditions for exiting Try.SNK state:
"The port shall wait for tDRPTry and only then begin monitoring the CC1 and CC2 pins for the SNK.Rp state. The port shall then transition to Attached.SNK when the SNK.Rp state is detected on exactly one of the CC1 or CC2 pins for at least tPDDebounce and V BUS is detected. Alternatively, the port shall transition to TryWait.SRC if SNK.Rp state is not detected for tPDDebounce."
---
Changelog since v1:
- Corrected tag
Changelog since v2:
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 68 ++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 44 deletions(-)
drivers/staging/typec/tcpm.c +24 -44
@@ -105,6 +105,8 @@ \S (SNK_TRY ), \S (SNK_TRY_WAIT ), \ +S (SNK_TRY_WAIT_DEBOUNCE ), \ +S (SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS ), \S (SRC_TRYWAIT ), \S (SRC_TRYWAIT_DEBOUNCE ), \ S(SRC_TRYWAIT_UNATTACHED), \
@@ -2202,18 +2204,24 @@ static void run_state_machine(struct tcpm_port *port)tcpm_set_state (port,SNK_TRY_WAIT ,PD_T_DRP_TRY );break ;case SNK_TRY_WAIT : +if (tcpm_port_is_sink (port)) { +tcpm_set_state (port,SNK_TRY_WAIT_DEBOUNCE ,0 ); + }else { +tcpm_set_state (port,SRC_TRYWAIT ,0 ); + port->max_wait =0 ; + } +break ; +case SNK_TRY_WAIT_DEBOUNCE : +tcpm_set_state (port,SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS , +PD_T_PD_DEBOUNCE ); +break ; +case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS :if (port->vbus_present &&tcpm_port_is_sink (port)) {tcpm_set_state (port,SNK_ATTACHED ,0 ); -break ; - } -if (!tcpm_port_is_sink (port)) { -tcpm_set_state (port,SRC_TRYWAIT , -PD_T_PD_DEBOUNCE ); + }else { +tcpm_set_state (port,SRC_TRYWAIT ,0 ); port->max_wait =0 ; -break ; } -/* No vbus, cc state is sink or open */ -tcpm_set_state (port,SRC_TRYWAIT_UNATTACHED ,PD_T_DRP_TRYWAIT );break ;case SRC_TRYWAIT :tcpm_set_cc (port,tcpm_rp_cc (port));
@@ -2921,20 +2929,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,if (port->vbus_present || !tcpm_port_is_source (port))tcpm_set_state (port,SRC_TRYWAIT ,0 );break ; -case SNK_TRY_WAIT : -if (port->vbus_present &&tcpm_port_is_sink (port)) { -tcpm_set_state (port,SNK_ATTACHED ,0 ); -break ; +case SNK_TRY_WAIT_DEBOUNCE : +if (!tcpm_port_is_sink (port)) { + port->max_wait =0 ; +tcpm_set_state (port,SRC_TRYWAIT ,0 ); } -if (!tcpm_port_is_sink (port)) - new_state =SRC_TRYWAIT ; -else - new_state =SRC_TRYWAIT_UNATTACHED ; - -if (new_state != port->delayed_state) -tcpm_set_state (port,SNK_TRY_WAIT ,0 );break ; -case SRC_TRY :if (tcpm_port_is_source (port))tcpm_set_state (port,SRC_TRY_DEBOUNCE ,0 );
@@ -2974,8 +2974,6 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,static void _tcpm_pd_vbus_on (struct tcpm_port *port) { -enum tcpm_state new_state; -tcpm_log_force (port,"VBUS on" ); port->vbus_present = true;switch (port->state) {
@@ -3011,18 +3009,8 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)case SRC_TRYWAIT_DEBOUNCE :tcpm_set_state (port,SRC_TRYWAIT ,0 );break ; -case SNK_TRY_WAIT : -if (tcpm_port_is_sink (port)) { -tcpm_set_state (port,SNK_ATTACHED ,0 ); -break ; - } -if (!tcpm_port_is_sink (port)) - new_state =SRC_TRYWAIT ; -else - new_state =SRC_TRYWAIT_UNATTACHED ; - -if (new_state != port->delayed_state) -tcpm_set_state (port,SNK_TRY_WAIT ,0 ); +case SNK_TRY_WAIT_DEBOUNCE : +/* Do nothing, waiting for PD_DEBOUNCE to do be done */ break ;case SNK_TRYWAIT :tcpm_set_state (port,SNK_TRYWAIT_VBUS ,0 );
@@ -3035,8 +3023,6 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)static void _tcpm_pd_vbus_off (struct tcpm_port *port) { -enum tcpm_state new_state; -tcpm_log_force (port,"VBUS off" ); port->vbus_present = false; port->vbus_never_low = false;
@@ -3058,14 +3044,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)if (tcpm_port_is_source (port))tcpm_set_state (port,SRC_TRYWAIT_DEBOUNCE ,0 );break ; -case SNK_TRY_WAIT : -if (!tcpm_port_is_sink (port)) - new_state =SRC_TRYWAIT ; -else - new_state =SRC_TRYWAIT_UNATTACHED ; - -if (new_state != port->delayed_state) -tcpm_set_state (port,SNK_TRY_WAIT ,0 ); +case SNK_TRY_WAIT_DEBOUNCE : +/* Do nothing, waiting for PD_DEBOUNCE to do be done */ break ;case SNK_TRYWAIT_VBUS :tcpm_set_state (port,SNK_TRYWAIT ,0 );
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 5/11 staging: typec: tcpm: Follow Try.SRC exit requirements
In reply to Badhri Jagan SridharanAccording to spec:
" 4.5.2.2.9.2 Exiting from Try.SRC State:
The port shall transition to Attached.SRC when the SRC.Rd state is detected on exactly one of the CC1 or CC2 pins for at least tPDDebounce. The port shall transition to TryWait.SNK after tDRPTry and the SRC.Rd state has not been detected."
---
Changelog since v1:
- Corrected tag
Changelog since v2:
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-)
drivers/staging/typec/tcpm.c +28 -5
@@ -112,6 +112,7 @@S (SRC_TRYWAIT_UNATTACHED ), \ \S (SRC_TRY ), \ +S (SRC_TRY_WAIT ), \S (SRC_TRY_DEBOUNCE ), \S (SNK_TRYWAIT ), \ S(SNK_TRYWAIT_DEBOUNCE), \
@@ -2158,6 +2159,7 @@ static void run_state_machine(struct tcpm_port *port) {int ret;enum typec_pwr_opmode opmode; +unsigned int msecs; port->enter_state = port->state;switch (port->state) {
@@ -2379,7 +2381,22 @@ static void run_state_machine(struct tcpm_port *port)case SRC_TRY : port->try_src_count++;tcpm_set_cc (port,tcpm_rp_cc (port)); -tcpm_set_state (port,SNK_TRYWAIT ,PD_T_DRP_TRY ); + port->max_wait =0 ; +tcpm_set_state (port,SRC_TRY_WAIT ,0 ); +break ; +case SRC_TRY_WAIT : +if (port->max_wait ==0 ) { + port->max_wait = jiffies + +msecs_to_jiffies (PD_T_DRP_TRY ); + msecs =PD_T_DRP_TRY ; + }else { +if (time_is_after_jiffies (port->max_wait)) + msecs =jiffies_to_msecs (port->max_wait - + jiffies); +else + msecs =0 ; + } +tcpm_set_state (port,SNK_TRYWAIT , msecs);break ;case SRC_TRY_DEBOUNCE :tcpm_set_state (port,SRC_ATTACHED ,PD_T_PD_DEBOUNCE );
@@ -2935,12 +2952,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,tcpm_set_state (port,SRC_TRYWAIT ,0 ); }break ; -case SRC_TRY : +case SRC_TRY_WAIT :if (tcpm_port_is_source (port))tcpm_set_state (port,SRC_TRY_DEBOUNCE ,0 );break ;case SRC_TRY_DEBOUNCE : -tcpm_set_state (port,SRC_TRY ,0 ); +tcpm_set_state (port,SRC_TRY_WAIT ,0 );break ;case SNK_TRYWAIT_DEBOUNCE :if (port->vbus_present) {
@@ -3015,7 +3032,10 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)case SNK_TRYWAIT :tcpm_set_state (port,SNK_TRYWAIT_VBUS ,0 );break ; - +case SRC_TRY_WAIT : +case SRC_TRY_DEBOUNCE : +/* Do nothing, waiting for sink detection */ +break ;default :break ; }
@@ -3069,7 +3089,10 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)case PORT_RESET_WAIT_OFF :tcpm_set_state (port,tcpm_default_state (port),0 );break ; - +case SRC_TRY_WAIT : +case SRC_TRY_DEBOUNCE : +/* Do nothing, waiting for sink detection */ +break ;default :if (port->pwr_role ==TYPEC_SINK && port->attached)
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 6/11 staging: typec: tcpm: Comply with TryWait.SNK State
In reply to Badhri Jagan SridharanAccording to the spec:
"4.5.2.2.10.2 Exiting from TryWait.SNK State
The port shall transition to Attached.SNK after tCCDebounce if or when VBUS is detected. Note the Source may initiate USB PD communications which will cause brief periods of the SNK.Open state on both the CC1 and CC2 pins, but this event will not exceed tPDDebounce. The port shall transition to Unattached.SNK when the state of both of the CC1 and CC2 pins is SNK.Open for at least tPDDebounce."
---
Changelog since v1:
- Corrected tag
Changelog since v2:
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 58 +++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 28 deletions(-)
drivers/staging/typec/tcpm.c +30 -28
@@ -2403,26 +2403,24 @@ static void run_state_machine(struct tcpm_port *port)break ;case SNK_TRYWAIT :tcpm_set_cc (port,TYPEC_CC_RD ); -tcpm_set_state (port,SNK_TRYWAIT_DEBOUNCE ,PD_T_CC_DEBOUNCE ); +tcpm_set_state (port,SNK_TRYWAIT_VBUS ,PD_T_CC_DEBOUNCE );break ; -case SNK_TRYWAIT_DEBOUNCE : -if (port->vbus_present) { +case SNK_TRYWAIT_VBUS : +/* +* TCPM stays in this state indefinitely until VBUS +* is detected as long as Rp is not detected for +* more than a time period of tPDDebounce. +*/ +if (port->vbus_present &&tcpm_port_is_sink (port)) {tcpm_set_state (port,SNK_ATTACHED ,0 );break ; } -if (tcpm_port_is_disconnected (port)) { -tcpm_set_state (port,SNK_UNATTACHED , -PD_T_PD_DEBOUNCE ); -break ; - } -if (tcpm_port_is_source (port)) -tcpm_set_state (port,SRC_ATTACHED ,0 ); -/* XXX Are we supposed to stay in this state ? */ +if (!tcpm_port_is_sink (port)) +tcpm_set_state (port,SNK_TRYWAIT_DEBOUNCE ,0 );break ; -case SNK_TRYWAIT_VBUS : -tcpm_set_state (port,SNK_ATTACHED ,PD_T_CC_DEBOUNCE ); +case SNK_TRYWAIT_DEBOUNCE : +tcpm_set_state (port,SNK_UNATTACHED ,PD_T_PD_DEBOUNCE );break ; -case SNK_ATTACHED : ret =tcpm_snk_attach (port);if (ret <0 )
@@ -2960,19 +2958,16 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,tcpm_set_state (port,SRC_TRY_WAIT ,0 );break ;case SNK_TRYWAIT_DEBOUNCE : -if (port->vbus_present) { -tcpm_set_state (port,SNK_ATTACHED ,0 ); -break ; - } -if (tcpm_port_is_source (port)) { -tcpm_set_state (port,SRC_ATTACHED ,0 ); -break ; - } -if (tcpm_port_is_disconnected (port) && - port->delayed_state !=SNK_UNATTACHED ) +if (tcpm_port_is_sink (port)) +tcpm_set_state (port,SNK_TRYWAIT_VBUS ,0 ); +break ; +case SNK_TRYWAIT_VBUS : +if (!tcpm_port_is_sink (port))tcpm_set_state (port,SNK_TRYWAIT_DEBOUNCE ,0 );break ; - +case SNK_TRYWAIT : +/* Do nothing, waiting for tCCDebounce */ +break ;case PR_SWAP_SNK_SRC_SINK_OFF :case PR_SWAP_SRC_SNK_TRANSITION_OFF :case PR_SWAP_SRC_SNK_SOURCE_OFF :
@@ -3030,7 +3025,14 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)/* Do nothing, waiting for PD_DEBOUNCE to do be done */ break ;case SNK_TRYWAIT : -tcpm_set_state (port,SNK_TRYWAIT_VBUS ,0 ); +/* Do nothing, waiting for tCCDebounce */ +break ; +case SNK_TRYWAIT_VBUS : +if (tcpm_port_is_sink (port)) +tcpm_set_state (port,SNK_ATTACHED ,0 ); +break ; +case SNK_TRYWAIT_DEBOUNCE : +/* Do nothing, waiting for Rp */ break ;case SRC_TRY_WAIT :case SRC_TRY_DEBOUNCE :
@@ -3067,10 +3069,10 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)case SNK_TRY_WAIT_DEBOUNCE :/* Do nothing, waiting for PD_DEBOUNCE to do be done */ break ; +case SNK_TRYWAIT :case SNK_TRYWAIT_VBUS : -tcpm_set_state (port,SNK_TRYWAIT ,0 ); +case SNK_TRYWAIT_DEBOUNCE :break ; -case SNK_ATTACH_WAIT :tcpm_set_state (port,SNK_UNATTACHED ,0 );break ;
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 7/11 staging: typec: tcpm: Consider port_type while determining unattached_state
In reply to Badhri Jagan SridharanWhile performing PORT_RESET, upon receiving the cc disconnect signal from the underlaying tcpc device, TCPM transitions into unattached state. Consider the current type of port while determining the unattached state.
In the below logs, although the port_type was set to sink, TCPM transitioned into SRC_UNATTACHED.
[ 762.290654] state change SRC_READY -> PORT_RESET [ 762.324531] Setting voltage/current limit 0 mV 0 mA [ 762.327912] polarity 0 [ 762.334864] cc:=0 [ 762.347193] pending state change PORT_RESET -> PORT_RESET_WAIT_OFF @ 100 ms [ 762.347200] VBUS off [ 762.347203] CC1: 2 -> 0, CC2: 0 -> 0 [state PORT_RESET, polarity 0, disconnected] [ 762.347206] state change PORT_RESET -> SRC_UNATTACHED
---
Changelog since previous version:
- Only one previous version of the patch was sent. Numbering this V3 instead of V2 to keep the sequence number in sync with the rest of the patches in the patch list.
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
- addressed comment nit
drivers/staging/typec/tcpm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/staging/typec/tcpm.c +9 -3
@@ -2117,10 +2117,16 @@ static inline enum tcpm_state ready_state(struct tcpm_port *port)static inline enum tcpm_state unattached_state (struct tcpm_port *port) { -if (port->pwr_role ==TYPEC_SOURCE ) +if (port->port_type ==TYPEC_PORT_DRP ) { +if (port->pwr_role ==TYPEC_SOURCE ) +return SRC_UNATTACHED ; +else +return SNK_UNATTACHED ; + }else if (port->port_type ==TYPEC_PORT_DFP ) {return SRC_UNATTACHED ; -else -return SNK_UNATTACHED ; + } + +return SNK_UNATTACHED ; }static void tcpm_check_send_discover (struct tcpm_port *port)
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 8/11 staging: typec: tcpm: add cc change handling in src states
In reply to Badhri Jagan SridharanIn the case that the lower layer driver reports a cc change directly from SINK state to SOURCE state, TCPM doesn't handle these cc change in SRC_SEND_CAPABILITIES, SRC_READY states. And with SRC_ATTACHED state, the change is not handled as the port is still considered connected.
[49606.131672] state change DRP_TOGGLING -> SRC_ATTACH_WAIT [49606.131701] pending state change SRC_ATTACH_WAIT -> SRC_ATTACHED @ 200 ms [49606.329952] state change SRC_ATTACH_WAIT -> SRC_ATTACHED [delayed 200 ms] [49606.329978] polarity 0 [49606.329989] Requesting mux mode 1, config 0, polarity 0 [49606.349416] vbus:=1 charge=0 [49606.372274] pending state change SRC_ATTACHED -> SRC_UNATTACHED @ 480 ms [49606.372431] VBUS on [49606.372488] state change SRC_ATTACHED -> SRC_STARTUP ... (the lower layer driver reports a direct change from source to sink) [49606.536927] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES @ 150 ms [49606.547244] CC1: 2 -> 5, CC2: 0 -> 0 [state SRC_SEND_CAPABILITIES,
polarity 0, connected]
This can happen when the lower layer driver and/or the hardware handles a portion of the Type-C state machine work, and quietly goes through the unattached state.
Originally-from: Yueyao Zhu <[email protected]>
---
Changelog since previous version:
- Only one previous version of the patch was sent. Numbering this V3 instead of V2 to keep the sequence number in sync with the rest of the patches in the patch list.
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/staging/typec/tcpm.c +4 -2
@@ -2874,10 +2874,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,tcpm_set_state (port,SRC_ATTACH_WAIT ,0 );break ;case SRC_ATTACHED : -if (tcpm_port_is_disconnected (port)) +case SRC_SEND_CAPABILITIES : +case SRC_READY : +if (tcpm_port_is_disconnected (port) || + !tcpm_port_is_source (port))tcpm_set_state (port,SRC_UNATTACHED ,0 );break ; -case SNK_UNATTACHED :if (tcpm_port_is_sink (port))tcpm_set_state (port,SNK_ATTACH_WAIT ,0 );
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 9/11 staging: typec: tcpm: typec: tcpm: Wait for CC debounce before PD excg
In reply to Badhri Jagan SridharanOnce, Rp or Rd is switched, wait for PD_T_CC_DEBOUNCE. If not the PS_RDY message transmitted might result in failure. Also, Only wait for PD_T_SRCSWAPSTDBY while in PR_SWAP_SRC_SNK_TRANSITION_OFF. PD_T_PS_SOURCE_OFF is the overall time after which the initial sink would issue hard reset.
---
Changelog since previous version:
- Only one previous version of the patch was sent. Numbering this V3 instead of V2 to keep the sequence number in sync with the rest of the patches in the patch list.
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/pd.h | 2 ++ drivers/staging/typec/tcpm.c | 25 ++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-)
drivers/staging/typec/pd.h +2 -0
@@ -278,6 +278,8 @@ static inline unsigned int rdo_max_power(u32 rdo)#define PD_T_VCONN_SOURCE_ON 100#define PD_T_SINK_REQUEST 100/* 100 ms minimum */ #define PD_T_ERROR_RECOVERY 100/* minimum 25 is insufficient */ +#define PD_T_SRCSWAPSTDBY 625/* Maximum of 650ms */ +#define PD_T_NEWSRC 250/* Maximum of 275ms */ #define PD_T_DRP_TRY 100/* 75 - 150 ms */ #define PD_T_DRP_TRYWAIT 600/* 400 - 800 ms */
drivers/staging/typec/tcpm.c +22 -3
@@ -90,9 +90,11 @@S (PR_SWAP_START ), \S (PR_SWAP_SRC_SNK_TRANSITION_OFF ), \S (PR_SWAP_SRC_SNK_SOURCE_OFF ), \ +S (PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED ), \S (PR_SWAP_SRC_SNK_SINK_ON ), \S (PR_SWAP_SNK_SRC_SINK_OFF ), \S (PR_SWAP_SNK_SRC_SOURCE_ON ), \ +S (PR_SWAP_SNK_SRC_SOURCE_ON_VBUS_RAMPED_UP ), \ \S (VCONN_SWAP_ACCEPT ), \ S(VCONN_SWAP_SEND), \
@@ -1395,7 +1397,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, SNK_TRANSITION_SINK_VBUS, 0); }break ; -case PR_SWAP_SRC_SNK_SOURCE_OFF : +case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED :tcpm_set_state (port,PR_SWAP_SRC_SNK_SINK_ON ,0 );break ;case PR_SWAP_SNK_SRC_SINK_OFF :
@@ -2679,11 +2681,17 @@ static void run_state_machine(struct tcpm_port *port)case PR_SWAP_SRC_SNK_TRANSITION_OFF :tcpm_set_vbus (port, false); port->explicit_contract = false; +/* allow time for Vbus discharge, must be < tSrcSwapStdby */ tcpm_set_state (port,PR_SWAP_SRC_SNK_SOURCE_OFF , -PD_T_PS_SOURCE_OFF ); +PD_T_SRCSWAPSTDBY );break ;case PR_SWAP_SRC_SNK_SOURCE_OFF :tcpm_set_cc (port,TYPEC_CC_RD ); +/* allow CC debounce */ +tcpm_set_state (port,PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED , +PD_T_CC_DEBOUNCE ); +break ; +case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED :/* * USB-PD standard, 6.2.1.4, Port Power Role: * "During the Power Role Swap Sequence, for the initial Source
@@ -2709,6 +2717,15 @@ static void run_state_machine(struct tcpm_port *port)case PR_SWAP_SNK_SRC_SOURCE_ON :tcpm_set_cc (port,tcpm_rp_cc (port));tcpm_set_vbus (port, true); +/* +* allow time VBUS ramp-up, must be < tNewSrc +* Also, this window overlaps with CC debounce as well. +* So, Wait for the max of two which is PD_T_NEWSRC +*/ +tcpm_set_state (port,PR_SWAP_SNK_SRC_SOURCE_ON_VBUS_RAMPED_UP , +PD_T_NEWSRC ); +break ; +case PR_SWAP_SNK_SRC_SOURCE_ON_VBUS_RAMPED_UP :/* * USB PD standard, 6.2.1.4: * "Subsequent Messages initiated by the Policy Engine,
@@ -2979,8 +2996,10 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,case PR_SWAP_SNK_SRC_SINK_OFF :case PR_SWAP_SRC_SNK_TRANSITION_OFF :case PR_SWAP_SRC_SNK_SOURCE_OFF : +case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED : +case PR_SWAP_SNK_SRC_SOURCE_ON :/* -* CC state change is expected here; we just turned off power. +* CC state change is expected in PR_SWAP * Ignore it. */ break ;
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 10/11 staging: typec: tcpm: Do not send PING msgs in TCPM
In reply to Badhri Jagan SridharanPING messages are used to monitor the connect/disconnect. However, when PD is carried over CC, so this is not required.
Also, the spec does not clearly say if PD is possible when Type-c is connected to Type-A/B. So, removing sending PING messages altogether.
---
Changelog since previous version:
- Only one previous version of the patch was sent. Numbering this V3 instead of V2 to keep the sequence number in sync with the rest of the patches in the patch list.
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/staging/typec/tcpm.c +4 -7
@@ -2335,14 +2335,11 @@ static void run_state_machine(struct tcpm_port *port)* - The system is not operating in PD mode * or * - Both partners are connected using a Type-C connector -* XXX How do we know that ? +* +* There is no actual need to send PD messages since the local +* port type-c and the spec does not clearly say whether PD is +* possible when type-c is connected to Type-A/B */ -if (port->pwr_opmode ==TYPEC_PWR_MODE_PD && - !port->op_vsafe5v) { -tcpm_pd_send_control (port,PD_CTRL_PING ); -tcpm_set_state_cond (port,SRC_READY , -PD_T_SOURCE_ACTIVITY ); - }break ;case SRC_WAIT_NEW_CAPABILITIES :/* Nothing to do... */
Signature · 1 line
2.14.1.342.g6490525c54-goog
PATCH v3 11/11 staging: typec: tcpm: Switch to PORT_RESET instead of SNK_UNATTACHED
In reply to Badhri Jagan SridharanWhen VBUS is not discovered within PD_T_PS_SOURCE_ON although Rp is detected on CC, TCPM switches the port to SNK_UNATTACHED state. SNK_UNATTACHED, however does not force TYPEC_CC_OPEN which makes the partner(source) to think that it is connected.
To overcome this issue, force the port into PORT_RESET state to make sure the CC lines are open.
---
Changelog since previous version:
- Only one previous version of the patch was sent. Numbering this V3 instead of V2 to keep the sequence number in sync with the rest of the patches in the patch list.
- added Reviewed-by: Guenter Roeck <[email protected]>
- fixed version/sequence numbers
drivers/staging/typec/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/typec/tcpm.c +1 -1
@@ -2380,7 +2380,7 @@ static void run_state_machine(struct tcpm_port *port) 0); else/* Wait for VBUS, but not forever */ -tcpm_set_state (port ,SNK_UNATTACHED ,PD_T_PS_SOURCE_ON ); +tcpm_set_state (port ,PORT_RESET ,PD_T_PS_SOURCE_ON );break ;case SRC_TRY :
Signature · 1 line
2.14.1.342.g6490525c54-goog