linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] tcpm: Parse and log AVS APDO
@ 2025-10-15  4:30 Badhri Jagan Sridharan
  2025-10-15  4:30 ` [PATCH v2 2/2] usb: typec: pd: Register SPR AVS caps with usb_power_delivery class Badhri Jagan Sridharan
  2025-10-20  9:51 ` [PATCH v2 1/2] tcpm: Parse and log AVS APDO Heikki Krogerus
  0 siblings, 2 replies; 4+ messages in thread
From: Badhri Jagan Sridharan @ 2025-10-15  4:30 UTC (permalink / raw)
  To: heikki.krogerus, gregkh, badhri
  Cc: amitsd, kyletso, rdbabiera, linux-kernel, linux-usb

The USB PD specification introduced new Adjustable Voltage Supply (AVS)
types for both Standard Power Range (SPR) and Extended Power Range (EPR)
sources.

Add definitions to correctly parse and handle the new AVS APDO. Use
bitfield macros to add inline helper functions to extract voltage,
current, power, and peak current fields to parse and log the details
of the new EPR AVS and SPR AVS APDO.

Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Kyle Tso <kyletso@google.com>
Reviewed-by: RD Babiera <rdbabiera@google.com>
---
Changes since v1:
* Fixed incorrrect squash.
---
 drivers/usb/typec/tcpm/tcpm.c | 15 +++++++-
 include/linux/usb/pd.h        | 69 ++++++++++++++++++++++++++++++++++-
 2 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index b2a568a5bc9b..c65aa8104950 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -823,10 +823,23 @@ static void tcpm_log_source_caps(struct tcpm_port *port)
 		case PDO_TYPE_APDO:
 			if (pdo_apdo_type(pdo) == APDO_TYPE_PPS)
 				scnprintf(msg, sizeof(msg),
-					  "%u-%u mV, %u mA",
+					  "PPS %u-%u mV, %u mA",
 					  pdo_pps_apdo_min_voltage(pdo),
 					  pdo_pps_apdo_max_voltage(pdo),
 					  pdo_pps_apdo_max_current(pdo));
+			else if (pdo_apdo_type(pdo) == APDO_TYPE_EPR_AVS)
+				scnprintf(msg, sizeof(msg),
+					  "EPR AVS %u-%u mV %u W peak_current: %u",
+					  pdo_epr_avs_apdo_min_voltage_mv(pdo),
+					  pdo_epr_avs_apdo_max_voltage_mv(pdo),
+					  pdo_epr_avs_apdo_pdp_w(pdo),
+					  pdo_epr_avs_apdo_src_peak_current(pdo));
+			else if (pdo_apdo_type(pdo) == APDO_TYPE_SPR_AVS)
+				scnprintf(msg, sizeof(msg),
+					  "SPR AVS 9-15 V: %u mA 15-20 V: %u mA peak_current: %u",
+					  pdo_spr_avs_apdo_9v_to_15v_max_current_ma(pdo),
+					  pdo_spr_avs_apdo_15v_to_20v_max_current_ma(pdo),
+					  pdo_spr_avs_apdo_src_peak_current(pdo));
 			else
 				strcpy(msg, "undefined APDO");
 			break;
diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h
index 3068c3084eb6..6ccd1b2af993 100644
--- a/include/linux/usb/pd.h
+++ b/include/linux/usb/pd.h
@@ -6,6 +6,7 @@
 #ifndef __LINUX_USB_PD_H
 #define __LINUX_USB_PD_H
 
+#include <linux/bitfield.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/usb/typec.h>
@@ -271,9 +272,11 @@ enum pd_pdo_type {
 
 enum pd_apdo_type {
 	APDO_TYPE_PPS = 0,
+	APDO_TYPE_EPR_AVS = 1,
+	APDO_TYPE_SPR_AVS = 2,
 };
 
-#define PDO_APDO_TYPE_SHIFT	28	/* Only valid value currently is 0x0 - PPS */
+#define PDO_APDO_TYPE_SHIFT	28
 #define PDO_APDO_TYPE_MASK	0x3
 
 #define PDO_APDO_TYPE(t)	((t) << PDO_APDO_TYPE_SHIFT)
@@ -297,6 +300,35 @@ enum pd_apdo_type {
 	PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) |	\
 	PDO_PPS_APDO_MAX_CURR(max_ma))
 
