diff mbox

[v5,3/5] power: supply: Add 'usb_type' property and supporting code

Message ID 3774272cd49908e88b56a1c4bbf3b363b851ebdd.1521552959.git.Adam.Thomson.Opensource@diasemi.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Adam Thomson March 20, 2018, 2:33 p.m. UTC
This commit adds the 'usb_type' property to represent USB supplies
which can report a number of different types based on a connection
event.

Examples of this already exist in drivers whereby the existing 'type'
property is updated, based on an event, to represent what was
connected (e.g. USB, USB_DCP, USB_ACA, ...). Current implementations
however don't show all supported connectable types, so this knowledge
has to be exlicitly known for each driver that supports this.

The 'usb_type' property is intended to fill this void and show users
all possible USB types supported by a driver. The property, when read,
shows all available types for the driver, and the one currently chosen
is highlighted/bracketed. It is expected that the 'type' property
would then just show the top-level type 'USB', and this would be
static.

Currently the 'usb_type' enum contains all of the USB variant types
that exist for the 'type' enum at this time, and in addition has
SDP and PPS types. The mirroring is intentional so as to not impact
existing usage of the 'type' property.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 Documentation/ABI/testing/sysfs-class-power | 12 +++++++
 drivers/power/supply/power_supply_sysfs.c   | 50 +++++++++++++++++++++++++++++
 include/linux/power_supply.h                | 16 +++++++++
 3 files changed, 78 insertions(+)

Comments

