usb: typec: tcpm: Notify the tcpc to start connection-detection for SRPs
Some tcpc device-drivers need to explicitly be told to watch for connection events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices being plugged into the Type-C port will not be noticed. For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to watch for connection events. Sofar we lack a similar callback to the tcpc for single-role ports. With some tcpc-s such as the fusb302 this means no TCPM_CC_EVENTs will be generated when the port is configured as a single-role port. This commit renames start_drp_toggling to start_toggling and since the device-properties are parsed by the tcpm-core, adds a port_type parameter to the start_toggling callback so that the tcpc_dev driver knows the port-type and can act accordingly when it starts toggling. The new start_toggling callback now always gets called if defined, instead of only being called for DRP ports. To avoid this causing undesirable functional changes all existing start_drp_toggling implementations are not only renamed to start_toggling, but also get a port_type check added and return -EOPNOTSUPP when port_type is not DRP. Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...") Cc: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Tested-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9bcb762ce0
commit
7893f9e1c2
|
@ -876,13 +876,17 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcpm_start_drp_toggling(struct tcpc_dev *dev,
|
static int tcpm_start_toggling(struct tcpc_dev *dev,
|
||||||
|
enum typec_port_type port_type,
|
||||||
enum typec_cc_status cc)
|
enum typec_cc_status cc)
|
||||||
{
|
{
|
||||||
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
|
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
|
||||||
tcpc_dev);
|
tcpc_dev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (port_type != TYPEC_PORT_DRP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
mutex_lock(&chip->lock);
|
mutex_lock(&chip->lock);
|
||||||
ret = fusb302_set_src_current(chip, cc_src_current[cc]);
|
ret = fusb302_set_src_current(chip, cc_src_current[cc]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1088,7 +1092,7 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev)
|
||||||
fusb302_tcpc_dev->set_vbus = tcpm_set_vbus;
|
fusb302_tcpc_dev->set_vbus = tcpm_set_vbus;
|
||||||
fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx;
|
fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx;
|
||||||
fusb302_tcpc_dev->set_roles = tcpm_set_roles;
|
fusb302_tcpc_dev->set_roles = tcpm_set_roles;
|
||||||
fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
|
fusb302_tcpc_dev->start_toggling = tcpm_start_toggling;
|
||||||
fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
|
fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,13 +100,17 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
|
static int tcpci_start_toggling(struct tcpc_dev *tcpc,
|
||||||
|
enum typec_port_type port_type,
|
||||||
enum typec_cc_status cc)
|
enum typec_cc_status cc)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
unsigned int reg = TCPC_ROLE_CTRL_DRP;
|
unsigned int reg = TCPC_ROLE_CTRL_DRP;
|
||||||
|
|
||||||
|
if (port_type != TYPEC_PORT_DRP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
/* Handle vendor drp toggling */
|
/* Handle vendor drp toggling */
|
||||||
if (tcpci->data->start_drp_toggling) {
|
if (tcpci->data->start_drp_toggling) {
|
||||||
ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc);
|
ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc);
|
||||||
|
@ -511,7 +515,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
|
||||||
tcpci->tcpc.get_cc = tcpci_get_cc;
|
tcpci->tcpc.get_cc = tcpci_get_cc;
|
||||||
tcpci->tcpc.set_polarity = tcpci_set_polarity;
|
tcpci->tcpc.set_polarity = tcpci_set_polarity;
|
||||||
tcpci->tcpc.set_vconn = tcpci_set_vconn;
|
tcpci->tcpc.set_vconn = tcpci_set_vconn;
|
||||||
tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling;
|
tcpci->tcpc.start_toggling = tcpci_start_toggling;
|
||||||
|
|
||||||
tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
|
tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
|
||||||
tcpci->tcpc.set_roles = tcpci_set_roles;
|
tcpci->tcpc.set_roles = tcpci_set_roles;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
#define FOREACH_STATE(S) \
|
#define FOREACH_STATE(S) \
|
||||||
S(INVALID_STATE), \
|
S(INVALID_STATE), \
|
||||||
S(DRP_TOGGLING), \
|
S(TOGGLING), \
|
||||||
S(SRC_UNATTACHED), \
|
S(SRC_UNATTACHED), \
|
||||||
S(SRC_ATTACH_WAIT), \
|
S(SRC_ATTACH_WAIT), \
|
||||||
S(SRC_ATTACHED), \
|
S(SRC_ATTACHED), \
|
||||||
|
@ -472,7 +472,7 @@ static void tcpm_log(struct tcpm_port *port, const char *fmt, ...)
|
||||||
/* Do not log while disconnected and unattached */
|
/* Do not log while disconnected and unattached */
|
||||||
if (tcpm_port_is_disconnected(port) &&
|
if (tcpm_port_is_disconnected(port) &&
|
||||||
(port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED ||
|
(port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED ||
|
||||||
port->state == DRP_TOGGLING))
|
port->state == TOGGLING))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
@ -2540,20 +2540,16 @@ static int tcpm_set_charge(struct tcpm_port *port, bool charge)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tcpm_start_drp_toggling(struct tcpm_port *port,
|
static bool tcpm_start_toggling(struct tcpm_port *port, enum typec_cc_status cc)
|
||||||
enum typec_cc_status cc)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (port->tcpc->start_drp_toggling &&
|
if (!port->tcpc->start_toggling)
|
||||||
port->port_type == TYPEC_PORT_DRP) {
|
|
||||||
tcpm_log_force(port, "Start DRP toggling");
|
|
||||||
ret = port->tcpc->start_drp_toggling(port->tcpc, cc);
|
|
||||||
if (!ret)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
tcpm_log_force(port, "Start toggling");
|
||||||
|
ret = port->tcpc->start_toggling(port->tcpc, port->port_type, cc);
|
||||||
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
|
static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
|
||||||
|
@ -2847,15 +2843,15 @@ static void run_state_machine(struct tcpm_port *port)
|
||||||
|
|
||||||
port->enter_state = port->state;
|
port->enter_state = port->state;
|
||||||
switch (port->state) {
|
switch (port->state) {
|
||||||
case DRP_TOGGLING:
|
case TOGGLING:
|
||||||
break;
|
break;
|
||||||
/* SRC states */
|
/* SRC states */
|
||||||
case SRC_UNATTACHED:
|
case SRC_UNATTACHED:
|
||||||
if (!port->non_pd_role_swap)
|
if (!port->non_pd_role_swap)
|
||||||
tcpm_swap_complete(port, -ENOTCONN);
|
tcpm_swap_complete(port, -ENOTCONN);
|
||||||
tcpm_src_detach(port);
|
tcpm_src_detach(port);
|
||||||
if (tcpm_start_drp_toggling(port, tcpm_rp_cc(port))) {
|
if (tcpm_start_toggling(port, tcpm_rp_cc(port))) {
|
||||||
tcpm_set_state(port, DRP_TOGGLING, 0);
|
tcpm_set_state(port, TOGGLING, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tcpm_set_cc(port, tcpm_rp_cc(port));
|
tcpm_set_cc(port, tcpm_rp_cc(port));
|
||||||
|
@ -3053,8 +3049,8 @@ static void run_state_machine(struct tcpm_port *port)
|
||||||
tcpm_swap_complete(port, -ENOTCONN);
|
tcpm_swap_complete(port, -ENOTCONN);
|
||||||
tcpm_pps_complete(port, -ENOTCONN);
|
tcpm_pps_complete(port, -ENOTCONN);
|
||||||
tcpm_snk_detach(port);
|
tcpm_snk_detach(port);
|
||||||
if (tcpm_start_drp_toggling(port, TYPEC_CC_RD)) {
|
if (tcpm_start_toggling(port, TYPEC_CC_RD)) {
|
||||||
tcpm_set_state(port, DRP_TOGGLING, 0);
|
tcpm_set_state(port, TOGGLING, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tcpm_set_cc(port, TYPEC_CC_RD);
|
tcpm_set_cc(port, TYPEC_CC_RD);
|
||||||
|
@ -3621,7 +3617,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
|
||||||
: "connected");
|
: "connected");
|
||||||
|
|
||||||
switch (port->state) {
|
switch (port->state) {
|
||||||
case DRP_TOGGLING:
|
case TOGGLING:
|
||||||
if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) ||
|
if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) ||
|
||||||
tcpm_port_is_source(port))
|
tcpm_port_is_source(port))
|
||||||
tcpm_set_state(port, SRC_ATTACH_WAIT, 0);
|
tcpm_set_state(port, SRC_ATTACH_WAIT, 0);
|
||||||
|
|
|
@ -416,12 +416,16 @@ static int wcove_pd_transmit(struct tcpc_dev *tcpc,
|
||||||
return regmap_write(wcove->regmap, USBC_TXCMD, cmd | USBC_TXCMD_START);
|
return regmap_write(wcove->regmap, USBC_TXCMD, cmd | USBC_TXCMD_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wcove_start_drp_toggling(struct tcpc_dev *tcpc,
|
static int wcove_start_toggling(struct tcpc_dev *tcpc,
|
||||||
|
enum typec_port_type port_type,
|
||||||
enum typec_cc_status cc)
|
enum typec_cc_status cc)
|
||||||
{
|
{
|
||||||
struct wcove_typec *wcove = tcpc_to_wcove(tcpc);
|
struct wcove_typec *wcove = tcpc_to_wcove(tcpc);
|
||||||
unsigned int usbc_ctrl;
|
unsigned int usbc_ctrl;
|
||||||
|
|
||||||
|
if (port_type != TYPEC_PORT_DRP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
usbc_ctrl = USBC_CONTROL1_MODE_DRP | USBC_CONTROL1_DRPTOGGLE_RANDOM;
|
usbc_ctrl = USBC_CONTROL1_MODE_DRP | USBC_CONTROL1_DRPTOGGLE_RANDOM;
|
||||||
|
|
||||||
switch (cc) {
|
switch (cc) {
|
||||||
|
@ -639,7 +643,7 @@ static int wcove_typec_probe(struct platform_device *pdev)
|
||||||
wcove->tcpc.set_polarity = wcove_set_polarity;
|
wcove->tcpc.set_polarity = wcove_set_polarity;
|
||||||
wcove->tcpc.set_vconn = wcove_set_vconn;
|
wcove->tcpc.set_vconn = wcove_set_vconn;
|
||||||
wcove->tcpc.set_current_limit = wcove_set_current_limit;
|
wcove->tcpc.set_current_limit = wcove_set_current_limit;
|
||||||
wcove->tcpc.start_drp_toggling = wcove_start_drp_toggling;
|
wcove->tcpc.start_toggling = wcove_start_toggling;
|
||||||
|
|
||||||
wcove->tcpc.set_pd_rx = wcove_set_pd_rx;
|
wcove->tcpc.set_pd_rx = wcove_set_pd_rx;
|
||||||
wcove->tcpc.set_roles = wcove_set_roles;
|
wcove->tcpc.set_roles = wcove_set_roles;
|
||||||
|
|
|
@ -121,10 +121,10 @@ struct tcpc_config {
|
||||||
* with partner.
|
* with partner.
|
||||||
* @set_pd_rx: Called to enable or disable reception of PD messages
|
* @set_pd_rx: Called to enable or disable reception of PD messages
|
||||||
* @set_roles: Called to set power and data roles
|
* @set_roles: Called to set power and data roles
|
||||||
* @start_drp_toggling:
|
* @start_toggling:
|
||||||
* Optional; if supported by hardware, called to start DRP
|
* Optional; if supported by hardware, called to start dual-role
|
||||||
* toggling. DRP toggling is stopped automatically if
|
* toggling or single-role connection detection. Toggling stops
|
||||||
* a connection is established.
|
* automatically if a connection is established.
|
||||||
* @try_role: Optional; called to set a preferred role
|
* @try_role: Optional; called to set a preferred role
|
||||||
* @pd_transmit:Called to transmit PD message
|
* @pd_transmit:Called to transmit PD message
|
||||||
* @mux: Pointer to multiplexer data
|
* @mux: Pointer to multiplexer data
|
||||||
|
@ -147,7 +147,8 @@ struct tcpc_dev {
|
||||||
int (*set_pd_rx)(struct tcpc_dev *dev, bool on);
|
int (*set_pd_rx)(struct tcpc_dev *dev, bool on);
|
||||||
int (*set_roles)(struct tcpc_dev *dev, bool attached,
|
int (*set_roles)(struct tcpc_dev *dev, bool attached,
|
||||||
enum typec_role role, enum typec_data_role data);
|
enum typec_role role, enum typec_data_role data);
|
||||||
int (*start_drp_toggling)(struct tcpc_dev *dev,
|
int (*start_toggling)(struct tcpc_dev *dev,
|
||||||
|
enum typec_port_type port_type,
|
||||||
enum typec_cc_status cc);
|
enum typec_cc_status cc);
|
||||||
int (*try_role)(struct tcpc_dev *dev, int role);
|
int (*try_role)(struct tcpc_dev *dev, int role);
|
||||||
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
|
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
|
||||||
|
|
Loading…
Reference in New Issue