+/*
+ * Applicable only to EPR AVS APDO source cap as per
+ * Table 6.15 EPR Adjustable Voltage Supply APDO – Source
+ */
+#define PDO_EPR_AVS_APDO_PEAK_CURRENT	GENMASK(27, 26)
+
+/*
+ * Applicable to both EPR AVS APDO source and sink cap as per
+ * Table 6.15 EPR Adjustable Voltage Supply APDO – Source
+ * Table 6.22 EPR Adjustable Voltage Supply APDO – Sink
+ */
+#define PDO_EPR_AVS_APDO_MAX_VOLT	GENMASK(25, 17)	/* 100mV unit */
+#define PDO_EPR_AVS_APDO_MIN_VOLT	GENMASK(15, 8)	/* 100mV unit */
+#define PDO_EPR_AVS_APDO_PDP		GENMASK(7, 0) /* 1W unit */
+
+/*
+ * Applicable only SPR AVS APDO source cap as per
+ * Table 6.14 SPR Adjustable Voltage Supply APDO – Source
+ */
+#define PDO_SPR_AVS_APDO_PEAK_CURRENT		GENMASK(27, 26)
+
+/*
+ * Applicable to both SPR AVS APDO source and sink cap as per
+ * Table 6.14 SPR Adjustable Voltage Supply APDO – Source
+ * Table 6.21 SPR Adjustable Voltage Supply APDO – Sink
+ */
+#define PDO_SPR_AVS_APDO_9V_TO_15V_MAX_CURR	GENMASK(19, 10)	/* 10mA unit */
+#define PDO_SPR_AVS_APDO_15V_TO_20V_MAX_CURR	GENMASK(9, 0)	/* 10mA unit */
+
 static inline enum pd_pdo_type pdo_type(u32 pdo)
 {
 	return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
@@ -350,6 +382,41 @@ static inline unsigned int pdo_pps_apdo_max_current(u32 pdo)
 		PDO_PPS_APDO_CURR_MASK) * 50;
 }
 
+static inline unsigned int pdo_epr_avs_apdo_src_peak_current(u32 pdo)
+{
+	return FIELD_GET(PDO_EPR_AVS_APDO_PEAK_CURRENT, pdo);
+}
+
+static inline unsigned int pdo_epr_avs_apdo_min_voltage_mv(u32 pdo)
+{
+	return FIELD_GET(PDO_EPR_AVS_APDO_MIN_VOLT, pdo) * 100;
+}
+
+static inline unsigned int pdo_epr_avs_apdo_max_voltage_mv(u32 pdo)
+{
+	return FIELD_GET(PDO_EPR_AVS_APDO_MIN_VOLT, pdo) * 100;
+}
+
+static inline unsigned int pdo_epr_avs_apdo_pdp_w(u32 pdo)
+{
+	return FIELD_GET(PDO_EPR_AVS_APDO_PDP, pdo);
+}
+
+static inline unsigned int pdo_spr_avs_apdo_src_peak_current(u32 pdo)
+{
+	return FIELD_GET(PDO_SPR_AVS_APDO_PEAK_CURRENT, pdo);
+}
+
+static inline unsigned int pdo_spr_avs_apdo_9v_to_15v_max_current_ma(u32 pdo)
+{
+	return FIELD_GET(PDO_SPR_AVS_APDO_9V_TO_15V_MAX_CURR, pdo) * 10;
+}
+
+static inline unsigned int pdo_spr_avs_apdo_15v_to_20v_max_current_ma(u32 pdo)
+{
+	return FIELD_GET(PDO_SPR_AVS_APDO_15V_TO_20V_MAX_CURR, pdo) * 10;
+}
+
 /* RDO: Request Data Object */
 #define RDO_OBJ_POS_SHIFT	28
 #define RDO_OBJ_POS_MASK	0x7

base-commit: 877c80dfbf788e57a3338627899033b7007037ee
-- 
2.51.0.858.gf9c4a03a3a-goog


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] usb: typec: pd: Register SPR AVS caps with usb_power_delivery class
  2025-10-15  4:30 [PATCH v2 1/2] tcpm: Parse and log AVS APDO Badhri Jagan Sridharan
