Commit cf450041 authored by Adam Thomson's avatar Adam Thomson Committed by Greg Kroah-Hartman

power: supply: Add 'usb_type' property and supporting code

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: default avatarAdam Thomson <Adam.Thomson.Opensource@diasemi.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: default avatarSebastian Reichel <sebastian.reichel@collabora.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1ac3eef7
...@@ -409,6 +409,18 @@ Description: ...@@ -409,6 +409,18 @@ Description:
Access: Read Access: Read
Valid values: Represented in 1/10 Degrees Celsius 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 What: /sys/class/power_supply/<supply_name>/voltage_max
Date: January 2008 Date: January 2008
Contact: linux-pm@vger.kernel.org Contact: linux-pm@vger.kernel.org
......
...@@ -843,7 +843,7 @@ __power_supply_register(struct device *parent, ...@@ -843,7 +843,7 @@ __power_supply_register(struct device *parent,
{ {
struct device *dev; struct device *dev;
struct power_supply *psy; struct power_supply *psy;
int rc; int i, rc;
if (!parent) if (!parent)
pr_warn("%s: Expected proper parent device for '%s'\n", pr_warn("%s: Expected proper parent device for '%s'\n",
...@@ -852,6 +852,12 @@ __power_supply_register(struct device *parent, ...@@ -852,6 +852,12 @@ __power_supply_register(struct device *parent,
if (!desc || !desc->name || !desc->properties || !desc->num_properties) if (!desc || !desc->name || !desc->properties || !desc->num_properties)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
for (i = 0; i < desc->num_properties; ++i) {
if ((desc->properties[i] == POWER_SUPPLY_PROP_USB_TYPE) &&
(!desc->usb_types || !desc->num_usb_types))
return ERR_PTR(-EINVAL);
}
psy = kzalloc(sizeof(*psy), GFP_KERNEL); psy = kzalloc(sizeof(*psy), GFP_KERNEL);
if (!psy) if (!psy)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -46,6 +46,11 @@ static const char * const power_supply_type_text[] = { ...@@ -46,6 +46,11 @@ static const char * const power_supply_type_text[] = {
"USB_PD", "USB_PD_DRP", "BrickID" "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[] = { static const char * const power_supply_status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full" "Unknown", "Charging", "Discharging", "Not charging", "Full"
}; };
...@@ -73,6 +78,41 @@ static const char * const power_supply_scope_text[] = { ...@@ -73,6 +78,41 @@ static const char * const power_supply_scope_text[] = {
"Unknown", "System", "Device" "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;
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, static ssize_t power_supply_show_property(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) { char *buf) {
...@@ -115,6 +155,10 @@ static ssize_t power_supply_show_property(struct device *dev, ...@@ -115,6 +155,10 @@ static ssize_t power_supply_show_property(struct device *dev,
else if (off == POWER_SUPPLY_PROP_TYPE) else if (off == POWER_SUPPLY_PROP_TYPE)
return sprintf(buf, "%s\n", return sprintf(buf, "%s\n",
power_supply_type_text[value.intval]); 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) else if (off == POWER_SUPPLY_PROP_SCOPE)
return sprintf(buf, "%s\n", return sprintf(buf, "%s\n",
power_supply_scope_text[value.intval]); power_supply_scope_text[value.intval]);
...@@ -241,6 +285,7 @@ static struct device_attribute power_supply_attrs[] = { ...@@ -241,6 +285,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(time_to_full_now), POWER_SUPPLY_ATTR(time_to_full_now),
POWER_SUPPLY_ATTR(time_to_full_avg), POWER_SUPPLY_ATTR(time_to_full_avg),
POWER_SUPPLY_ATTR(type), POWER_SUPPLY_ATTR(type),
POWER_SUPPLY_ATTR(usb_type),
POWER_SUPPLY_ATTR(scope), POWER_SUPPLY_ATTR(scope),
POWER_SUPPLY_ATTR(precharge_current), POWER_SUPPLY_ATTR(precharge_current),
POWER_SUPPLY_ATTR(charge_term_current), POWER_SUPPLY_ATTR(charge_term_current),
......
...@@ -145,6 +145,7 @@ enum power_supply_property { ...@@ -145,6 +145,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_PRECHARGE_CURRENT, POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
...@@ -170,6 +171,19 @@ enum power_supply_type { ...@@ -170,6 +171,19 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */ 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 { enum power_supply_notifier_events {
PSY_EVENT_PROP_CHANGED, PSY_EVENT_PROP_CHANGED,
}; };
...@@ -196,6 +210,8 @@ struct power_supply_config { ...@@ -196,6 +210,8 @@ struct power_supply_config {
struct power_supply_desc { struct power_supply_desc {
const char *name; const char *name;
enum power_supply_type type; enum power_supply_type type;
enum power_supply_usb_type *usb_types;
size_t num_usb_types;
enum power_supply_property *properties; enum power_supply_property *properties;
size_t num_properties; size_t num_properties;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment