On 27 June 2018 00:45, Li Jun wrote:

> This patch adds support of get typec and power delivery config from
> firmware description.
> 
> Reviewed-by: Heikki Krogerus <heikki.kroge...@linux.intel.com>
> Reviewed-by: Guenter Roeck <li...@roeck-us.net>
> Signed-off-by: Li Jun <jun...@nxp.com>

Acked-by: Adam Thomson <adam.thomson.opensou...@diasemi.com>

> ---
>  drivers/usb/typec/tcpm.c | 131 +++++++++++++++++++++++++++++++++++++++-----
> ---
>  1 file changed, 109 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c
> index d22b37b..9dcab81 100644
> --- a/drivers/usb/typec/tcpm.c
> +++ b/drivers/usb/typec/tcpm.c
> @@ -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;
> --
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to