Skip to content

Commit e3ee0e7

Browse files
pcercueigregkh
authored andcommitted
usb: common: usb-conn-gpio: Register charger
Register a power supply charger, whose online state depends on whether the USB role is set to device or not. This is useful when the USB role is the only way to know if the device is charging from USB. The API is the standard power supply charger API, you get a /sys/class/power_supply/xxx/online node which tells you the state of the charger. The sole purpose of this is to give userspace applications a way to know whether or not the charger is plugged. Signed-off-by: Paul Cercueil <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ab4dc05 commit e3ee0e7

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

drivers/usb/common/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ config USB_CONN_GPIO
4040
tristate "USB GPIO Based Connection Detection Driver"
4141
depends on GPIOLIB
4242
select USB_ROLE_SWITCH
43+
select POWER_SUPPLY
4344
help
4445
The driver supports USB role switch between host and device via GPIO
4546
based USB cable detection, used typically if an input GPIO is used

drivers/usb/common/usb-conn-gpio.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/of.h>
1818
#include <linux/pinctrl/consumer.h>
1919
#include <linux/platform_device.h>
20+
#include <linux/power_supply.h>
2021
#include <linux/regulator/consumer.h>
2122
#include <linux/usb/role.h>
2223

@@ -38,6 +39,9 @@ struct usb_conn_info {
3839
struct gpio_desc *vbus_gpiod;
3940
int id_irq;
4041
int vbus_irq;
42+
43+
struct power_supply_desc desc;
44+
struct power_supply *charger;
4145
};
4246

4347
/*
@@ -104,6 +108,8 @@ static void usb_conn_detect_cable(struct work_struct *work)
104108

105109
dev_dbg(info->dev, "vbus regulator is %s\n",
106110
regulator_is_enabled(info->vbus) ? "enabled" : "disabled");
111+
112+
power_supply_changed(info->charger);
107113
}
108114

109115
static void usb_conn_queue_dwork(struct usb_conn_info *info,
@@ -121,10 +127,35 @@ static irqreturn_t usb_conn_isr(int irq, void *dev_id)
121127
return IRQ_HANDLED;
122128
}
123129

130+
static enum power_supply_property usb_charger_properties[] = {
131+
POWER_SUPPLY_PROP_ONLINE,
132+
};
133+
134+
static int usb_charger_get_property(struct power_supply *psy,
135+
enum power_supply_property psp,
136+
union power_supply_propval *val)
137+
{
138+
struct usb_conn_info *info = power_supply_get_drvdata(psy);
139+
140+
switch (psp) {
141+
case POWER_SUPPLY_PROP_ONLINE:
142+
val->intval = info->last_role == USB_ROLE_DEVICE;
143+
break;
144+
default:
145+
return -EINVAL;
146+
}
147+
148+
return 0;
149+
}
150+
124151
static int usb_conn_probe(struct platform_device *pdev)
125152
{
126153
struct device *dev = &pdev->dev;
154+
struct power_supply_desc *desc;
127155
struct usb_conn_info *info;
156+
struct power_supply_config cfg = {
157+
.of_node = dev->of_node,
158+
};
128159
int ret = 0;
129160

130161
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
@@ -203,6 +234,20 @@ static int usb_conn_probe(struct platform_device *pdev)
203234
}
204235
}
205236

237+
desc = &info->desc;
238+
desc->name = "usb-charger";
239+
desc->properties = usb_charger_properties;
240+
desc->num_properties = ARRAY_SIZE(usb_charger_properties);
241+
desc->get_property = usb_charger_get_property;
242+
desc->type = POWER_SUPPLY_TYPE_USB;
243+
cfg.drv_data = info;
244+
245+
info->charger = devm_power_supply_register(dev, desc, &cfg);
246+
if (IS_ERR(info->charger)) {
247+
dev_err(dev, "Unable to register charger\n");
248+
return PTR_ERR(info->charger);
249+
}
250+
206251
platform_set_drvdata(pdev, info);
207252

208253
/* Perform initial detection */

0 commit comments

Comments
 (0)