@ 2025-10-15  4:30 ` Badhri Jagan Sridharan
  2025-10-20  9:52   ` Heikki Krogerus
  2025-10-20  9:51 ` [PATCH v2 1/2] tcpm: Parse and log AVS APDO Heikki Krogerus
  1 sibling, 1 reply; 4+ messages in thread
From: Badhri Jagan Sridharan @ 2025-10-15  4:30 UTC (permalink / raw)
  To: heikki.krogerus, gregkh, badhri
  Cc: amitsd, kyletso, rdbabiera, linux-kernel, linux-usb

usb_power_delivery class will now display AVS cap as
`spr_adjustable_voltage_supply`. `maximum_current_9V_to_15V` and
`maximum_current_15V_to_20V` shows the corresponding current limits
in mA. `peak_current` follows the same convention as fixed_supply
where the value reported in the capabilities message is displayed
as is.

Sample output with an SPR AVS capable PD charger:
$cat /sys/class/usb_power_delivery/pd1/source-capabilities/5:spr_adjustable_voltage_supply/maximum_current_9V_to_15V
4000mA

$cat /sys/class/usb_power_delivery/pd1/source-capabilities/5:spr_adjustable_voltage_supply/maximum_current_15V_to_20V
3350mA

$cat /sys/class/usb_power_delivery/pd1/source-capabilities/5:spr_adjustable_voltage_supply/peak_current
0

Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
---
Changes since V1:
* Fixed incorrect squash
---
 .../testing/sysfs-class-usb_power_delivery    | 28 ++++++
 drivers/usb/typec/pd.c                        | 95 ++++++++++++++++++-
 2 files changed, 118 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-usb_power_delivery b/Documentation/ABI/testing/sysfs-class-usb_power_delivery
index 61d233c320ea..c754458a527e 100644
--- a/Documentation/ABI/testing/sysfs-class-usb_power_delivery
+++ b/Documentation/ABI/testing/sysfs-class-usb_power_delivery
@@ -254,3 +254,31 @@ Contact:	Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
 		The PPS Power Limited bit indicates whether or not the source
 		supply will exceed the rated output power if requested.
+
+Standard Power Range (SPR) Adjustable Voltage Supplies
+
+What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply
+Date:		Oct 2025
+Contact:	Badhri Jagan Sridharan <badhri@google.com>
+Description:
+		Adjustable Voltage Supply (AVS) Augmented PDO (APDO).
+
+What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply/maximum_current_9V_to_15V
+Date:		Oct 2025
+Contact:	Badhri Jagan Sridharan <badhri@google.com>
+Description:
+		Maximum Current for 9V to 15V range in milliamperes.
+
+What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply/maximum_current_15V_to_20V
+Date:		Oct 2025
+Contact:	Badhri Jagan Sridharan <badhri@google.com>
+Description:
+		Maximum Current for greater than 15V till 20V range in
+		milliamperes.
+
+What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply/peak_current
+Date:		Oct 2025
+Contact:	Badhri Jagan Sridharan <badhri@google.com>
+Description:
+		This file shows the value of the Adjustable Voltage Supply Peak Current
+		Capability field.
diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c
index d78c04a421bc..67f20b5ffdf4 100644
--- a/drivers/usb/typec/pd.c
+++ b/drivers/usb/typec/pd.c
@@ -359,6 +359,84 @@ static const struct device_type sink_pps_type = {
 	.groups = sink_pps_groups,
 };
 
+/* -------------------------------------------------------------------------- */
+/* Standard Power Range (SPR) Adjustable Voltage Supply (AVS) */
+
+static ssize_t
+spr_avs_9v_to_15v_max_current_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%umA\n",
+			  pdo_spr_avs_apdo_9v_to_15v_max_current_ma(to_pdo(dev)->pdo));
+}
+
+static ssize_t
+spr_avs_15v_to_20v_max_current_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%umA\n",
+			  pdo_spr_avs_apdo_15v_to_20v_max_current_ma(to_pdo(dev)->pdo));
+}
+
+static ssize_t
+spr_avs_src_peak_current_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%u\n",
+			  pdo_spr_avs_apdo_src_peak_current(to_pdo(dev)->pdo));
+}
+
+static struct device_attribute spr_avs_9v_to_15v_max_current_attr = {
+	.attr = {
+		.name = "maximum_current_9V_to_15V",
+		.mode = 0444,
+	},
+	.show = spr_avs_9v_to_15v_max_current_show,
+};
+
+static struct device_attribute spr_avs_15v_to_20v_max_current_attr = {
+	.attr = {
+		.name = "maximum_current_15V_to_20V",
+		.mode = 0444,
+	},
+	.show = spr_avs_15v_to_20v_max_current_show,
+};
+
+static struct device_attribute spr_avs_src_peak_current_attr = {
+	.attr = {
+		.name = "peak_current",
+		.mode = 0444,
+	},
+	.show = spr_avs_src_peak_current_show,
+};
+
+static struct attribute *source_spr_avs_attrs[] = {
+	&spr_avs_9v_to_15v_max_current_attr.attr,
+	&spr_avs_15v_to_20v_max_current_attr.attr,
+	&spr_avs_src_peak_current_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(source_spr_avs);
+
+static const struct device_type source_spr_avs_type = {
+	.name = "pdo",
+	.release = pdo_release,
+	.groups = source_spr_avs_groups,
+};
+
+static struct attribute *sink_spr_avs_attrs[] = {
+	&spr_avs_9v_to_15v_max_current_attr.attr,
+	&spr_avs_15v_to_20v_max_current_attr.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(sink_spr_avs);
+
+static const struct device_type sink_spr_avs_type = {
+	.name = "pdo",
+	.release = pdo_release,
+	.groups = sink_spr_avs_groups,
+};
+
 /* -------------------------------------------------------------------------- */
 
 static const char * const supply_name[] = {
@@ -368,7 +446,8 @@ static const char * const supply_name[] = {
 };
 
 static const char * const apdo_supply_name[] = {
-	[APDO_TYPE_PPS]  = "programmable_supply",
+	[APDO_TYPE_PPS]      = "programmable_supply",
+	[APDO_TYPE_SPR_AVS]  = "spr_adjustable_voltage_supply",
 };
 
 static const struct device_type *source_type[] = {
@@ -378,7 +457,8 @@ static const struct device_type *source_type[] = {
 };
 
 static const struct device_type *source_apdo_type[] = {
-	[APDO_TYPE_PPS]  = &source_pps_type,
+	[APDO_TYPE_PPS]     = &source_pps_type,
+	[APDO_TYPE_SPR_AVS] = &source_spr_avs_type,
 };
 
 static const struct device_type *sink_type[] = {
@@ -388,7 +468,8 @@ static const struct device_type *sink_type[] = {
 };
 
 static const struct device_type *sink_apdo_type[] = {
-	[APDO_TYPE_PPS]  = &sink_pps_type,
+	[APDO_TYPE_PPS]     = &sink_pps_type,
+	[APDO_TYPE_SPR_AVS] = &sink_spr_avs_type,
 };
 
 /* REVISIT: Export when EPR_*_Capabilities need to be supported. */
@@ -407,8 +488,12 @@ static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int pos
 	p->object_position = position;
 
 	if (pdo_type(pdo) == PDO_TYPE_APDO) {
-		/* FIXME: Only PPS supported for now! Skipping others. */
-		if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) {
+		/*
+		 * FIXME: Only PPS, SPR_AVS supported for now!
+		 * Skipping others.
+		 */
+		if (pdo_apdo_type(pdo) != APDO_TYPE_PPS &&
+		    pdo_apdo_type(pdo) != APDO_TYPE_SPR_AVS) {
 			dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo);
 			kfree(p);
 			return 0;
-- 
2.51.0.858.gf9c4a03a3a-goog


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 1/2] tcpm: Parse and log AVS APDO
  2025-10-15  4:30 [PATCH v2 1/2] tcpm: Parse and log AVS APDO Badhri Jagan Sridharan
  2025-10-15  4:30 ` [PATCH v2 2/2] usb: typec: pd: Register SPR AVS caps with usb_power_delivery class Badhri Jagan Sridharan