Guenter Roeck March 22, 2018, 4:07 a.m. UTC | #1
On 03/20/2018 07:33 AM, Adam Thomson wrote:
> This commit adds the 'usb_type' property to represent USB supplies
> which can report a number of different types based on a connection
> event.
> 
> Examples of this already exist in drivers whereby the existing 'type'
> property is updated, based on an event, to represent what was
> connected (e.g. USB, USB_DCP, USB_ACA, ...). Current implementations
> however don't show all supported connectable types, so this knowledge
> has to be exlicitly known for each driver that supports this.
> 
> The 'usb_type' property is intended to fill this void and show users
> all possible USB types supported by a driver. The property, when read,
> shows all available types for the driver, and the one currently chosen
> is highlighted/bracketed. It is expected that the 'type' property
> would then just show the top-level type 'USB', and this would be
> static.
> 
> Currently the 'usb_type' enum contains all of the USB variant types
> that exist for the 'type' enum at this time, and in addition has
> SDP and PPS types. The mirroring is intentional so as to not impact
> existing usage of the 'type' property.
> 
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
> ---
>   Documentation/ABI/testing/sysfs-class-power | 12 +++++++
>   drivers/power/supply/power_supply_sysfs.c   | 50 +++++++++++++++++++++++++++++
>   include/linux/power_supply.h                | 16 +++++++++
>   3 files changed, 78 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
> index e046566..5e23e22 100644
> --- a/Documentation/ABI/testing/sysfs-class-power
> +++ b/Documentation/ABI/testing/sysfs-class-power
> @@ -409,6 +409,18 @@ Description:
>   		Access: Read
>   		Valid values: Represented in 1/10 Degrees Celsius
>   
> +What: 		/sys/class/power_supply/<supply_name>/usb_type
> +Date:		March 2018
> +Contact:	linux-pm@vger.kernel.org
> +Description:
> +		Reports what type of USB connection is currently active for
> +		the supply, for example it can show if USB-PD capable source
> +		is attached.
> +
> +		Access: Read-Only
> +		Valid values: "Unknown", "SDP", "DCP", "CDP", "ACA", "C", "PD",
> +			      "PD_DRP", "PD_PPS", "BrickID"
> +
>   What: 		/sys/class/power_supply/<supply_name>/voltage_max
>   Date:		January 2008
>   Contact:	linux-pm@vger.kernel.org
> diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
> index 5204f11..b68def4 100644
> --- a/drivers/power/supply/power_supply_sysfs.c
> +++ b/drivers/power/supply/power_supply_sysfs.c
> @@ -46,6 +46,11 @@
>   	"USB_PD", "USB_PD_DRP", "BrickID"
>   };
>   
> +static const char * const power_supply_usb_type_text[] = {
> +	"Unknown", "SDP", "DCP", "CDP", "ACA", "C",
> +	"PD", "PD_DRP", "PD_PPS", "BrickID"
> +};
> +
>   static const char * const power_supply_status_text[] = {
>   	"Unknown", "Charging", "Discharging", "Not charging", "Full"
>   };
> @@ -73,6 +78,46 @@
>   	"Unknown", "System", "Device"
>   };
>   
> +static ssize_t power_supply_show_usb_type(struct device *dev,
> +					  enum power_supply_usb_type *usb_types,
> +					  ssize_t num_usb_types,
> +					  union power_supply_propval *value,
> +					  char *buf)
> +{
> +	enum power_supply_usb_type usb_type;
> +	ssize_t count = 0;
> +	bool match = false;
> +	int i;
> +
> +	if ((!usb_types) || (num_usb_types <= 0)) {

Unnecessary ( )

> +		dev_warn(dev, "driver has no valid connected types\n");

Are those warnings useful or do they just clog the log ? Either case, if that happens,
wouldn't it be better to detect the situation during registration and abort ?

> +		return -ENODATA;
> +	}
> +
> +	for (i = 0; i < num_usb_types; ++i) {
> +		usb_type = usb_types[i];
> +
> +		if (value->intval == usb_type) {
> +			count += sprintf(buf + count, "[%s] ",
> +					 power_supply_usb_type_text[usb_type]);
> +			match = true;
> +		} else {
> +			count += sprintf(buf + count, "%s ",
> +					 power_supply_usb_type_text[usb_type]);
> +		}
> +	}
> +
> +	if (!match) {
> +		dev_warn(dev, "driver reporting unsupported connected type\n");
> +		return -EINVAL;
> +	}
> +
> +	if (count)
> +		buf[count - 1] = '\n';
> +
> +	return count;
> +}
> +
>   static ssize_t power_supply_show_property(struct device *dev,
>   					  struct device_attribute *attr,
>   					  char *buf) {
> @@ -115,6 +160,10 @@ static ssize_t power_supply_show_property(struct device *dev,
>   	else if (off == POWER_SUPPLY_PROP_TYPE)
>   		return sprintf(buf, "%s\n",
>   			       power_supply_type_text[value.intval]);
> +	else if (off == POWER_SUPPLY_PROP_USB_TYPE)
> +		return power_supply_show_usb_type(dev, psy->desc->usb_types,
> +						  psy->desc->num_usb_types,
> +						  &value, buf);
>   	else if (off == POWER_SUPPLY_PROP_SCOPE)
>   		return sprintf(buf, "%s\n",
>   			       power_supply_scope_text[value.intval]);
> @@ -241,6 +290,7 @@ static ssize_t power_supply_store_property(struct device *dev,
>   	POWER_SUPPLY_ATTR(time_to_full_now),
>   	POWER_SUPPLY_ATTR(time_to_full_avg),
>   	POWER_SUPPLY_ATTR(type),
> +	POWER_SUPPLY_ATTR(usb_type),
>   	POWER_SUPPLY_ATTR(scope),
>   	POWER_SUPPLY_ATTR(precharge_current),
>   	POWER_SUPPLY_ATTR(charge_term_current),
> diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> index 79e90b3..4ca8876 100644
> --- a/include/linux/power_supply.h
> +++ b/include/linux/power_supply.h
> @@ -145,6 +145,7 @@ enum power_supply_property {
>   	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
>   	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
>   	POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
> +	POWER_SUPPLY_PROP_USB_TYPE,
>   	POWER_SUPPLY_PROP_SCOPE,
>   	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
>   	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
> @@ -170,6 +171,19 @@ enum power_supply_type {
>   	POWER_SUPPLY_TYPE_APPLE_BRICK_ID,	/* Apple Charging Method */
>   };
>   
> +enum power_supply_usb_type {
> +	POWER_SUPPLY_USB_TYPE_UNKNOWN = 0,
> +	POWER_SUPPLY_USB_TYPE_SDP,		/* Standard Downstream Port */
> +	POWER_SUPPLY_USB_TYPE_DCP,		/* Dedicated Charging Port */
> +	POWER_SUPPLY_USB_TYPE_CDP,		/* Charging Downstream Port */
> +	POWER_SUPPLY_USB_TYPE_ACA,		/* Accessory Charger Adapters */
> +	POWER_SUPPLY_USB_TYPE_C,		/* Type C Port */
> +	POWER_SUPPLY_USB_TYPE_PD,		/* Power Delivery Port */
> +	POWER_SUPPLY_USB_TYPE_PD_DRP,		/* PD Dual Role Port */
> +	POWER_SUPPLY_USB_TYPE_PD_PPS,		/* PD Programmable Power Supply */
> +	POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID,	/* Apple Charging Method */
> +};
> +
>   enum power_supply_notifier_events {
>   	PSY_EVENT_PROP_CHANGED,
>   };
> @@ -196,6 +210,8 @@ struct power_supply_config {
>   struct power_supply_desc {
>   	const char *name;
>   	enum power_supply_type type;
> +	enum power_supply_usb_type *usb_types;
> +	size_t num_usb_types;
>   	enum power_supply_property *properties;
>   	size_t num_properties;
>   
>
Adam Thomson March 22, 2018, 10:27 a.m. UTC | #2
On 22 March 2018 04:08, Guenter Roeck wrote:

> > +static ssize_t power_supply_show_usb_type(struct device *dev,

> > +					  enum power_supply_usb_type

> *usb_types,

> > +					  ssize_t num_usb_types,

> > +					  union power_supply_propval *value,

> > +					  char *buf)

> > +{

> > +	enum power_supply_usb_type usb_type;

> > +	ssize_t count = 0;

> > +	bool match = false;

> > +	int i;

> > +

> > +	if ((!usb_types) || (num_usb_types <= 0)) {

>

> Unnecessary ( )


Fine, can remove.

>

> > +		dev_warn(dev, "driver has no valid connected types\n");

>

> Are those warnings useful or do they just clog the log ? Either case, if that happens,

> wouldn't it be better to detect the situation during registration and abort ?


This is added as an optional property for supply drivers. This will only show
up if a supply driver adds the USB_TYPE property to its list, and then someone
attempts to access it. Actually there's no current checking for the psy_desc
information provided to the register function, so for example if it's NULL then
the kernel will dump when it tries to dereference. I'll take a look at this and
see if I can add something, including checks on the usb_type property.
diff mbox

Patch

diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
index e046566..5e23e22 100644
--- a/Documentation/ABI/testing/sysfs-class-power
+++ b/Documentation/ABI/testing/sysfs-class-power
@@ -409,6 +409,18 @@  Description:
 		Access: Read
 		Valid values: Represented in 1/10 Degrees Celsius
 
+What: 		/sys/class/power_supply/<supply_name>/usb_type
+Date:		March 2018
+Contact:	linux-pm@vger.kernel.org
+Description:
+		Reports what type of USB connection is currently active for
+		the supply, for example it can show if USB-PD capable source
+		is attached.
+
+		Access: Read-Only
+		Valid values: "Unknown", "SDP", "DCP", "CDP", "ACA", "C", "PD",
+			      "PD_DRP", "PD_PPS", "BrickID"
+
 What: 		/sys/class/power_supply/<supply_name>/voltage_max
 Date:		January 2008
 Contact:	linux-pm@vger.kernel.org
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 5204f11..b68def4 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -46,6 +46,11 @@ 
 	"USB_PD", "USB_PD_DRP", "BrickID"
 };
 
+static const char * const power_supply_usb_type_text[] = {
+	"Unknown", "SDP", "DCP", "CDP", "ACA", "C",
+	"PD", "PD_DRP", "PD_PPS", "BrickID"
+};
+
 static const char * const power_supply_status_text[] = {
 	"Unknown", "Charging", "Discharging", "Not charging", "Full"
 };
@@ -73,6 +78,46 @@ 
 	"Unknown", "System", "Device"
 };
 
+static ssize_t power_supply_show_usb_type(struct device *dev,
+					  enum power_supply_usb_type *usb_types,
+					  ssize_t num_usb_types,
+					  union power_supply_propval *value,
+					  char *buf)
+{
+	enum power_supply_usb_type usb_type;
+	ssize_t count = 0;
+	bool match = false;
+	int i;
+
+	if ((!usb_types) || (num_usb_types <= 0)) {
+		dev_warn(dev, "driver has no valid connected types\n");
+		return -ENODATA;
+	}
+
+	for (i = 0; i < num_usb_types; ++i) {
+		usb_type = usb_types[i];
+
+		if (value->intval == usb_type) {
+			count += sprintf(buf + count, "[%s] ",
+					 power_supply_usb_type_text[usb_type]);
+			match = true;
+		} else {
+			count += sprintf(buf + count, "%s ",
+					 power_supply_usb_type_text[usb_type]);
+		}
+	}
+
+	if (!match) {
+		dev_warn(dev, "driver reporting unsupported connected type\n");
+		return -EINVAL;
+	}
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+
 static ssize_t power_supply_show_property(struct device *dev,
 					  struct device_attribute *attr,
 					  char *buf) {
@@ -115,6 +160,10 @@  static ssize_t power_supply_show_property(struct device *dev,
 	else if (off == POWER_SUPPLY_PROP_TYPE)
 		return sprintf(buf, "%s\n",
 			       power_supply_type_text[value.intval]);
+	else if (off == POWER_SUPPLY_PROP_USB_TYPE)
+		return power_supply_show_usb_type(dev, psy->desc->usb_types,
+						  psy->desc->num_usb_types,
+						  &value, buf);
 	else if (off == POWER_SUPPLY_PROP_SCOPE)
 		return sprintf(buf, "%s\n",
 			       power_supply_scope_text[value.intval]);
@@ -241,6 +290,7 @@  static ssize_t power_supply_store_property(struct device *dev,
 	POWER_SUPPLY_ATTR(time_to_full_now),
 	POWER_SUPPLY_ATTR(time_to_full_avg),
 	POWER_SUPPLY_ATTR(type),
+	POWER_SUPPLY_ATTR(usb_type),
 	POWER_SUPPLY_ATTR(scope),
 	POWER_SUPPLY_ATTR(precharge_current),
 	POWER_SUPPLY_ATTR(charge_term_current),
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 79e90b3..4ca8876 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -145,6 +145,7 @@  enum power_supply_property {
 	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
 	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
 	POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
+	POWER_SUPPLY_PROP_USB_TYPE,
 	POWER_SUPPLY_PROP_SCOPE,
 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
@@ -170,6 +171,19 @@  enum power_supply_type {
 	POWER_SUPPLY_TYPE_APPLE_BRICK_ID,	/* Apple Charging Method */
 };
 
+enum power_supply_usb_type {
+	POWER_SUPPLY_USB_TYPE_UNKNOWN = 0,
+	POWER_SUPPLY_USB_TYPE_SDP,		/* Standard Downstream Port */
+	POWER_SUPPLY_USB_TYPE_DCP,		/* Dedicated Charging Port */
+	POWER_SUPPLY_USB_TYPE_CDP,		/* Charging Downstream Port */
+	POWER_SUPPLY_USB_TYPE_ACA,		/* Accessory Charger Adapters */
+	POWER_SUPPLY_USB_TYPE_C,		/* Type C Port */
+	POWER_SUPPLY_USB_TYPE_PD,		/* Power Delivery Port */
+	POWER_SUPPLY_USB_TYPE_PD_DRP,		/* PD Dual Role Port */
+	POWER_SUPPLY_USB_TYPE_PD_PPS,		/* PD Programmable Power Supply */
+	POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID,	/* Apple Charging Method */
+};
+
 enum power_supply_notifier_events {
 	PSY_EVENT_PROP_CHANGED,
 };
@@ -196,6 +210,8 @@  struct power_supply_config {
 struct power_supply_desc {
 	const char *name;
 	enum power_supply_type type;
+	enum power_supply_usb_type *usb_types;
+	size_t num_usb_types;
 	enum power_supply_property *properties;
 	size_t num_properties;