Re: [PATCH] usb: typec: tcpm: Refactor the PPS APDO selection

From: Heikki Krogerus
Date: Wed Aug 02 2023 - 06:56:56 EST


On Tue, Aug 01, 2023 at 12:21:59AM +0800, Kyle Tso wrote:
> In current design of the PPS APDO selection, TCPM power supply only
> accepts the requested voltage which is inside the range of the selected
> PPS profile. To extend the flexibility and usability, remove the checks
> about the voltage range in current profile. And try to search all PPS
> APDOs of the Source that fit the requested voltage.
>
> Also remove some redundant checks in tcpm_pd_build_pps_request.
>
> Signed-off-by: Kyle Tso <kyletso@xxxxxxxxxx>

Acked-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>

> ---
> drivers/usb/typec/tcpm/tcpm.c | 122 ++++++----------------------------
> 1 file changed, 21 insertions(+), 101 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index 829d75ebab42..9c496b8302b4 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -3253,23 +3253,12 @@ static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo,
> return ret;
> }
>
> -#define min_pps_apdo_current(x, y) \
> - min(pdo_pps_apdo_max_current(x), pdo_pps_apdo_max_current(y))
> -
> static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
> {
> - unsigned int i, j, max_mw = 0, max_mv = 0;
> - unsigned int min_src_mv, max_src_mv, src_ma, src_mw;
> - unsigned int min_snk_mv, max_snk_mv;
> - unsigned int max_op_mv;
> - u32 pdo, src, snk;
> - unsigned int src_pdo = 0, snk_pdo = 0;
> + unsigned int i, src_ma, max_temp_mw = 0, max_op_ma, op_mw;
> + unsigned int src_pdo = 0;
> + u32 pdo, src;
>
> - /*
> - * Select the source PPS APDO providing the most power while staying
> - * within the board's limits. We skip the first PDO as this is always
> - * 5V 3A.
> - */
> for (i = 1; i < port->nr_source_caps; ++i) {
> pdo = port->source_caps[i];
>
> @@ -3280,54 +3269,17 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
> continue;
> }
>
> - min_src_mv = pdo_pps_apdo_min_voltage(pdo);
> - max_src_mv = pdo_pps_apdo_max_voltage(pdo);
> - src_ma = pdo_pps_apdo_max_current(pdo);
> - src_mw = (src_ma * max_src_mv) / 1000;
> -
> - /*
> - * Now search through the sink PDOs to find a matching
> - * PPS APDO. Again skip the first sink PDO as this will
> - * always be 5V 3A.
> - */
> - for (j = 1; j < port->nr_snk_pdo; j++) {
> - pdo = port->snk_pdo[j];
> -
> - switch (pdo_type(pdo)) {
> - case PDO_TYPE_APDO:
> - if (pdo_apdo_type(pdo) != APDO_TYPE_PPS) {
> - tcpm_log(port,
> - "Not PPS APDO (sink), ignoring");
> - continue;
> - }
> -
> - min_snk_mv =
> - pdo_pps_apdo_min_voltage(pdo);
> - max_snk_mv =
> - pdo_pps_apdo_max_voltage(pdo);
> - break;
> - default:
> - tcpm_log(port,
> - "Not APDO type (sink), ignoring");
> - continue;
> - }
> + if (port->pps_data.req_out_volt > pdo_pps_apdo_max_voltage(pdo) ||
> + port->pps_data.req_out_volt < pdo_pps_apdo_min_voltage(pdo))
> + continue;
>
> - if (min_src_mv <= max_snk_mv &&
> - max_src_mv >= min_snk_mv) {
> - max_op_mv = min(max_src_mv, max_snk_mv);
> - src_mw = (max_op_mv * src_ma) / 1000;
> - /* Prefer higher voltages if available */
> - if ((src_mw == max_mw &&
> - max_op_mv > max_mv) ||
> - src_mw > max_mw) {
> - src_pdo = i;
> - snk_pdo = j;
> - max_mw = src_mw;
> - max_mv = max_op_mv;
> - }
> - }
> + src_ma = pdo_pps_apdo_max_current(pdo);
> + max_op_ma = min(src_ma, port->pps_data.req_op_curr);
> + op_mw = max_op_ma * port->pps_data.req_out_volt / 1000;
> + if (op_mw > max_temp_mw) {
> + src_pdo = i;
> + max_temp_mw = op_mw;
> }
> -
> break;
> default:
> tcpm_log(port, "Not APDO type (source), ignoring");
> @@ -3337,16 +3289,10 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
>
> if (src_pdo) {
> src = port->source_caps[src_pdo];
> - snk = port->snk_pdo[snk_pdo];
> -
> - port->pps_data.req_min_volt = max(pdo_pps_apdo_min_voltage(src),
> - pdo_pps_apdo_min_voltage(snk));
> - port->pps_data.req_max_volt = min(pdo_pps_apdo_max_voltage(src),
> - pdo_pps_apdo_max_voltage(snk));
> - port->pps_data.req_max_curr = min_pps_apdo_current(src, snk);
> - port->pps_data.req_out_volt = min(port->pps_data.req_max_volt,
> - max(port->pps_data.req_min_volt,
> - port->pps_data.req_out_volt));
> +
> + port->pps_data.req_min_volt = pdo_pps_apdo_min_voltage(src);
> + port->pps_data.req_max_volt = pdo_pps_apdo_max_voltage(src);
> + port->pps_data.req_max_curr = pdo_pps_apdo_max_current(src);
> port->pps_data.req_op_curr = min(port->pps_data.req_max_curr,
> port->pps_data.req_op_curr);
> }
> @@ -3464,32 +3410,16 @@ static int tcpm_pd_send_request(struct tcpm_port *port)
> static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo)
> {
> unsigned int out_mv, op_ma, op_mw, max_mv, max_ma, flags;
> - enum pd_pdo_type type;
> unsigned int src_pdo_index;
> - u32 pdo;
>
> src_pdo_index = tcpm_pd_select_pps_apdo(port);
> if (!src_pdo_index)
> return -EOPNOTSUPP;
>
> - pdo = port->source_caps[src_pdo_index];
> - type = pdo_type(pdo);
> -
> - switch (type) {
> - case PDO_TYPE_APDO:
> - if (pdo_apdo_type(pdo) != APDO_TYPE_PPS) {
> - tcpm_log(port, "Invalid APDO selected!");
> - return -EINVAL;
> - }
> - max_mv = port->pps_data.req_max_volt;
> - max_ma = port->pps_data.req_max_curr;
> - out_mv = port->pps_data.req_out_volt;
> - op_ma = port->pps_data.req_op_curr;
> - break;
> - default:
> - tcpm_log(port, "Invalid PDO selected!");
> - return -EINVAL;
> - }
> + max_mv = port->pps_data.req_max_volt;
> + max_ma = port->pps_data.req_max_curr;
> + out_mv = port->pps_data.req_out_volt;
> + op_ma = port->pps_data.req_op_curr;
>
> flags = RDO_USB_COMM | RDO_NO_SUSPEND;
>
> @@ -5882,12 +5812,6 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 req_out_volt)
> goto port_unlock;
> }
>
> - if (req_out_volt < port->pps_data.min_volt ||
> - req_out_volt > port->pps_data.max_volt) {
> - ret = -EINVAL;
> - goto port_unlock;
> - }
> -
> target_mw = (port->current_limit * req_out_volt) / 1000;
> if (target_mw < port->operating_snk_mw) {
> ret = -EINVAL;
> @@ -6440,11 +6364,7 @@ static int tcpm_psy_set_prop(struct power_supply *psy,
> ret = tcpm_psy_set_online(port, val);
> break;
> case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> - if (val->intval < port->pps_data.min_volt * 1000 ||
> - val->intval > port->pps_data.max_volt * 1000)
> - ret = -EINVAL;
> - else
> - ret = tcpm_pps_set_out_volt(port, val->intval / 1000);
> + ret = tcpm_pps_set_out_volt(port, val->intval / 1000);
> break;
> case POWER_SUPPLY_PROP_CURRENT_NOW:
> if (val->intval > port->pps_data.max_curr * 1000)
> --
> 2.41.0.487.g6d72f3e995-goog

--
heikki