@ 2025-10-20  9:51 ` Heikki Krogerus
  1 sibling, 0 replies; 4+ messages in thread
From: Heikki Krogerus @ 2025-10-20  9:51 UTC (permalink / raw)
  To: Badhri Jagan Sridharan
  Cc: gregkh, amitsd, kyletso, rdbabiera, linux-kernel, linux-usb

On Wed, Oct 15, 2025 at 04:30:13AM +0000, Badhri Jagan Sridharan wrote:
> The USB PD specification introduced new Adjustable Voltage Supply (AVS)
> types for both Standard Power Range (SPR) and Extended Power Range (EPR)
> sources.
> 
> Add definitions to correctly parse and handle the new AVS APDO. Use
> bitfield macros to add inline helper functions to extract voltage,
> current, power, and peak current fields to parse and log the details
> of the new EPR AVS and SPR AVS APDO.
> 
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
> Reviewed-by: Amit Sunil Dhamne <amitsd@google.com>
> Reviewed-by: Kyle Tso <kyletso@google.com>
> Reviewed-by: RD Babiera <rdbabiera@google.com>

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
> Changes since v1:
> * Fixed incorrrect squash.
> ---
>  drivers/usb/typec/tcpm/tcpm.c | 15 +++++++-
>  include/linux/usb/pd.h        | 69 ++++++++++++++++++++++++++++++++++-
>  2 files changed, 82 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index b2a568a5bc9b..c65aa8104950 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -823,10 +823,23 @@ static void tcpm_log_source_caps(struct tcpm_port *port)
>  		case PDO_TYPE_APDO:
>  			if (pdo_apdo_type(pdo) == APDO_TYPE_PPS)
>  				scnprintf(msg, sizeof(msg),
> -					  "%u-%u mV, %u mA",
> +					  "PPS %u-%u mV, %u mA",
>  					  pdo_pps_apdo_min_voltage(pdo),
>  					  pdo_pps_apdo_max_voltage(pdo),
>  					  pdo_pps_apdo_max_current(pdo));
> +			else if (pdo_apdo_type(pdo) == APDO_TYPE_EPR_AVS)
> +				scnprintf(msg, sizeof(msg),
> +					  "EPR AVS %u-%u mV %u W peak_current: %u",
> +					  pdo_epr_avs_apdo_min_voltage_mv(pdo),
> +					  pdo_epr_avs_apdo_max_voltage_mv(pdo),
> +					  pdo_epr_avs_apdo_pdp_w(pdo),
> +					  pdo_epr_avs_apdo_src_peak_current(pdo));
> +			else if (pdo_apdo_type(pdo) == APDO_TYPE_SPR_AVS)
> +				scnprintf(msg, sizeof(msg),
> +					  "SPR AVS 9-15 V: %u mA 15-20 V: %u mA peak_current: %u",
> +					  pdo_spr_avs_apdo_9v_to_15v_max_current_ma(pdo),
> +					  pdo_spr_avs_apdo_15v_to_20v_max_current_ma(pdo),
> +					  pdo_spr_avs_apdo_src_peak_current(pdo));
>  			else
>  				strcpy(msg, "undefined APDO");
>  			break;
> diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h
> index 3068c3084eb6..6ccd1b2af993 100644
> --- a/include/linux/usb/pd.h
> +++ b/include/linux/usb/pd.h
> @@ -6,6 +6,7 @@
>  #ifndef __LINUX_USB_PD_H
>  #define __LINUX_USB_PD_H
>  
> +#include <linux/bitfield.h>
>  #include <linux/kernel.h>
>  #include <linux/types.h>
>  #include <linux/usb/typec.h>
> @@ -271,9 +272,11 @@ enum pd_pdo_type {
>  
>  enum pd_apdo_type {
>  	APDO_TYPE_PPS = 0,
> +	APDO_TYPE_EPR_AVS = 1,
> +	APDO_TYPE_SPR_AVS = 2,
>  };
>  
> -#define PDO_APDO_TYPE_SHIFT	28	/* Only valid value currently is 0x0 - PPS */
> +#define PDO_APDO_TYPE_SHIFT	28
>  #define PDO_APDO_TYPE_MASK	0x3
>  
>  #define PDO_APDO_TYPE(t)	((t) << PDO_APDO_TYPE_SHIFT)
> @@ -297,6 +300,35 @@ enum pd_apdo_type {
>  	PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) |	\
>  	PDO_PPS_APDO_MAX_CURR(max_ma))
>  
> +/*
> + * Applicable only to EPR AVS APDO source cap as per
> + * Table 6.15 EPR Adjustable Voltage Supply APDO – Source
> + */
> +#define PDO_EPR_AVS_APDO_PEAK_CURRENT	GENMASK(27, 26)
> +
> +/*
> + * Applicable to both EPR AVS APDO source and sink cap as per
> + * Table 6.15 EPR Adjustable Voltage Supply APDO – Source
> + * Table 6.22 EPR Adjustable Voltage Supply APDO – Sink
> + */
> +#define PDO_EPR_AVS_APDO_MAX_VOLT	GENMASK(25, 17)	/* 100mV unit */
> +#define PDO_EPR_AVS_APDO_MIN_VOLT	GENMASK(15, 8)	/* 100mV unit */
> +#define PDO_EPR_AVS_APDO_PDP		GENMASK(7, 0) /* 1W unit */
> +
> +/*
> + * Applicable only SPR AVS APDO source cap as per
> + * Table 6.14 SPR Adjustable Voltage Supply APDO – Source
> + */
> +#define PDO_SPR_AVS_APDO_PEAK_CURRENT		GENMASK(27, 26)
> +
> +/*
> + * Applicable to both SPR AVS APDO source and sink cap as per
> + * Table 6.14 SPR Adjustable Voltage Supply APDO – Source
> + * Table 6.21 SPR Adjustable Voltage Supply APDO – Sink
> + */
> +#define PDO_SPR_AVS_APDO_9V_TO_15V_MAX_CURR	GENMASK(19, 10)	/* 10mA unit */
> +#define PDO_SPR_AVS_APDO_15V_TO_20V_MAX_CURR	GENMASK(9, 0)	/* 10mA unit */
> +
>  static inline enum pd_pdo_type pdo_type(u32 pdo)
>  {
>  	return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
> @@ -350,6 +382,41 @@ static inline unsigned int pdo_pps_apdo_max_current(u32 pdo)
>  		PDO_PPS_APDO_CURR_MASK) * 50;
>  }
>  
> +static inline unsigned int pdo_epr_avs_apdo_src_peak_current(u32 pdo)
> +{
> +	return FIELD_GET(PDO_EPR_AVS_APDO_PEAK_CURRENT, pdo);
> +}
> +
> +static inline unsigned int pdo_epr_avs_apdo_min_voltage_mv(u32 pdo)
> +{
> +	return FIELD_GET(PDO_EPR_AVS_APDO_MIN_VOLT, pdo) * 100;
> +}
> +
> +static inline unsigned int pdo_epr_avs_apdo_max_voltage_mv(u32 pdo)
> +{
> +	return FIELD_GET(PDO_EPR_AVS_APDO_MIN_VOLT, pdo) * 100;
> +}
> +
> +static inline unsigned int pdo_epr_avs_apdo_pdp_w(u32 pdo)
> +{
> +	return FIELD_GET(PDO_EPR_AVS_APDO_PDP, pdo);
> +}
> +
> +static inline unsigned int pdo_spr_avs_apdo_src_peak_current(u32 pdo)
> +{
> +	return FIELD_GET(PDO_SPR_AVS_APDO_PEAK_CURRENT, pdo);
> +}
> +
> +static inline unsigned int pdo_spr_avs_apdo_9v_to_15v_max_current_ma(u32 pdo)
> +{
> +	return FIELD_GET(PDO_SPR_AVS_APDO_9V_TO_15V_MAX_CURR, pdo) * 10;
> +}
> +
> +static inline unsigned int pdo_spr_avs_apdo_15v_to_20v_max_current_ma(u32 pdo)
> +{
> +	return FIELD_GET(PDO_SPR_AVS_APDO_15V_TO_20V_MAX_CURR, pdo) * 10;
> +}
> +
>  /* RDO: Request Data Object */
>  #define RDO_OBJ_POS_SHIFT	28
>  #define RDO_OBJ_POS_MASK	0x7
> 
> base-commit: 877c80dfbf788e57a3338627899033b7007037ee
> -- 
> 2.51.0.858.gf9c4a03a3a-goog

-- 
heikki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] usb: typec: pd: Register SPR AVS caps with usb_power_delivery class
  2025-10-15  4:30 ` [PATCH v2 2/2] usb: typec: pd: Register SPR AVS caps with usb_power_delivery class Badhri Jagan Sridharan
