mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-16 13:26:45 +07:00
usb: typec: tcpm: support get typec and pd config from device properties
This patch adds support of get typec and power delivery config from firmware description. Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Li Jun <jun.li@nxp.com> Acked-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9c90e02434
commit
96232cbc6c
@ -4236,6 +4236,81 @@ static int tcpm_copy_vdos(u32 *dest_vdo, const u32 *src_vdo,
|
||||
return nr_vdo;
|
||||
}
|
||||
|
||||
static int tcpm_fw_get_caps(struct tcpm_port *port,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
const char *cap_str;
|
||||
int ret;
|
||||
u32 mw;
|
||||
|
||||
if (!fwnode)
|
||||
return -EINVAL;
|
||||
|
||||
/* USB data support is optional */
|
||||
ret = fwnode_property_read_string(fwnode, "data-role", &cap_str);
|
||||
if (ret == 0) {
|
||||
port->typec_caps.data = typec_find_port_data_role(cap_str);
|
||||
if (port->typec_caps.data < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_string(fwnode, "power-role", &cap_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port->typec_caps.type = typec_find_port_power_role(cap_str);
|
||||
if (port->typec_caps.type < 0)
|
||||
return -EINVAL;
|
||||
port->port_type = port->typec_caps.type;
|
||||
|
||||
if (port->port_type == TYPEC_PORT_SNK)
|
||||
goto sink;
|
||||
|
||||
/* Get source pdos */
|
||||
ret = fwnode_property_read_u32_array(fwnode, "source-pdos",
|
||||
NULL, 0);
|
||||
if (ret <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
port->nr_src_pdo = min(ret, PDO_MAX_OBJECTS);
|
||||
ret = fwnode_property_read_u32_array(fwnode, "source-pdos",
|
||||
port->src_pdo, port->nr_src_pdo);
|
||||
if ((ret < 0) || tcpm_validate_caps(port, port->src_pdo,
|
||||
port->nr_src_pdo))
|
||||
return -EINVAL;
|
||||
|
||||
if (port->port_type == TYPEC_PORT_SRC)
|
||||
return 0;
|
||||
|
||||
/* Get the preferred power role for DRP */
|
||||
ret = fwnode_property_read_string(fwnode, "try-power-role", &cap_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port->typec_caps.prefer_role = typec_find_power_role(cap_str);
|
||||
if (port->typec_caps.prefer_role < 0)
|
||||
return -EINVAL;
|
||||
sink:
|
||||
/* Get sink pdos */
|
||||
ret = fwnode_property_read_u32_array(fwnode, "sink-pdos",
|
||||
NULL, 0);
|
||||
if (ret <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
port->nr_snk_pdo = min(ret, PDO_MAX_OBJECTS);
|
||||
ret = fwnode_property_read_u32_array(fwnode, "sink-pdos",
|
||||
port->snk_pdo, port->nr_snk_pdo);
|
||||
if ((ret < 0) || tcpm_validate_caps(port, port->snk_pdo,
|
||||
port->nr_snk_pdo))
|
||||
return -EINVAL;
|
||||
|
||||
if (fwnode_property_read_u32(fwnode, "op-sink-microwatt", &mw) < 0)
|
||||
return -EINVAL;
|
||||
port->operating_snk_mw = mw / 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo,
|
||||
unsigned int nr_pdo)
|
||||
{
|
||||
@ -4521,12 +4596,36 @@ static int devm_tcpm_psy_register(struct tcpm_port *port)
|
||||
return PTR_ERR_OR_ZERO(port->psy);
|
||||
}
|
||||
|
||||
static int tcpm_copy_caps(struct tcpm_port *port,
|
||||
const struct tcpc_config *tcfg)
|
||||
{
|
||||
if (tcpm_validate_caps(port, tcfg->src_pdo, tcfg->nr_src_pdo) ||
|
||||
tcpm_validate_caps(port, tcfg->snk_pdo, tcfg->nr_snk_pdo))
|
||||
return -EINVAL;
|
||||
|
||||
port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcfg->src_pdo,
|
||||
tcfg->nr_src_pdo);
|
||||
port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcfg->snk_pdo,
|
||||
tcfg->nr_snk_pdo);
|
||||
|
||||
port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcfg->snk_vdo,
|
||||
tcfg->nr_snk_vdo);
|
||||
|
||||
port->operating_snk_mw = tcfg->operating_snk_mw;
|
||||
|
||||
port->typec_caps.prefer_role = tcfg->default_role;
|
||||
port->typec_caps.type = tcfg->type;
|
||||
port->typec_caps.data = tcfg->data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
||||
{
|
||||
struct tcpm_port *port;
|
||||
int i, err;
|
||||
|
||||
if (!dev || !tcpc || !tcpc->config ||
|
||||
if (!dev || !tcpc ||
|
||||
!tcpc->get_vbus || !tcpc->set_cc || !tcpc->get_cc ||
|
||||
!tcpc->set_polarity || !tcpc->set_vconn || !tcpc->set_vbus ||
|
||||
!tcpc->set_pd_rx || !tcpc->set_roles || !tcpc->pd_transmit)
|
||||
@ -4556,30 +4655,18 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
||||
init_completion(&port->pps_complete);
|
||||
tcpm_debugfs_init(port);
|
||||
|
||||
if (tcpm_validate_caps(port, tcpc->config->src_pdo,
|
||||
tcpc->config->nr_src_pdo) ||
|
||||
tcpm_validate_caps(port, tcpc->config->snk_pdo,
|
||||
tcpc->config->nr_snk_pdo)) {
|
||||
err = -EINVAL;
|
||||
err = tcpm_fw_get_caps(port, tcpc->fwnode);
|
||||
if ((err < 0) && tcpc->config)
|
||||
err = tcpm_copy_caps(port, tcpc->config);
|
||||
if (err < 0)
|
||||
goto out_destroy_wq;
|
||||
}
|
||||
port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcpc->config->src_pdo,
|
||||
tcpc->config->nr_src_pdo);
|
||||
port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo,
|
||||
tcpc->config->nr_snk_pdo);
|
||||
port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo,
|
||||
tcpc->config->nr_snk_vdo);
|
||||
|
||||
port->operating_snk_mw = tcpc->config->operating_snk_mw;
|
||||
if (!tcpc->config->try_role_hw)
|
||||
port->try_role = tcpc->config->default_role;
|
||||
if (!tcpc->config || !tcpc->config->try_role_hw)
|
||||
port->try_role = port->typec_caps.prefer_role;
|
||||
else
|
||||
port->try_role = TYPEC_NO_PREFERRED_ROLE;
|
||||
|
||||
port->typec_caps.fwnode = tcpc->fwnode;
|
||||
port->typec_caps.prefer_role = tcpc->config->default_role;
|
||||
port->typec_caps.type = tcpc->config->type;
|
||||
port->typec_caps.data = tcpc->config->data;
|
||||
port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
|
||||
port->typec_caps.pd_revision = 0x0300; /* USB-PD spec release 3.0 */
|
||||
port->typec_caps.dr_set = tcpm_dr_set;
|
||||
@ -4589,7 +4676,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
||||
port->typec_caps.port_type_set = tcpm_port_type_set;
|
||||
|
||||
port->partner_desc.identity = &port->partner_ident;
|
||||
port->port_type = tcpc->config->type;
|
||||
port->port_type = port->typec_caps.type;
|
||||
|
||||
port->role_sw = usb_role_switch_get(port->dev);
|
||||
if (IS_ERR(port->role_sw)) {
|
||||
@ -4607,7 +4694,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
||||
goto out_destroy_wq;
|
||||
}
|
||||
|
||||
if (tcpc->config->alt_modes) {
|
||||
if (tcpc->config && tcpc->config->alt_modes) {
|
||||
const struct typec_altmode_desc *paltmode = tcpc->config->alt_modes;
|
||||
|
||||
i = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user