Message ID | 20191211155032.167032-3-paul@crapouillou.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2,1/3] dt-bindings: power/supply: Document generic USB charger | expand |
On 19-12-11 16:50:32, Paul Cercueil wrote: > This simple charger driver uses the USB role switch framework to detect > the presence of a charger. The USB charger will report as online when > the USB role is set to device, and offline otherwise. > > Signed-off-by: Paul Cercueil <paul@crapouillou.net> > --- > > Notes: > v2: Instead of detecting charger state from USB PHY, we detect it from the > USB role in use. > > drivers/power/supply/Kconfig | 8 ++ > drivers/power/supply/Makefile | 1 + > drivers/power/supply/generic-usb-charger.c | 124 +++++++++++++++++++++ > 3 files changed, 133 insertions(+) > create mode 100644 drivers/power/supply/generic-usb-charger.c > > diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig > index 27164a1d3c7c..c4221bcabee4 100644 > --- a/drivers/power/supply/Kconfig > +++ b/drivers/power/supply/Kconfig > @@ -51,6 +51,14 @@ config GENERIC_ADC_BATTERY > Say Y here to enable support for the generic battery driver > which uses IIO framework to read adc. > > +config GENERIC_USB_CHARGER > + tristate "Generic USB charger" > + depends on USB_SUPPORT > + select USB_ROLE_SWITCH > + help > + Say Y here to enable a generic USB charger driver which uses > + the USB role switch framework to detect the presence of the charger. > + > config MAX8925_POWER > tristate "MAX8925 battery charger support" > depends on MFD_MAX8925 > diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile > index 6c7da920ea83..03f9b553bdfc 100644 > --- a/drivers/power/supply/Makefile > +++ b/drivers/power/supply/Makefile > @@ -8,6 +8,7 @@ power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o > obj-$(CONFIG_POWER_SUPPLY) += power_supply.o > obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o > obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o > +obj-$(CONFIG_GENERIC_USB_CHARGER) += generic-usb-charger.o > > obj-$(CONFIG_PDA_POWER) += pda_power.o > obj-$(CONFIG_APM_POWER) += apm_power.o > diff --git a/drivers/power/supply/generic-usb-charger.c b/drivers/power/supply/generic-usb-charger.c > new file mode 100644 > index 000000000000..0493fafbd4c0 > --- /dev/null > +++ b/drivers/power/supply/generic-usb-charger.c > @@ -0,0 +1,124 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Simple USB charger driver > + * Copyright (c) 2019 Paul Cercueil <paul@crapouillou.net> > + */ > + > +#include <linux/device.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/platform_device.h> > +#include <linux/power_supply.h> > +#include <linux/usb/role.h> > + > +struct usb_charger { > + struct notifier_block nb; > + struct usb_role_switch *role; > + struct power_supply_desc desc; > + struct power_supply *charger; > +}; > + > +static enum power_supply_property usb_charger_properties[] = { > + POWER_SUPPLY_PROP_ONLINE, > +}; > + > +static int usb_charger_get_property(struct power_supply *psy, > + enum power_supply_property psp, > + union power_supply_propval *val) > +{ > + struct usb_charger *charger = power_supply_get_drvdata(psy); > + enum usb_role role; > + > + switch (psp) { > + case POWER_SUPPLY_PROP_ONLINE: > + role = usb_role_switch_get_role(charger->role); > + val->intval = role == USB_ROLE_DEVICE; > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int usb_charger_event(struct notifier_block *nb, > + unsigned long event, void *d) > +{ > + struct usb_charger *charger = container_of(nb, struct usb_charger, nb); > + > + power_supply_changed(charger->charger); > + > + return 0; > +} > + > +static void usb_charger_unregister(void *data) > +{ > + struct usb_charger *charger = data; > + > + usb_role_switch_unregister_notifier(charger->role, &charger->nb); > +} > + > +static int usb_charger_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct power_supply_desc *desc; > + struct usb_charger *charger; > + struct power_supply_config cfg = { > + .of_node = dev->of_node, > + }; > + int err; > + > + charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL); > + if (!charger) > + return -ENOMEM; > + > + cfg.drv_data = charger; > + charger->nb.notifier_call = usb_charger_event; > + > + charger->role = usb_role_switch_get(dev); > + if (IS_ERR(charger->role)) { > + if (PTR_ERR(charger->role) != -EPROBE_DEFER) > + dev_err(dev, "Unable to get USB role"); > + return PTR_ERR(charger->role); > + } > + > + desc = &charger->desc; > + desc->name = "usb-charger"; > + desc->properties = usb_charger_properties; > + desc->num_properties = ARRAY_SIZE(usb_charger_properties); > + desc->get_property = usb_charger_get_property; > + desc->type = POWER_SUPPLY_TYPE_USB; What's your further plan for this generic USB charger? To support BC1.2, we need to know charger type, and how we could get it? Peter > + > + charger->charger = devm_power_supply_register(dev, desc, &cfg); > + if (IS_ERR(charger->charger)) { > + dev_err(dev, "Unable to register charger"); > + return PTR_ERR(charger->charger); > + } > + > + err = usb_role_switch_register_notifier(charger->role, &charger->nb); > + if (err) { > + dev_err(dev, "Unable to register USB role switch notifier"); > + return err; > + } > + > + return devm_add_action_or_reset(dev, usb_charger_unregister, charger); > +} > + > +static const struct of_device_id usb_charger_of_match[] = { > + { .compatible = "usb-charger" }, > + { /* sentinel */ }, > +}; > +MODULE_DEVICE_TABLE(of, usb_charger_of_match); > + > +static struct platform_driver usb_charger_driver = { > + .driver = { > + .name = "usb-charger", > + .of_match_table = of_match_ptr(usb_charger_of_match), > + }, > + .probe = usb_charger_probe, > +}; > +module_platform_driver(usb_charger_driver); > + > +MODULE_DESCRIPTION("Simple USB charger driver"); > +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); > +MODULE_LICENSE("GPL"); > -- > 2.24.0 >
Hi Peter, Le jeu., déc. 12, 2019 at 09:18, Peter Chen <peter.chen@nxp.com> a écrit : > On 19-12-11 16:50:32, Paul Cercueil wrote: >> This simple charger driver uses the USB role switch framework to >> detect >> the presence of a charger. The USB charger will report as online >> when >> the USB role is set to device, and offline otherwise. >> >> Signed-off-by: Paul Cercueil <paul@crapouillou.net> >> --- >> >> Notes: >> v2: Instead of detecting charger state from USB PHY, we detect >> it from the >> USB role in use. >> >> drivers/power/supply/Kconfig | 8 ++ >> drivers/power/supply/Makefile | 1 + >> drivers/power/supply/generic-usb-charger.c | 124 >> +++++++++++++++++++++ >> 3 files changed, 133 insertions(+) >> create mode 100644 drivers/power/supply/generic-usb-charger.c >> >> diff --git a/drivers/power/supply/Kconfig >> b/drivers/power/supply/Kconfig >> index 27164a1d3c7c..c4221bcabee4 100644 >> --- a/drivers/power/supply/Kconfig >> +++ b/drivers/power/supply/Kconfig >> @@ -51,6 +51,14 @@ config GENERIC_ADC_BATTERY >> Say Y here to enable support for the generic battery driver >> which uses IIO framework to read adc. >> >> +config GENERIC_USB_CHARGER >> + tristate "Generic USB charger" >> + depends on USB_SUPPORT >> + select USB_ROLE_SWITCH >> + help >> + Say Y here to enable a generic USB charger driver which uses >> + the USB role switch framework to detect the presence of the >> charger. >> + >> config MAX8925_POWER >> tristate "MAX8925 battery charger support" >> depends on MFD_MAX8925 >> diff --git a/drivers/power/supply/Makefile >> b/drivers/power/supply/Makefile >> index 6c7da920ea83..03f9b553bdfc 100644 >> --- a/drivers/power/supply/Makefile >> +++ b/drivers/power/supply/Makefile >> @@ -8,6 +8,7 @@ power_supply-$(CONFIG_LEDS_TRIGGERS) += >> power_supply_leds.o >> obj-$(CONFIG_POWER_SUPPLY) += power_supply.o >> obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o >> obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o >> +obj-$(CONFIG_GENERIC_USB_CHARGER) += generic-usb-charger.o >> >> obj-$(CONFIG_PDA_POWER) += pda_power.o >> obj-$(CONFIG_APM_POWER) += apm_power.o >> diff --git a/drivers/power/supply/generic-usb-charger.c >> b/drivers/power/supply/generic-usb-charger.c >> new file mode 100644 >> index 000000000000..0493fafbd4c0 >> --- /dev/null >> +++ b/drivers/power/supply/generic-usb-charger.c >> @@ -0,0 +1,124 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Simple USB charger driver >> + * Copyright (c) 2019 Paul Cercueil <paul@crapouillou.net> >> + */ >> + >> +#include <linux/device.h> >> +#include <linux/module.h> >> +#include <linux/of.h> >> +#include <linux/platform_device.h> >> +#include <linux/power_supply.h> >> +#include <linux/usb/role.h> >> + >> +struct usb_charger { >> + struct notifier_block nb; >> + struct usb_role_switch *role; >> + struct power_supply_desc desc; >> + struct power_supply *charger; >> +}; >> + >> +static enum power_supply_property usb_charger_properties[] = { >> + POWER_SUPPLY_PROP_ONLINE, >> +}; >> + >> +static int usb_charger_get_property(struct power_supply *psy, >> + enum power_supply_property psp, >> + union power_supply_propval *val) >> +{ >> + struct usb_charger *charger = power_supply_get_drvdata(psy); >> + enum usb_role role; >> + >> + switch (psp) { >> + case POWER_SUPPLY_PROP_ONLINE: >> + role = usb_role_switch_get_role(charger->role); >> + val->intval = role == USB_ROLE_DEVICE; >> + break; >> + default: >> + return -EINVAL; >> + } >> + >> + return 0; >> +} >> + >> +static int usb_charger_event(struct notifier_block *nb, >> + unsigned long event, void *d) >> +{ >> + struct usb_charger *charger = container_of(nb, struct >> usb_charger, nb); >> + >> + power_supply_changed(charger->charger); >> + >> + return 0; >> +} >> + >> +static void usb_charger_unregister(void *data) >> +{ >> + struct usb_charger *charger = data; >> + >> + usb_role_switch_unregister_notifier(charger->role, &charger->nb); >> +} >> + >> +static int usb_charger_probe(struct platform_device *pdev) >> +{ >> + struct device *dev = &pdev->dev; >> + struct power_supply_desc *desc; >> + struct usb_charger *charger; >> + struct power_supply_config cfg = { >> + .of_node = dev->of_node, >> + }; >> + int err; >> + >> + charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL); >> + if (!charger) >> + return -ENOMEM; >> + >> + cfg.drv_data = charger; >> + charger->nb.notifier_call = usb_charger_event; >> + >> + charger->role = usb_role_switch_get(dev); >> + if (IS_ERR(charger->role)) { >> + if (PTR_ERR(charger->role) != -EPROBE_DEFER) >> + dev_err(dev, "Unable to get USB role"); >> + return PTR_ERR(charger->role); >> + } >> + >> + desc = &charger->desc; >> + desc->name = "usb-charger"; >> + desc->properties = usb_charger_properties; >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); >> + desc->get_property = usb_charger_get_property; >> + desc->type = POWER_SUPPLY_TYPE_USB; > > What's your further plan for this generic USB charger? > To support BC1.2, we need to know charger type, and how > we could get it? > > Peter Well I don't really know. The USB role framework does not give any info about what's plugged. -Paul > >> + >> + charger->charger = devm_power_supply_register(dev, desc, &cfg); >> + if (IS_ERR(charger->charger)) { >> + dev_err(dev, "Unable to register charger"); >> + return PTR_ERR(charger->charger); >> + } >> + >> + err = usb_role_switch_register_notifier(charger->role, >> &charger->nb); >> + if (err) { >> + dev_err(dev, "Unable to register USB role switch notifier"); >> + return err; >> + } >> + >> + return devm_add_action_or_reset(dev, usb_charger_unregister, >> charger); >> +} >> + >> +static const struct of_device_id usb_charger_of_match[] = { >> + { .compatible = "usb-charger" }, >> + { /* sentinel */ }, >> +}; >> +MODULE_DEVICE_TABLE(of, usb_charger_of_match); >> + >> +static struct platform_driver usb_charger_driver = { >> + .driver = { >> + .name = "usb-charger", >> + .of_match_table = of_match_ptr(usb_charger_of_match), >> + }, >> + .probe = usb_charger_probe, >> +}; >> +module_platform_driver(usb_charger_driver); >> + >> +MODULE_DESCRIPTION("Simple USB charger driver"); >> +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); >> +MODULE_LICENSE("GPL"); >> -- >> 2.24.0 >> > > -- > > Thanks, > Peter Chen
> >> + > >> + desc = &charger->desc; > >> + desc->name = "usb-charger"; > >> + desc->properties = usb_charger_properties; > >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); > >> + desc->get_property = usb_charger_get_property; > >> + desc->type = POWER_SUPPLY_TYPE_USB; > > > > What's your further plan for this generic USB charger? > > To support BC1.2, we need to know charger type, and how we could get > > it? > > > > Peter > > Well I don't really know. The USB role framework does not give any info about > what's plugged. > What's the use case for this patch set? How it be used? Thanks, Peter > -Paul > > > > > >> + > >> + charger->charger = devm_power_supply_register(dev, desc, &cfg); > >> + if (IS_ERR(charger->charger)) { > >> + dev_err(dev, "Unable to register charger"); > >> + return PTR_ERR(charger->charger); > >> + } > >> + > >> + err = usb_role_switch_register_notifier(charger->role, > >> &charger->nb); > >> + if (err) { > >> + dev_err(dev, "Unable to register USB role switch notifier"); > >> + return err; > >> + } > >> + > >> + return devm_add_action_or_reset(dev, usb_charger_unregister, > >> charger); > >> +} > >> + > >> +static const struct of_device_id usb_charger_of_match[] = { > >> + { .compatible = "usb-charger" }, > >> + { /* sentinel */ }, > >> +}; > >> +MODULE_DEVICE_TABLE(of, usb_charger_of_match); + +static struct > >> platform_driver usb_charger_driver = { > >> + .driver = { > >> + .name = "usb-charger", > >> + .of_match_table = of_match_ptr(usb_charger_of_match), > >> + }, > >> + .probe = usb_charger_probe, > >> +}; > >> +module_platform_driver(usb_charger_driver); > >> + > >> +MODULE_DESCRIPTION("Simple USB charger driver"); > >> +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); > >> +MODULE_LICENSE("GPL"); > >> -- > >> 2.24.0 > >> > > > > -- > > > > Thanks, > > Peter Chen >
Hi Peter, Le lun., déc. 16, 2019 at 01:24, Peter Chen <peter.chen@nxp.com> a écrit : > >> >> + >> >> + desc = &charger->desc; >> >> + desc->name = "usb-charger"; >> >> + desc->properties = usb_charger_properties; >> >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); >> >> + desc->get_property = usb_charger_get_property; >> >> + desc->type = POWER_SUPPLY_TYPE_USB; >> > >> > What's your further plan for this generic USB charger? >> > To support BC1.2, we need to know charger type, and how we could >> get >> > it? >> > >> > Peter >> >> Well I don't really know. The USB role framework does not give any >> info about >> what's plugged. >> > > What's the use case for this patch set? How it be used? My devicetree: usb_otg: usb@13440000 { compatible = "ingenic,jz4770-musb", "simple-mfd"; reg = <0x13440000 0x10000>; [...] usb-role-switch; connector { compatible = "gpio-usb-b-connector", "usb-b-connector"; label = "mini-USB"; type = "mini"; id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; [...] }; usb_charger: usb-charger { compatible = "usb-charger"; }; }; The new gpio-usb-connector driver uses the ID/VBUS GPIOs to detect in which state (device, host, unconnected) a OTG connector is. However, that means I cannot use the standard gpio-charger driver to detect the presence of a charger based on the state of the VBUS gpio, since it's already requested here. So the point of this patchset is to provide an alternative to gpio-charger that works with OTG controllers compatible with 'usb-role-switch'. Cheers, -Paul >> > >> >> + >> >> + charger->charger = devm_power_supply_register(dev, desc, >> &cfg); >> >> + if (IS_ERR(charger->charger)) { >> >> + dev_err(dev, "Unable to register charger"); >> >> + return PTR_ERR(charger->charger); >> >> + } >> >> + >> >> + err = usb_role_switch_register_notifier(charger->role, >> >> &charger->nb); >> >> + if (err) { >> >> + dev_err(dev, "Unable to register USB role switch notifier"); >> >> + return err; >> >> + } >> >> + >> >> + return devm_add_action_or_reset(dev, usb_charger_unregister, >> >> charger); >> >> +} >> >> + >> >> +static const struct of_device_id usb_charger_of_match[] = { >> >> + { .compatible = "usb-charger" }, >> >> + { /* sentinel */ }, >> >> +}; >> >> +MODULE_DEVICE_TABLE(of, usb_charger_of_match); + +static >> struct >> >> platform_driver usb_charger_driver = { >> >> + .driver = { >> >> + .name = "usb-charger", >> >> + .of_match_table = of_match_ptr(usb_charger_of_match), >> >> + }, >> >> + .probe = usb_charger_probe, >> >> +}; >> >> +module_platform_driver(usb_charger_driver); >> >> + >> >> +MODULE_DESCRIPTION("Simple USB charger driver"); >> >> +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); >> >> +MODULE_LICENSE("GPL"); >> >> -- >> >> 2.24.0 >> >> >> > >> > -- >> > >> > Thanks, >> > Peter Chen >> >
> Le lun., déc. 16, 2019 at 01:24, Peter Chen <peter.chen@nxp.com> a écrit : > > > >> >> + > >> >> + desc = &charger->desc; > >> >> + desc->name = "usb-charger"; > >> >> + desc->properties = usb_charger_properties; > >> >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); > >> >> + desc->get_property = usb_charger_get_property; > >> >> + desc->type = POWER_SUPPLY_TYPE_USB; > >> > > >> > What's your further plan for this generic USB charger? > >> > To support BC1.2, we need to know charger type, and how we could > >> get > it? > >> > > >> > Peter > >> > >> Well I don't really know. The USB role framework does not give any > >> info about what's plugged. > >> > > > > What's the use case for this patch set? How it be used? > > My devicetree: > > usb_otg: usb@13440000 { > compatible = "ingenic,jz4770-musb", "simple-mfd"; > reg = <0x13440000 0x10000>; > [...] > > usb-role-switch; > > connector { > compatible = "gpio-usb-b-connector", "usb-b-connector"; > label = "mini-USB"; > type = "mini"; > > id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; > vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; > [...] > }; > > usb_charger: usb-charger { > compatible = "usb-charger"; > }; > }; > > The new gpio-usb-connector driver uses the ID/VBUS GPIOs to detect in > which state (device, host, unconnected) a OTG connector is. However, > that means I cannot use the standard gpio-charger driver to detect the > presence of a charger based on the state of the VBUS gpio, since it's > already requested here. So the point of this patchset is to provide an > alternative to gpio-charger that works with OTG controllers compatible > with 'usb-role-switch'. > Thanks for explaining it. What's the user for this USB charger, PMIC or what else? How the user uses this USB charger interface? Peter > > > >> > > >> >> + > >> >> + charger->charger = devm_power_supply_register(dev, desc, > >> &cfg); > >> >> + if (IS_ERR(charger->charger)) { > >> >> + dev_err(dev, "Unable to register charger"); > >> >> + return PTR_ERR(charger->charger); > >> >> + } > >> >> + > >> >> + err = usb_role_switch_register_notifier(charger->role, > >> >> &charger->nb); > >> >> + if (err) { > >> >> + dev_err(dev, "Unable to register USB role switch notifier"); > >> >> + return err; > >> >> + } > >> >> + > >> >> + return devm_add_action_or_reset(dev, usb_charger_unregister, > >> >> charger); > >> >> +} > >> >> + > >> >> +static const struct of_device_id usb_charger_of_match[] = { > >> >> + { .compatible = "usb-charger" }, > >> >> + { /* sentinel */ }, > >> >> +}; > >> >> +MODULE_DEVICE_TABLE(of, usb_charger_of_match); + +static > >> struct > >> >> platform_driver usb_charger_driver = { > >> >> + .driver = { > >> >> + .name = "usb-charger", > >> >> + .of_match_table = of_match_ptr(usb_charger_of_match), > >> >> + }, > >> >> + .probe = usb_charger_probe, > >> >> +}; > >> >> +module_platform_driver(usb_charger_driver); > >> >> + > >> >> +MODULE_DESCRIPTION("Simple USB charger driver"); > >> >> +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); > >> >> +MODULE_LICENSE("GPL"); > >> >> -- > >> >> 2.24.0 > >> >> > >> > > >> > -- > >> > > >> > Thanks, > >> > Peter Chen > >> > > >
Hi Peter, Le mar., déc. 17, 2019 at 01:32, Peter Chen <peter.chen@nxp.com> a écrit : > >> Le lun., déc. 16, 2019 at 01:24, Peter Chen <peter.chen@nxp.com> a >> écrit : >> > >> >> >> + >> >> >> + desc = &charger->desc; >> >> >> + desc->name = "usb-charger"; >> >> >> + desc->properties = usb_charger_properties; >> >> >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); >> >> >> + desc->get_property = usb_charger_get_property; >> >> >> + desc->type = POWER_SUPPLY_TYPE_USB; >> >> > >> >> > What's your further plan for this generic USB charger? >> >> > To support BC1.2, we need to know charger type, and how we >> could >> >> get > it? >> >> > >> >> > Peter >> >> >> >> Well I don't really know. The USB role framework does not give >> any >> >> info about what's plugged. >> >> >> > >> > What's the use case for this patch set? How it be used? >> >> My devicetree: >> >> usb_otg: usb@13440000 { >> compatible = "ingenic,jz4770-musb", "simple-mfd"; >> reg = <0x13440000 0x10000>; >> [...] >> >> usb-role-switch; >> >> connector { >> compatible = "gpio-usb-b-connector", "usb-b-connector"; >> label = "mini-USB"; >> type = "mini"; >> >> id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; >> vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; >> [...] >> }; >> >> usb_charger: usb-charger { >> compatible = "usb-charger"; >> }; >> }; >> >> The new gpio-usb-connector driver uses the ID/VBUS GPIOs to detect >> in >> which state (device, host, unconnected) a OTG connector is. However, >> that means I cannot use the standard gpio-charger driver to detect >> the >> presence of a charger based on the state of the VBUS gpio, since >> it's >> already requested here. So the point of this patchset is to provide >> an >> alternative to gpio-charger that works with OTG controllers >> compatible >> with 'usb-role-switch'. >> > > Thanks for explaining it. > > What's the user for this USB charger, PMIC or what else? How the > user uses > this USB charger interface? It's exported as a standard charger, so it can be passed to client drivers through devicetree, and its online status can be retrieved from sysfs. -Paul > >> >> >> >> > >> >> >> + >> >> >> + charger->charger = devm_power_supply_register(dev, desc, >> >> &cfg); >> >> >> + if (IS_ERR(charger->charger)) { >> >> >> + dev_err(dev, "Unable to register charger"); >> >> >> + return PTR_ERR(charger->charger); >> >> >> + } >> >> >> + >> >> >> + err = usb_role_switch_register_notifier(charger->role, >> >> >> &charger->nb); >> >> >> + if (err) { >> >> >> + dev_err(dev, "Unable to register USB role switch >> notifier"); >> >> >> + return err; >> >> >> + } >> >> >> + >> >> >> + return devm_add_action_or_reset(dev, >> usb_charger_unregister, >> >> >> charger); >> >> >> +} >> >> >> + >> >> >> +static const struct of_device_id usb_charger_of_match[] = { >> >> >> + { .compatible = "usb-charger" }, >> >> >> + { /* sentinel */ }, >> >> >> +}; >> >> >> +MODULE_DEVICE_TABLE(of, usb_charger_of_match); + +static >> >> struct >> >> >> platform_driver usb_charger_driver = { >> >> >> + .driver = { >> >> >> + .name = "usb-charger", >> >> >> + .of_match_table = of_match_ptr(usb_charger_of_match), >> >> >> + }, >> >> >> + .probe = usb_charger_probe, >> >> >> +}; >> >> >> +module_platform_driver(usb_charger_driver); >> >> >> + >> >> >> +MODULE_DESCRIPTION("Simple USB charger driver"); >> >> >> +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); >> >> >> +MODULE_LICENSE("GPL"); >> >> >> -- >> >> >> 2.24.0 >> >> >> >> >> > >> >> > -- >> >> > >> >> > Thanks, >> >> > Peter Chen >> >> >> > >> >
> >> > > >> >> >> + > >> >> >> + desc = &charger->desc; > >> >> >> + desc->name = "usb-charger"; > >> >> >> + desc->properties = usb_charger_properties; > >> >> >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); > >> >> >> + desc->get_property = usb_charger_get_property; > >> >> >> + desc->type = POWER_SUPPLY_TYPE_USB; > >> >> > > >> >> > What's your further plan for this generic USB charger? > >> >> > To support BC1.2, we need to know charger type, and how we > >> could >> get > it? > >> >> > > >> >> > Peter > >> >> > >> >> Well I don't really know. The USB role framework does not give > >> any >> info about what's plugged. > >> >> > >> > > >> > What's the use case for this patch set? How it be used? > >> > >> My devicetree: > >> > >> usb_otg: usb@13440000 { > >> compatible = "ingenic,jz4770-musb", "simple-mfd"; > >> reg = <0x13440000 0x10000>; > >> [...] > >> > >> usb-role-switch; > >> > >> connector { > >> compatible = "gpio-usb-b-connector", "usb-b-connector"; > >> label = "mini-USB"; > >> type = "mini"; > >> > >> id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; > >> vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; > >> [...] > >> }; > >> > >> usb_charger: usb-charger { > >> compatible = "usb-charger"; > >> }; > >> }; > >> > >> The new gpio-usb-connector driver uses the ID/VBUS GPIOs to detect > >> in which state (device, host, unconnected) a OTG connector is. > >> However, that means I cannot use the standard gpio-charger driver to > >> detect the presence of a charger based on the state of the VBUS > >> gpio, since it's already requested here. So the point of this > >> patchset is to provide an alternative to gpio-charger that works > >> with OTG controllers compatible with 'usb-role-switch'. > >> > > > > Thanks for explaining it. > > > > What's the user for this USB charger, PMIC or what else? How the user > > uses this USB charger interface? > > It's exported as a standard charger, so it can be passed to client drivers through > devicetree, and its online status can be retrieved from sysfs. > Hi Paul, If you would like to get role from usb-role-switch, the udc driver may probably have already worked. There is a 'state' entry under the udc device to indicate USB Ch9 state. Try to see if it could satisfy your requirement. Peter
Hi Peter, Le mer., déc. 18, 2019 at 02:46, Peter Chen <peter.chen@nxp.com> a écrit : > >> >> > >> >> >> >> + >> >> >> >> + desc = &charger->desc; >> >> >> >> + desc->name = "usb-charger"; >> >> >> >> + desc->properties = usb_charger_properties; >> >> >> >> + desc->num_properties = >> ARRAY_SIZE(usb_charger_properties); >> >> >> >> + desc->get_property = usb_charger_get_property; >> >> >> >> + desc->type = POWER_SUPPLY_TYPE_USB; >> >> >> > >> >> >> > What's your further plan for this generic USB charger? >> >> >> > To support BC1.2, we need to know charger type, and how we >> >> could >> get > it? >> >> >> > >> >> >> > Peter >> >> >> >> >> >> Well I don't really know. The USB role framework does not >> give >> >> any >> info about what's plugged. >> >> >> >> >> > >> >> > What's the use case for this patch set? How it be used? >> >> >> >> My devicetree: >> >> >> >> usb_otg: usb@13440000 { >> >> compatible = "ingenic,jz4770-musb", "simple-mfd"; >> >> reg = <0x13440000 0x10000>; >> >> [...] >> >> >> >> usb-role-switch; >> >> >> >> connector { >> >> compatible = "gpio-usb-b-connector", "usb-b-connector"; >> >> label = "mini-USB"; >> >> type = "mini"; >> >> >> >> id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; >> >> vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; >> >> [...] >> >> }; >> >> >> >> usb_charger: usb-charger { >> >> compatible = "usb-charger"; >> >> }; >> >> }; >> >> >> >> The new gpio-usb-connector driver uses the ID/VBUS GPIOs to >> detect >> >> in which state (device, host, unconnected) a OTG connector is. >> >> However, that means I cannot use the standard gpio-charger >> driver to >> >> detect the presence of a charger based on the state of the VBUS >> >> gpio, since it's already requested here. So the point of this >> >> patchset is to provide an alternative to gpio-charger that works >> >> with OTG controllers compatible with 'usb-role-switch'. >> >> >> > >> > Thanks for explaining it. >> > >> > What's the user for this USB charger, PMIC or what else? How the >> user >> > uses this USB charger interface? >> >> It's exported as a standard charger, so it can be passed to client >> drivers through >> devicetree, and its online status can be retrieved from sysfs. >> > > Hi Paul, > > If you would like to get role from usb-role-switch, the udc driver > may probably have already worked. > There is a 'state' entry under the udc device to indicate USB Ch9 > state. Try to see if it could > satisfy your requirement. This is not the proper way to retrieve charger status. Linux supports chargers through the power supply subsystem, that's where it should be exported. Cheers, -Paul
On Mon, Dec 16, 2019 at 11:52:05AM +0100, Paul Cercueil wrote: > Hi Peter, > > > Le lun., déc. 16, 2019 at 01:24, Peter Chen <peter.chen@nxp.com> a écrit : > > > > > >> + > > > >> + desc = &charger->desc; > > > >> + desc->name = "usb-charger"; > > > >> + desc->properties = usb_charger_properties; > > > >> + desc->num_properties = ARRAY_SIZE(usb_charger_properties); > > > >> + desc->get_property = usb_charger_get_property; > > > >> + desc->type = POWER_SUPPLY_TYPE_USB; > > > > > > > > What's your further plan for this generic USB charger? > > > > To support BC1.2, we need to know charger type, and how we could > > > get > > > > it? > > > > > > > > Peter > > > > > > Well I don't really know. The USB role framework does not give any > > > info about > > > what's plugged. > > > > > > > What's the use case for this patch set? How it be used? > > My devicetree: > > usb_otg: usb@13440000 { > compatible = "ingenic,jz4770-musb", "simple-mfd"; > reg = <0x13440000 0x10000>; > [...] > > usb-role-switch; > > connector { > compatible = "gpio-usb-b-connector", "usb-b-connector"; > label = "mini-USB"; > type = "mini"; > > id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; > vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; > [...] > }; > > usb_charger: usb-charger { > compatible = "usb-charger"; What h/w device is this? > }; > }; > > The new gpio-usb-connector driver uses the ID/VBUS GPIOs to detect in which > state (device, host, unconnected) a OTG connector is. However, that means I > cannot use the standard gpio-charger driver to detect the presence of a > charger based on the state of the VBUS gpio, since it's already requested > here. So the point of this patchset is to provide an alternative to > gpio-charger that works with OTG controllers compatible with > 'usb-role-switch'. Why not fix gpio-charger or make whatever 'owns' vbus-gpios to register a charger device? I guess you could have Vbus sensing with no charging capability, but that sounds like a new property, not a node to me. Rob
Hi Rob, Le jeu., déc. 19, 2019 at 13:38, Rob Herring <robh@kernel.org> a écrit : > On Mon, Dec 16, 2019 at 11:52:05AM +0100, Paul Cercueil wrote: >> Hi Peter, >> >> >> Le lun., déc. 16, 2019 at 01:24, Peter Chen <peter.chen@nxp.com> a >> écrit : >> > >> > > >> + >> > > >> + desc = &charger->desc; >> > > >> + desc->name = "usb-charger"; >> > > >> + desc->properties = usb_charger_properties; >> > > >> + desc->num_properties = >> ARRAY_SIZE(usb_charger_properties); >> > > >> + desc->get_property = usb_charger_get_property; >> > > >> + desc->type = POWER_SUPPLY_TYPE_USB; >> > > > >> > > > What's your further plan for this generic USB charger? >> > > > To support BC1.2, we need to know charger type, and how we >> could >> > > get >> > > > it? >> > > > >> > > > Peter >> > > >> > > Well I don't really know. The USB role framework does not give >> any >> > > info about >> > > what's plugged. >> > > >> > >> > What's the use case for this patch set? How it be used? >> >> My devicetree: >> >> usb_otg: usb@13440000 { >> compatible = "ingenic,jz4770-musb", "simple-mfd"; >> reg = <0x13440000 0x10000>; >> [...] >> >> usb-role-switch; >> >> connector { >> compatible = "gpio-usb-b-connector", "usb-b-connector"; >> label = "mini-USB"; >> type = "mini"; >> >> id-gpios = <&gpf 18 GPIO_ACTIVE_HIGH>; >> vbus-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>; >> [...] >> }; >> >> usb_charger: usb-charger { >> compatible = "usb-charger"; > > What h/w device is this? GCW Zero: arch/mips/boot/dts/ingenic/gcw0.dts Most of it isn't upstream, so I can still experiment things to get the perfect devicetree. > >> }; >> }; >> >> The new gpio-usb-connector driver uses the ID/VBUS GPIOs to detect >> in which >> state (device, host, unconnected) a OTG connector is. However, that >> means I >> cannot use the standard gpio-charger driver to detect the presence >> of a >> charger based on the state of the VBUS gpio, since it's already >> requested >> here. So the point of this patchset is to provide an alternative to >> gpio-charger that works with OTG controllers compatible with >> 'usb-role-switch'. > > Why not fix gpio-charger or make whatever 'owns' vbus-gpios to > register > a charger device? I see there is a GPIOD_FLAGS_BIT_NONEXCLUSIVE bit that could be used, I'll have a look. Thanks, -Paul > > I guess you could have Vbus sensing with no charging capability, but > that sounds like a new property, not a node to me. > > Rob
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 27164a1d3c7c..c4221bcabee4 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -51,6 +51,14 @@ config GENERIC_ADC_BATTERY Say Y here to enable support for the generic battery driver which uses IIO framework to read adc. +config GENERIC_USB_CHARGER + tristate "Generic USB charger" + depends on USB_SUPPORT + select USB_ROLE_SWITCH + help + Say Y here to enable a generic USB charger driver which uses + the USB role switch framework to detect the presence of the charger. + config MAX8925_POWER tristate "MAX8925 battery charger support" depends on MFD_MAX8925 diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 6c7da920ea83..03f9b553bdfc 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -8,6 +8,7 @@ power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o obj-$(CONFIG_POWER_SUPPLY) += power_supply.o obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o +obj-$(CONFIG_GENERIC_USB_CHARGER) += generic-usb-charger.o obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o diff --git a/drivers/power/supply/generic-usb-charger.c b/drivers/power/supply/generic-usb-charger.c new file mode 100644 index 000000000000..0493fafbd4c0 --- /dev/null +++ b/drivers/power/supply/generic-usb-charger.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Simple USB charger driver + * Copyright (c) 2019 Paul Cercueil <paul@crapouillou.net> + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/usb/role.h> + +struct usb_charger { + struct notifier_block nb; + struct usb_role_switch *role; + struct power_supply_desc desc; + struct power_supply *charger; +}; + +static enum power_supply_property usb_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int usb_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct usb_charger *charger = power_supply_get_drvdata(psy); + enum usb_role role; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + role = usb_role_switch_get_role(charger->role); + val->intval = role == USB_ROLE_DEVICE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int usb_charger_event(struct notifier_block *nb, + unsigned long event, void *d) +{ + struct usb_charger *charger = container_of(nb, struct usb_charger, nb); + + power_supply_changed(charger->charger); + + return 0; +} + +static void usb_charger_unregister(void *data) +{ + struct usb_charger *charger = data; + + usb_role_switch_unregister_notifier(charger->role, &charger->nb); +} + +static int usb_charger_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct power_supply_desc *desc; + struct usb_charger *charger; + struct power_supply_config cfg = { + .of_node = dev->of_node, + }; + int err; + + charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + cfg.drv_data = charger; + charger->nb.notifier_call = usb_charger_event; + + charger->role = usb_role_switch_get(dev); + if (IS_ERR(charger->role)) { + if (PTR_ERR(charger->role) != -EPROBE_DEFER) + dev_err(dev, "Unable to get USB role"); + return PTR_ERR(charger->role); + } + + desc = &charger->desc; + desc->name = "usb-charger"; + desc->properties = usb_charger_properties; + desc->num_properties = ARRAY_SIZE(usb_charger_properties); + desc->get_property = usb_charger_get_property; + desc->type = POWER_SUPPLY_TYPE_USB; + + charger->charger = devm_power_supply_register(dev, desc, &cfg); + if (IS_ERR(charger->charger)) { + dev_err(dev, "Unable to register charger"); + return PTR_ERR(charger->charger); + } + + err = usb_role_switch_register_notifier(charger->role, &charger->nb); + if (err) { + dev_err(dev, "Unable to register USB role switch notifier"); + return err; + } + + return devm_add_action_or_reset(dev, usb_charger_unregister, charger); +} + +static const struct of_device_id usb_charger_of_match[] = { + { .compatible = "usb-charger" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, usb_charger_of_match); + +static struct platform_driver usb_charger_driver = { + .driver = { + .name = "usb-charger", + .of_match_table = of_match_ptr(usb_charger_of_match), + }, + .probe = usb_charger_probe, +}; +module_platform_driver(usb_charger_driver); + +MODULE_DESCRIPTION("Simple USB charger driver"); +MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); +MODULE_LICENSE("GPL");
This simple charger driver uses the USB role switch framework to detect the presence of a charger. The USB charger will report as online when the USB role is set to device, and offline otherwise. Signed-off-by: Paul Cercueil <paul@crapouillou.net> --- Notes: v2: Instead of detecting charger state from USB PHY, we detect it from the USB role in use. drivers/power/supply/Kconfig | 8 ++ drivers/power/supply/Makefile | 1 + drivers/power/supply/generic-usb-charger.c | 124 +++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 drivers/power/supply/generic-usb-charger.c