@ 2025-10-20  9:52   ` Heikki Krogerus
  0 siblings, 0 replies; 4+ messages in thread
From: Heikki Krogerus @ 2025-10-20  9:52 UTC (permalink / raw)
  To: Badhri Jagan Sridharan
  Cc: gregkh, amitsd, kyletso, rdbabiera, linux-kernel, linux-usb

On Wed, Oct 15, 2025 at 04:30:14AM +0000, Badhri Jagan Sridharan wrote:
> usb_power_delivery class will now display AVS cap as
> `spr_adjustable_voltage_supply`. `maximum_current_9V_to_15V` and
> `maximum_current_15V_to_20V` shows the corresponding current limits
> in mA. `peak_current` follows the same convention as fixed_supply
> where the value reported in the capabilities message is displayed
> as is.
> 
> Sample output with an SPR AVS capable PD charger:
> $cat /sys/class/usb_power_delivery/pd1/source-capabilities/5:spr_adjustable_voltage_supply/maximum_current_9V_to_15V
> 4000mA
> 
> $cat /sys/class/usb_power_delivery/pd1/source-capabilities/5:spr_adjustable_voltage_supply/maximum_current_15V_to_20V
> 3350mA
> 
> $cat /sys/class/usb_power_delivery/pd1/source-capabilities/5:spr_adjustable_voltage_supply/peak_current
> 0
> 
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
> Changes since V1:
> * Fixed incorrect squash
> ---
>  .../testing/sysfs-class-usb_power_delivery    | 28 ++++++
>  drivers/usb/typec/pd.c                        | 95 ++++++++++++++++++-
>  2 files changed, 118 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-usb_power_delivery b/Documentation/ABI/testing/sysfs-class-usb_power_delivery
> index 61d233c320ea..c754458a527e 100644
> --- a/Documentation/ABI/testing/sysfs-class-usb_power_delivery
> +++ b/Documentation/ABI/testing/sysfs-class-usb_power_delivery
> @@ -254,3 +254,31 @@ Contact:	Heikki Krogerus <heikki.krogerus@linux.intel.com>
>  Description:
>  		The PPS Power Limited bit indicates whether or not the source
>  		supply will exceed the rated output power if requested.
> +
> +Standard Power Range (SPR) Adjustable Voltage Supplies
> +
> +What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply
> +Date:		Oct 2025
> +Contact:	Badhri Jagan Sridharan <badhri@google.com>
> +Description:
> +		Adjustable Voltage Supply (AVS) Augmented PDO (APDO).
> +
> +What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply/maximum_current_9V_to_15V
> +Date:		Oct 2025
> +Contact:	Badhri Jagan Sridharan <badhri@google.com>
> +Description:
> +		Maximum Current for 9V to 15V range in milliamperes.
> +
> +What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply/maximum_current_15V_to_20V
> +Date:		Oct 2025
> +Contact:	Badhri Jagan Sridharan <badhri@google.com>
> +Description:
> +		Maximum Current for greater than 15V till 20V range in
> +		milliamperes.
> +
> +What:		/sys/class/usb_power_delivery/.../<capability>/<position>:spr_adjustable_voltage_supply/peak_current
> +Date:		Oct 2025
> +Contact:	Badhri Jagan Sridharan <badhri@google.com>
> +Description:
> +		This file shows the value of the Adjustable Voltage Supply Peak Current
> +		Capability field.
> diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c
> index d78c04a421bc..67f20b5ffdf4 100644
> --- a/drivers/usb/typec/pd.c
> +++ b/drivers/usb/typec/pd.c
> @@ -359,6 +359,84 @@ static const struct device_type sink_pps_type = {
>  	.groups = sink_pps_groups,
>  };
>  
> +/* -------------------------------------------------------------------------- */
> +/* Standard Power Range (SPR) Adjustable Voltage Supply (AVS) */
> +
> +static ssize_t
> +spr_avs_9v_to_15v_max_current_show(struct device *dev,
> +				   struct device_attribute *attr, char *buf)
> +{
> +	return sysfs_emit(buf, "%umA\n",
> +			  pdo_spr_avs_apdo_9v_to_15v_max_current_ma(to_pdo(dev)->pdo));
> +}
> +
> +static ssize_t
> +spr_avs_15v_to_20v_max_current_show(struct device *dev,
> +				    struct device_attribute *attr, char *buf)
> +{
> +	return sysfs_emit(buf, "%umA\n",
> +			  pdo_spr_avs_apdo_15v_to_20v_max_current_ma(to_pdo(dev)->pdo));
> +}
> +
> +static ssize_t
> +spr_avs_src_peak_current_show(struct device *dev,
> +			      struct device_attribute *attr, char *buf)
> +{
> +	return sysfs_emit(buf, "%u\n",
> +			  pdo_spr_avs_apdo_src_peak_current(to_pdo(dev)->pdo));
> +}
> +
> +static struct device_attribute spr_avs_9v_to_15v_max_current_attr = {
> +	.attr = {
> +		.name = "maximum_current_9V_to_15V",
> +		.mode = 0444,
> +	},
> +	.show = spr_avs_9v_to_15v_max_current_show,
> +};
> +
> +static struct device_attribute spr_avs_15v_to_20v_max_current_attr = {
> +	.attr = {
> +		.name = "maximum_current_15V_to_20V",
> +		.mode = 0444,
> +	},
> +	.show = spr_avs_15v_to_20v_max_current_show,
> +};
> +
> +static struct device_attribute spr_avs_src_peak_current_attr = {
> +	.attr = {
> +		.name = "peak_current",
> +		.mode = 0444,
> +	},
> +	.show = spr_avs_src_peak_current_show,
> +};
> +
> +static struct attribute *source_spr_avs_attrs[] = {
> +	&spr_avs_9v_to_15v_max_current_attr.attr,
> +	&spr_avs_15v_to_20v_max_current_attr.attr,
> +	&spr_avs_src_peak_current_attr.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(source_spr_avs);
> +
> +static const struct device_type source_spr_avs_type = {
> +	.name = "pdo",
> +	.release = pdo_release,
> +	.groups = source_spr_avs_groups,
> +};
> +
> +static struct attribute *sink_spr_avs_attrs[] = {
> +	&spr_avs_9v_to_15v_max_current_attr.attr,
> +	&spr_avs_15v_to_20v_max_current_attr.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(sink_spr_avs);
> +
> +static const struct device_type sink_spr_avs_type = {
> +	.name = "pdo",
> +	.release = pdo_release,
> +	.groups = sink_spr_avs_groups,
> +};
> +
>  /* -------------------------------------------------------------------------- */
>  
>  static const char * const supply_name[] = {
> @@ -368,7 +446,8 @@ static const char * const supply_name[] = {
>  };
>  
>  static const char * const apdo_supply_name[] = {
> -	[APDO_TYPE_PPS]  = "programmable_supply",
> +	[APDO_TYPE_PPS]      = "programmable_supply",
> +	[APDO_TYPE_SPR_AVS]  = "spr_adjustable_voltage_supply",
>  };
>  
>  static const struct device_type *source_type[] = {
> @@ -378,7 +457,8 @@ static const struct device_type *source_type[] = {
>  };
>  
>  static const struct device_type *source_apdo_type[] = {
> -	[APDO_TYPE_PPS]  = &source_pps_type,
> +	[APDO_TYPE_PPS]     = &source_pps_type,
> +	[APDO_TYPE_SPR_AVS] = &source_spr_avs_type,
>  };
>  
>  static const struct device_type *sink_type[] = {
> @@ -388,7 +468,8 @@ static const struct device_type *sink_type[] = {
>  };
>  
>  static const struct device_type *sink_apdo_type[] = {
> -	[APDO_TYPE_PPS]  = &sink_pps_type,
> +	[APDO_TYPE_PPS]     = &sink_pps_type,
> +	[APDO_TYPE_SPR_AVS] = &sink_spr_avs_type,
>  };
>  
>  /* REVISIT: Export when EPR_*_Capabilities need to be supported. */
> @@ -407,8 +488,12 @@ static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int pos
>  	p->object_position = position;
>  
>  	if (pdo_type(pdo) == PDO_TYPE_APDO) {
> -		/* FIXME: Only PPS supported for now! Skipping others. */
> -		if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) {
> +		/*
> +		 * FIXME: Only PPS, SPR_AVS supported for now!
> +		 * Skipping others.
> +		 */
> +		if (pdo_apdo_type(pdo) != APDO_TYPE_PPS &&
> +		    pdo_apdo_type(pdo) != APDO_TYPE_SPR_AVS) {
>  			dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo);
>  			kfree(p);
>  			return 0;
> -- 
> 2.51.0.858.gf9c4a03a3a-goog

-- 
heikki

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-10-20  9:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-15  4:30 [PATCH v2 1/2] tcpm: Parse and log AVS APDO Badhri Jagan Sridharan
2025-10-15  4:30 ` [PATCH v2 2/2] usb: typec: pd: Register SPR AVS caps with usb_power_delivery class Badhri Jagan Sridharan
2025-10-20  9:52   ` Heikki Krogerus
2025-10-20  9:51 ` [PATCH v2 1/2] tcpm: Parse and log AVS APDO Heikki Krogerus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).