Re: [PATCH 0/2] Introduce usb charger framework to deal with the usb gadget power negotation
On 8 August 2015 at 01:52, Greg KH gre...@linuxfoundation.org wrote: On Fri, Aug 07, 2015 at 04:19:40PM +0800, Baolin Wang wrote: On 7 August 2015 at 13:34, Peter Chen peter.c...@freescale.com wrote: On Thu, Aug 06, 2015 at 03:03:47PM +0800, Baolin Wang wrote: Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Baolin, thanks for introducing a framework for doing it, we do support USB Charger for chipidea driver at internal tree, but it is specific for imx, and still have some problems to upstream due to need to change some common code. One suggestion, would you add your user next time? In that case, we can know better for this framework. Peter, Thanks for your reviewing and comments. Now I just introduce the framework to review for more feedbacks and do not have a useful user to use it. I just can show you some example code to show how to use it. Thanks. Without a real, in-tree user, I can not accept this code. We don't add frameworks for non-existant things, otherwise it will be instantly ripped out the next kernel release. Please come up with at least 2 users, ideally 3, otherwise there's no real way to know if the framework is sufficient. OK, I'll try to come up with 2 or 3 users. Thanks. thanks, greg k-h -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] gadget: Support for the usb charger framework
On 8 August 2015 at 01:53, Greg KH gre...@linuxfoundation.org wrote: On Fri, Aug 07, 2015 at 05:22:47PM +0800, Baolin Wang wrote: On 7 August 2015 at 17:07, Peter Chen peter.c...@freescale.com wrote: /** * struct usb_udc - describes one usb device controller @@ -127,12 +128,45 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, +struct notifier_block *nb) { + unsigned long flags; + int ret; + + spin_lock_irqsave(gadget-lock, flags); I find you use so many spin_lock_irqsave, any reasons for that? Why mutex_lock can't be used? The spin_lock_irqsave() can make it as a atomic notifier, that can make sure the gadget state event can be quickly reported to the user who register a notifier on the gadget device. Is it OK? I don't think it is a good reason, spin_lock_irqsave is usually used for protecting data which is accessed at atomic environment. Yes, we want the notify process is a atomic environment which do not want to be interrupted by irq or other things to make the notice can be quickly reported to the user. No, this is a slow event, you don't need to notify anyone under atomic context, that's crazy. Also i think the notify process is less cost, thus i use the spinlock. Thanks. No, use a mutex please, that's the safe thing. This is not time-critical code at all. OK, Thanks for your comments and will fix the lock thing. thanks, greg k-h -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 0/3] Introduce usb charger framework to deal with the usb gadget power negotation
On 17 August 2015 at 16:20, Li Jun b47...@freescale.com wrote: On Mon, Aug 17, 2015 at 02:02:08PM +0800, Baolin Wang wrote: On 17 August 2015 at 09:15, Li Jun b47...@freescale.com wrote: On Fri, Aug 14, 2015 at 07:04:56PM +0800, Baolin Wang wrote: On 14 August 2015 at 16:55, Li Jun b47...@freescale.com wrote: Hi Baolin, On Fri, Aug 14, 2015 at 05:47:43PM +0800, Baolin Wang wrote: Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Why not add power supply class support into this? Hi Jun, We don't need the power supply class support into the usb charger, I suppose usb charger is also a power supply for the system, we can use power supply class framework for notify mechanism and get/set many attributes(maybe also the current limit), I see those usb charger drivers under ./driver/power/ are designed with power supply supported. I don't think so. The usb charger is rely on the usb gadget, which is not a complete power supply device and it combines the usb and the power supply. Thus we make it into usb gadget system. Thanks. Why it cannot be a complete power supply device? I was thinking this framework can cover it, I have no doubt on putting this framework into gadget system, but still can't understand why we don't need power supply class at all for a usb charger, or you think introduce power supply into usb gadget is not a right direction from code structure point view? We just do not think the usb charger as a real device, which is only used to set the current limitation when the usb charger state is changed detecting by extcon device or usb gadget. So we just need one message to notify the power user to set the current limitation when uab charge is added or removed. I also agree with the power supply framework can cover it, but we don't need to implement it to be another power supply, cause there is a real device as the power supply to deal with the power issue in the system. Thanks. Li Jun Li Jun just introduce the notify mechanism for power to set the current limit when notifying some events from usb charger. Maybe I misunderstand your meanings, please describe it detailedly. Thanks for your comments. Li Jun -- Baolin.wang Best Regards -- Baolin.wang Best Regards -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/3] gadget: Introduce the usb charger framework
On 18 August 2015 at 01:24, Mark Brown broo...@kernel.org wrote: On Mon, Aug 17, 2015 at 11:03:26AM +0800, Baolin Wang wrote: On 14 August 2015 at 23:27, Greg KH gre...@linuxfoundation.org wrote: On Fri, Aug 14, 2015 at 05:47:45PM +0800, Baolin Wang wrote: + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. I have to ask, do you really mean any later version? I think I did not get your point, could you explain it detailedly? Unlike a lot of userspace projects the kernel is normally just licensed under GPLv2 without the option to relicense with a later version so the ...or any later version is a bit unusual. There is some controversy about some of the changes in GPLv3. Make sense. Thanks a lot. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [Device-mainlining] [PATCH v2 2/3] gadget: Introduce the usb charger framework
On 17 August 2015 at 23:25, Tim Bird tim.b...@sonymobile.com wrote: On 08/16/2015 08:03 PM, Baolin Wang via device-mainlining wrote: On 14 August 2015 at 23:27, Greg KH gre...@linuxfoundation.org wrote: On Fri, Aug 14, 2015 at 05:47:45PM +0800, Baolin Wang wrote: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. I have to ask, do you really mean any later version? I think I did not get your point, could you explain it detailedly? The full kernel is licensed under v2 of the GPL only, not any later version. See the second paragraph at the top of the COPYING file in the root directory of the kernel source tree. There are differences on individual files, but having this file allow any later version makes it different from much of rest of the kernel. Unless you have a specific reason to allow greater-than-V2 GPL licensing on this file, you should change the licensing clause. The following wording appears to be pretty popular: * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. Hi Tim, Make sense of it. Thanks for your explanation. -- Tim -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 3/3] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown broo...@kernel.org Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..72c661f 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include linux/platform_device.h #include linux/power_supply.h #include linux/slab.h +#include linux/usb/usb_charger.h #include linux/mfd/wm831x/core.h #include linux/mfd/wm831x/auxadc.h @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In miliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit wm831x_usb_limits[i] + wm831x_usb_limits[best] wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power-wm831x-dev, + Limiting USB current to %dmA, wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power-wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata wm831x_pdata-usb_gadget) { + power-usb_charger = + usb_charger_find_by_name(wm831x_pdata-usb_gadget); + if (IS_ERR(power-usb_charger)) { + ret = PTR_ERR(power-usb_charger); + dev_err(pdev-dev, + Failed to find USB gadget: %d\n, ret); + goto err_bat_irq; + } + + power-usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power-usb_charger, + power-usb_notify); + if (ret != 0) { + dev_err(pdev-dev, + Failed to register notifier: %d\n, ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + usb_charger_put(power-usb_charger); err_bat_irq: --i; for (; i = 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power-wm831x; int irq, i; + if (wm831x_power-usb_charger) { + usb_charger_unregister_notify(wm831x_power-usb_charger, + wm831x_power-usb_notify); + usb_charger_put(wm831x_power-usb_charger); + } + for (i = 0; i ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo
[PATCH v3 2/3] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 538 +++ include/linux/usb/usb_charger.h | 138 ++ 4 files changed, 684 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bcf83c0..3d2b959 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool USB charger support + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source drivers/usb/gadget/udc/Kconfig # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..93fd36f --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,538 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = usb-charger, + .dev_name = usb-charger, +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t cur_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, %d %d %d %d\n, +uchger-cur_limit.sdp_cur_limit, +uchger-cur_limit.dcp_cur_limit, +uchger-cur_limit.cdp_cur_limit, +uchger-cur_limit.aca_cur_limit); +} + +static ssize_t cur_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + struct usb_charger_cur_limit cur; + int ret; + + ret = sscanf(buf, %d %d %d %d, +cur.sdp_cur_limit, cur.dcp_cur_limit, +cur.cdp_cur_limit, cur.aca_cur_limit); + if (ret == 0) + return -EINVAL; + + ret = usb_charger_set_cur_limit(uchger, cur); + if (ret 0) + return ret; + + return count; +} +static DEVICE_ATTR_RW(cur_limit); + +static struct attribute *usb_charger_attrs[] = { + dev_attr_cur_limit.attr, + NULL
[PATCH v3 0/3] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v2: - Use macro DEVICE_ATTR_RW()/ATTRIBUTE_GROUPS() and change the method to register the attruibutes. - Remove the 'name' and 'entry' member of struct 'usb_charger'. - Replace devm_kzalloc() with kzalloc() to follow the the lifetime rules. - Other modifications. Baolin Wang (3): gadget: Support for the usb charger framework gadget: Introduce the usb charger framework power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 + drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 538 + drivers/usb/gadget/udc/udc-core.c | 41 ++- include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 20 ++ include/linux/usb/usb_charger.h | 138 ++ 8 files changed, 816 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 1/3] gadget: Support for the usb charger framework
The usb charger framework is based on usb gadget, and each usb gadget can be one usb charger to set the current limitation. This patch adds a notifier mechanism for usb charger to report to usb charger when the usb gadget state is changed. Also we introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 41 - include/linux/usb/gadget.h| 20 ++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..1971218 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -129,6 +130,32 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_register(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_unregister(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ /** @@ -226,6 +253,10 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget-udc; + mutex_lock(gadget-lock); + raw_notifier_call_chain(gadget-nh, gadget-state, gadget); + mutex_unlock(gadget-lock); + if (udc) sysfs_notify(udc-dev.kobj, NULL, state); } @@ -364,6 +395,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(gadget-dev, gadget); INIT_WORK(gadget-work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(gadget-nh); + mutex_init(gadget-lock); gadget-dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -405,8 +438,13 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(udc_lock); - return 0; + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(udc-dev); err4: list_del(udc-list); mutex_unlock(udc_lock); @@ -481,6 +519,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); + usb_charger_exit(gadget); device_unregister(gadget-dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c14a69b..78cc862 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -609,6 +610,9 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + struct raw_notifier_headnh; + struct usb_charger *uchger; + struct mutexlock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1183,6 +1187,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + /* utility to set gadget state properly
Re: [PATCH v4 5/5] power: wm831x_power: Support USB charger current limit management
On 20 August 2015 at 00:24, Mark Brown broo...@kernel.org wrote: On Wed, Aug 19, 2015 at 05:13:48PM +0800, Baolin Wang wrote: Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown broo...@kernel.org Signed-off-by: Baolin Wang baolin.w...@linaro.org When people (like Charles and Lee have) have reviewed a change you should add any tags they gave when you resend the change so they don't have to duplicate their work and other people know that the review has happened. Make sense. Thanks. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 3/5] gadget: Support for the usb charger framework
On 19 August 2015 at 20:56, Sergei Shtylyov sergei.shtyl...@cogentembedded.com wrote: Hello. On 8/19/2015 12:13 PM, Baolin Wang wrote: For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org [...] diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 755e8bc..44d82f5 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); ^^^ please use space, not tab here OK. }; /** @@ -611,6 +612,7 @@ struct usb_gadget { struct usb_otg_caps *otg_caps; struct raw_notifier_headnh; struct mutexlock; + struct usb_charger *uchger; Why not simply call the field 'charger'? :-) I think 'uchger' is the abbreviation of 'usb charger' which is maybe a little verbous, I'll change it. Thanks for your comments. [...] WBR, Sergei -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 5/5] power: wm831x_power: Support USB charger current limit management
On 19 August 2015 at 17:56, Lee Jones lee.jo...@linaro.org wrote: On Wed, 19 Aug 2015, Baolin Wang wrote: Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown broo...@kernel.org Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ I'm not going to keep reviewing this. You should carry forward any Acks received onto subsequent submissions yourself. OK, thanks. 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..72c661f 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include linux/platform_device.h #include linux/power_supply.h #include linux/slab.h +#include linux/usb/usb_charger.h #include linux/mfd/wm831x/core.h #include linux/mfd/wm831x/auxadc.h @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In miliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, +unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, + struct wm831x_power, + usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit wm831x_usb_limits[i] + wm831x_usb_limits[best] wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power-wm831x-dev, + Limiting USB current to %dmA, wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power-wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata wm831x_pdata-usb_gadget) { + power-usb_charger = + usb_charger_find_by_name(wm831x_pdata-usb_gadget); + if (IS_ERR(power-usb_charger)) { + ret = PTR_ERR(power-usb_charger); + dev_err(pdev-dev, + Failed to find USB gadget: %d\n, ret); + goto err_bat_irq; + } + + power-usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power-usb_charger, + power-usb_notify); + if (ret != 0) { + dev_err(pdev-dev, + Failed to register notifier: %d\n, ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + usb_charger_put(power-usb_charger); err_bat_irq: --i; for (; i = 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power-wm831x; int irq, i; + if (wm831x_power-usb_charger) { + usb_charger_unregister_notify(wm831x_power-usb_charger, + wm831x_power-usb_notify); + usb_charger_put(wm831x_power-usb_charger); + } + for (i = 0; i ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int
[PATCH v4 3/5] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c |8 include/linux/usb/gadget.h|2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 4238fc3..370376e 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -437,8 +438,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(udc_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(udc-dev); err4: list_del(udc-list); mutex_unlock(udc_lock); @@ -513,6 +520,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); + usb_charger_exit(gadget); device_unregister(gadget-dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 755e8bc..451ad32 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -611,6 +612,7 @@ struct usb_gadget { struct usb_otg_caps *otg_caps; struct raw_notifier_headnh; struct mutexlock; + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 5/5] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown broo...@kernel.org Signed-off-by: Baolin Wang baolin.w...@linaro.org Acked-by: Lee Jones lee.jo...@linaro.org Acked-by: Charles Keepax ckee...@opensource.wolfsonmicro.com Acked-by: Peter Chen peter.c...@freescale.com --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..33ae27a 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include linux/platform_device.h #include linux/power_supply.h #include linux/slab.h +#include linux/usb/usb_charger.h #include linux/mfd/wm831x/core.h #include linux/mfd/wm831x/auxadc.h @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit = wm831x_usb_limits[i] + wm831x_usb_limits[best] wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power-wm831x-dev, + Limiting USB current to %dmA, wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power-wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata wm831x_pdata-usb_gadget) { + power-usb_charger = + usb_charger_find_by_name(wm831x_pdata-usb_gadget); + if (IS_ERR(power-usb_charger)) { + ret = PTR_ERR(power-usb_charger); + dev_err(pdev-dev, + Failed to find USB gadget: %d\n, ret); + goto err_bat_irq; + } + + power-usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power-usb_charger, + power-usb_notify); + if (ret != 0) { + dev_err(pdev-dev, + Failed to register notifier: %d\n, ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i = 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power-wm831x; int irq, i; + if (wm831x_power-usb_charger) { + usb_charger_unregister_notify(wm831x_power-usb_charger, + wm831x_power-usb_notify); + /* Free charger */ + } + for (i = 0; i ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; -- 1.7.9.5 -- To unsubscribe from
[PATCH v4 4/5] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/charger.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 35b46c1..a919f38 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -181,6 +181,13 @@ int usb_charger_unregister_notify(struct usb_charger *uchger, enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { + if (uchger-gadget uchger-gadget-ops +uchger-gadget-ops-get_charger_type) + uchger-type = + uchger-gadget-ops-get_charger_type(uchger-gadget); + else + uchger-type = UNKNOWN_TYPE; + return uchger-type; } @@ -313,7 +320,8 @@ static int usb_charger_plug_by_gadget(struct notifier_block *nb, unsigned long state, void *data) { - struct usb_charger *uchger = NULL; + struct usb_gadget *gadget = (struct usb_gadget *)data; + struct usb_charger *uchger = gadget-charger; enum usb_charger_state uchger_state; if (!uchger) @@ -480,6 +488,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger-gadget = ugadget; + ugadget-charger = uchger; uchger-old_gadget_state = ugadget-state; uchger-gadget_nb.notifier_call = usb_charger_plug_by_gadget; usb_gadget_register_notify(ugadget, uchger-gadget_nb); @@ -503,7 +512,7 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - struct usb_charger *uchger = NULL; + struct usb_charger *uchger = ugadget-charger; if (!uchger) return -EINVAL; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 3/3] power: wm831x_power: Support USB charger current limit management
On 20 August 2015 at 17:02, David Laight david.lai...@aculab.com wrote: From: Baolin Wang Sent: 14 August 2015 10:48 +/* In miliamps */ Spelling police: milliamps Hi David, I'll correct it in next patch series. Thanks for your comments. +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; David -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 1/3] gadget: Support for the usb charger framework
On 19 August 2015 at 00:04, Greg KH gre...@linuxfoundation.org wrote: On Tue, Aug 18, 2015 at 07:14:19PM +0800, Baolin Wang wrote: The usb charger framework is based on usb gadget, and each usb gadget can be one usb charger to set the current limitation. This patch adds a notifier mechanism for usb charger to report to usb charger when the usb gadget state is changed. Also we introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 41 - include/linux/usb/gadget.h| 20 ++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..1971218 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h You just broke the build, which proves you did not properly test this patch series, so why should we even consider it? Oh, I'm very sorry about that. I'll re-check my patch and test it carefully. Thanks for your comments. greg k-h -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 2/5] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 529 +++ include/linux/usb/usb_charger.h | 138 ++ 4 files changed, 675 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bcf83c0..3d2b959 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool USB charger support + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source drivers/usb/gadget/udc/Kconfig # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..35b46c1 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,529 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = usb-charger, + .dev_name = usb-charger, +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t cur_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, %d %d %d %d\n, +uchger-cur_limit.sdp_cur_limit, +uchger-cur_limit.dcp_cur_limit, +uchger-cur_limit.cdp_cur_limit, +uchger-cur_limit.aca_cur_limit); +} + +static ssize_t cur_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + struct usb_charger_cur_limit cur; + int ret; + + ret = sscanf(buf, %d %d %d %d, +cur.sdp_cur_limit, cur.dcp_cur_limit, +cur.cdp_cur_limit, cur.aca_cur_limit); + if (ret == 0) + return -EINVAL; + + ret = usb_charger_set_cur_limit(uchger, cur); + if (ret 0) + return ret; + + return count; +} +static DEVICE_ATTR_RW(cur_limit); + +static struct attribute *usb_charger_attrs[] = { + dev_attr_cur_limit.attr, + NULL
[PATCH v4 3/5] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c |8 include/linux/usb/gadget.h|2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 4238fc3..370376e 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -437,8 +438,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(udc_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(udc-dev); err4: list_del(udc-list); mutex_unlock(udc_lock); @@ -513,6 +520,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); + usb_charger_exit(gadget); device_unregister(gadget-dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 755e8bc..44d82f5 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -611,6 +612,7 @@ struct usb_gadget { struct usb_otg_caps *otg_caps; struct raw_notifier_headnh; struct mutexlock; + struct usb_charger *uchger; unsignedsg_supported:1; unsignedis_otg:1; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 4/5] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/charger.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 35b46c1..93fd36f 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -181,6 +181,13 @@ int usb_charger_unregister_notify(struct usb_charger *uchger, enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { + if (uchger-gadget uchger-gadget-ops +uchger-gadget-ops-get_charger_type) + uchger-type = + uchger-gadget-ops-get_charger_type(uchger-gadget); + else + uchger-type = UNKNOWN_TYPE; + return uchger-type; } @@ -313,7 +320,8 @@ static int usb_charger_plug_by_gadget(struct notifier_block *nb, unsigned long state, void *data) { - struct usb_charger *uchger = NULL; + struct usb_gadget *gadget = (struct usb_gadget *)data; + struct usb_charger *uchger = gadget-uchger; enum usb_charger_state uchger_state; if (!uchger) @@ -480,6 +488,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger-gadget = ugadget; + ugadget-uchger = uchger; uchger-old_gadget_state = ugadget-state; uchger-gadget_nb.notifier_call = usb_charger_plug_by_gadget; usb_gadget_register_notify(ugadget, uchger-gadget_nb); @@ -503,7 +512,7 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - struct usb_charger *uchger = NULL; + struct usb_charger *uchger = ugadget-uchger; if (!uchger) return -EINVAL; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 1/5] gadget: Introduce the notifier functions
The usb charger framework is based on usb gadget. The usb charger need to be notified the state changing of usb gadget to confirm the usb charger state. Thus this patch adds a notifier mechanism for usb gadget to report a event to usb charger when the usb gadget state is changed. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 32 include/linux/usb/gadget.h| 18 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..4238fc3 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -129,6 +129,32 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_register(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_unregister(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ /** @@ -226,6 +252,10 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget-udc; + mutex_lock(gadget-lock); + raw_notifier_call_chain(gadget-nh, gadget-state, gadget); + mutex_unlock(gadget-lock); + if (udc) sysfs_notify(udc-dev.kobj, NULL, state); } @@ -364,6 +394,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(gadget-dev, gadget); INIT_WORK(gadget-work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(gadget-nh); + mutex_init(gadget-lock); gadget-dev.parent = parent; #ifdef CONFIG_HAS_DMA diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c14a69b..755e8bc 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -609,6 +609,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + struct raw_notifier_headnh; + struct mutexlock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1183,6 +1185,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + /* utility to set gadget state properly */ extern void usb_gadget_set_state(struct usb_gadget *gadget, -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 0/5] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v3: - Re-order the patch and split the patch to avoid breaking build. - Other modifications. Baolin Wang (5): gadget: Introduce the notifier functions gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 + drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 538 + drivers/usb/gadget/udc/udc-core.c | 40 +++ include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 20 ++ include/linux/usb/usb_charger.h | 138 ++ 8 files changed, 816 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 5/5] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown broo...@kernel.org Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..72c661f 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include linux/platform_device.h #include linux/power_supply.h #include linux/slab.h +#include linux/usb/usb_charger.h #include linux/mfd/wm831x/core.h #include linux/mfd/wm831x/auxadc.h @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In miliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit wm831x_usb_limits[i] + wm831x_usb_limits[best] wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power-wm831x-dev, + Limiting USB current to %dmA, wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power-wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata wm831x_pdata-usb_gadget) { + power-usb_charger = + usb_charger_find_by_name(wm831x_pdata-usb_gadget); + if (IS_ERR(power-usb_charger)) { + ret = PTR_ERR(power-usb_charger); + dev_err(pdev-dev, + Failed to find USB gadget: %d\n, ret); + goto err_bat_irq; + } + + power-usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power-usb_charger, + power-usb_notify); + if (ret != 0) { + dev_err(pdev-dev, + Failed to register notifier: %d\n, ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + usb_charger_put(power-usb_charger); err_bat_irq: --i; for (; i = 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power-wm831x; int irq, i; + if (wm831x_power-usb_charger) { + usb_charger_unregister_notify(wm831x_power-usb_charger, + wm831x_power-usb_notify); + usb_charger_put(wm831x_power-usb_charger); + } + for (i = 0; i ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo
Re: [PATCH v2 1/3] gadget: Support for the usb charger framework
On 17 August 2015 at 08:40, Peter Chen peter.c...@freescale.com wrote: On Fri, Aug 14, 2015 at 05:47:44PM +0800, Baolin Wang wrote: The usb charger framework is based on usb gadget, and each usb gadget can be one usb charger to set the current limitation. This patch adds a notifier mechanism for usb charger to report to usb charger when the usb gadget state is changed. Also we introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 38 + include/linux/usb/gadget.h| 20 +++ 2 files changed, 58 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..47b231c 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -129,6 +130,32 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_register(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_unregister(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ /** @@ -226,6 +253,10 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget-udc; + mutex_lock(gadget-lock); + raw_notifier_call_chain(gadget-nh, gadget-state, gadget); + mutex_unlock(gadget-lock); + if (udc) sysfs_notify(udc-dev.kobj, NULL, state); } @@ -364,6 +395,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(gadget-dev, gadget); INIT_WORK(gadget-work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(gadget-nh); + mutex_init(gadget-lock); gadget-dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -405,6 +438,10 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(udc_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err4; + If the charger's initialization fails, you may need to call device_del(udc-dev). Yes, I missed that. Thanks for your comments. Peter return 0; err4: @@ -481,6 +518,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); + usb_charger_exit(gadget); device_unregister(gadget-dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c14a69b..78cc862 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -609,6 +610,9 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + struct raw_notifier_headnh; + struct usb_charger *uchger; + struct mutexlock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1183,6 +1187,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget
Re: [PATCH v2 2/3] gadget: Introduce the usb charger framework
On 14 August 2015 at 23:27, Greg KH gre...@linuxfoundation.org wrote: On Fri, Aug 14, 2015 at 05:47:45PM +0800, Baolin Wang wrote: This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 561 +++ include/linux/usb/usb_charger.h | 145 ++ 4 files changed, 714 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bcf83c0..3d2b959 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool USB charger support + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source drivers/usb/gadget/udc/Kconfig # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y := usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER)+= charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..f24f7b7 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,561 @@ +/* + * usb charger.c -- USB charger driver I think your company also wants a copyright line here. Not that it means anything at all, but some lawyers love cargo-cult text blobs. Hi Greg, Thanks for your reviewing and comments. I'll add it in next patch. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. I have to ask, do you really mean any later version? I think I did not get your point, could you explain it detailedly? + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT (50) +#define DEFAULT_SDP_CUR_LIMIT(500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = usb-charger, + .dev_name = usb-charger, +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t usb_charger_cur_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, %d %d %d %d\n, + uchger-cur_limit.sdp_cur_limit, + uchger-cur_limit.dcp_cur_limit, + uchger-cur_limit.cdp_cur_limit, + uchger-cur_limit.aca_cur_limit); +} + +static ssize_t usb_charger_cur_store(struct device *dev, + struct device_attribute *attr
Re: [PATCH v2 0/3] Introduce usb charger framework to deal with the usb gadget power negotation
On 17 August 2015 at 09:15, Li Jun b47...@freescale.com wrote: On Fri, Aug 14, 2015 at 07:04:56PM +0800, Baolin Wang wrote: On 14 August 2015 at 16:55, Li Jun b47...@freescale.com wrote: Hi Baolin, On Fri, Aug 14, 2015 at 05:47:43PM +0800, Baolin Wang wrote: Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Why not add power supply class support into this? Hi Jun, We don't need the power supply class support into the usb charger, I suppose usb charger is also a power supply for the system, we can use power supply class framework for notify mechanism and get/set many attributes(maybe also the current limit), I see those usb charger drivers under ./driver/power/ are designed with power supply supported. I don't think so. The usb charger is rely on the usb gadget, which is not a complete power supply device and it combines the usb and the power supply. Thus we make it into usb gadget system. Thanks. Li Jun just introduce the notify mechanism for power to set the current limit when notifying some events from usb charger. Maybe I misunderstand your meanings, please describe it detailedly. Thanks for your comments. Li Jun -- Baolin.wang Best Regards -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/charger.c| 547 +++ include/linux/usb/usb_charger.h | 101 2 files changed, 648 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..3ca0180 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,547 @@ +/* + * usb charger.c -- USB charger driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) + +static LIST_HEAD(usb_charger_list); +static DEFINE_MUTEX(usb_charger_list_lock); + +/* + * usb_charger_find_by_name - Get the usb charger device by name. + * @name - usb charger device name. + * + * notes: when this function walks the list and returns a charger + * it's dropped the lock which means that something else could come + * along and delete the charger before we dereference the pointer. + * It's very unlikely but it's a possibility so you should take care + * of it. + * Thus when you get the usb charger by name, you should call + * put_usb_charger() to derease the reference count of the usb charger. + * + * return the instance of usb charger device. + */ +struct usb_charger *usb_charger_find_by_name(char *name) +{ + struct usb_charger *uchger; + + if (!name) + return ERR_PTR(-EINVAL); + + mutex_lock(usb_charger_list_lock); + list_for_each_entry(uchger, usb_charger_list, entry) { + if (!strcmp(uchger-name, name)) { + get_usb_charger(uchger); + mutex_unlock(usb_charger_list_lock); + return uchger; + } + } + mutex_unlock(usb_charger_list_lock); + + return NULL; +} + +/* + * usb_charger_register_notify() - Register a notifiee to get notified by + * any attach status changes from the usb charger type detection. + * @uchger - the usb charger device which is monitored. + * @nb - a notifier block to be registered. + */ +void usb_charger_register_notify(struct usb_charger *uchger, +struct notifier_block *nb) +{ + unsigned long flags; + + spin_lock_irqsave(uchger-lock, flags); + raw_notifier_chain_register(uchger-uchger_nh, nb); + spin_unlock_irqrestore(uchger-lock, flags); +} + +/* + * usb_charger_unregister_notify() - Unregister a notifiee from the usb charger. + * @uchger - the usb charger device which is monitored. + * @nb - a notifier block to be unregistered. + */ +void usb_charger_unregister_notify(struct usb_charger *uchger, + struct notifier_block *nb) +{ + unsigned long flags; + + spin_lock_irqsave(uchger-lock, flags); + raw_notifier_chain_unregister(uchger-uchger_nh, nb); + spin_unlock_irqrestore(uchger-lock, flags); +} + +/* + * usb_charger_register_extcon_notifier() - Register a notifiee of the usb + * charger to get notified by any attach status changes from + * the extcon device. + * @uchger - the usb charger device. + * @edev - the extcon device. + * @extcon_id - extcon id. + */ +int usb_charger_register_extcon_notifier(struct
Re: [PATCH 1/2] gadget: Introduce the usb charger framework
On 7 August 2015 at 00:39, Greg KH gre...@linuxfoundation.org wrote: On Thu, Aug 06, 2015 at 03:03:48PM +0800, Baolin Wang wrote: This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/charger.c| 547 +++ include/linux/usb/usb_charger.h | 101 2 files changed, 648 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..3ca0180 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,547 @@ +/* + * usb charger.c -- USB charger driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. I have to ask, do you really mean any later version? I'll think about this and modify it. + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT (50) +#define DEFAULT_SDP_CUR_LIMIT(500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) + +static LIST_HEAD(usb_charger_list); +static DEFINE_MUTEX(usb_charger_list_lock); + +/* + * usb_charger_find_by_name - Get the usb charger device by name. + * @name - usb charger device name. + * + * notes: when this function walks the list and returns a charger + * it's dropped the lock which means that something else could come + * along and delete the charger before we dereference the pointer. + * It's very unlikely but it's a possibility so you should take care + * of it. + * Thus when you get the usb charger by name, you should call + * put_usb_charger() to derease the reference count of the usb charger. + * + * return the instance of usb charger device. + */ +struct usb_charger *usb_charger_find_by_name(char *name) +{ + struct usb_charger *uchger; + + if (!name) + return ERR_PTR(-EINVAL); + + mutex_lock(usb_charger_list_lock); + list_for_each_entry(uchger, usb_charger_list, entry) { + if (!strcmp(uchger-name, name)) { + get_usb_charger(uchger); + mutex_unlock(usb_charger_list_lock); + return uchger; + } + } + mutex_unlock(usb_charger_list_lock); + + return NULL; +} + +/* + * usb_charger_register_notify() - Register a notifiee to get notified by + * any attach status changes from the usb charger type detection. + * @uchger - the usb charger device which is monitored. + * @nb - a notifier block to be registered. + */ +void usb_charger_register_notify(struct usb_charger *uchger, + struct notifier_block *nb) +{ + unsigned long flags; + + spin_lock_irqsave(uchger-lock, flags); + raw_notifier_chain_register(uchger-uchger_nh, nb); + spin_unlock_irqrestore(uchger-lock, flags); +} + +/* + * usb_charger_unregister_notify() - Unregister a notifiee from the usb charger. + * @uchger - the usb charger device which is monitored. + * @nb - a notifier block to be unregistered. + */ +void usb_charger_unregister_notify(struct usb_charger *uchger, +struct notifier_block *nb) +{ + unsigned long flags; + + spin_lock_irqsave(uchger-lock, flags); + raw_notifier_chain_unregister(uchger-uchger_nh, nb); + spin_unlock_irqrestore(uchger-lock, flags
[PATCH 0/2] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Baolin Wang (2): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework drivers/usb/gadget/charger.c | 547 + drivers/usb/gadget/udc/udc-core.c | 41 +++ include/linux/usb/gadget.h| 20 ++ include/linux/usb/usb_charger.h | 101 +++ 4 files changed, 709 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] gadget: Support for the usb charger framework
The usb charger framework is based on usb gadget, and each usb gadget can be one usb charger to set the current limitation. This patch adds a notifier mechanism for usb charger to report to usb charger when the usb gadget state is changed. Also we introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 41 + include/linux/usb/gadget.h| 20 ++ 2 files changed, 61 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index d69c355..d5368088 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -127,12 +128,45 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(gadget-lock, flags); + ret = raw_notifier_chain_register(gadget-nh, nb); + spin_unlock_irqrestore(gadget-lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(gadget-lock, flags); + ret = raw_notifier_chain_unregister(gadget-nh, nb); + spin_unlock_irqrestore(gadget-lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ static void usb_gadget_state_work(struct work_struct *work) { struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget-udc; + unsigned long flags; + + spin_lock_irqsave(gadget-lock, flags); + raw_notifier_call_chain(gadget-nh, gadget-state, gadget); + spin_unlock_irqrestore(gadget-lock, flags); if (udc) sysfs_notify(udc-dev.kobj, NULL, state); @@ -272,6 +306,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(gadget-dev, gadget); INIT_WORK(gadget-work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(gadget-nh); + spin_lock_init(gadget-lock); gadget-dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -313,6 +349,10 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(udc_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err4; + return 0; err4: @@ -388,6 +428,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); + usb_charger_exit(gadget); device_unregister(gadget-dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 4f3dfb7..f24d6ac 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -492,6 +492,7 @@ struct usb_gadget_ops { int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); int (*udc_stop)(struct usb_gadget *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -559,6 +560,9 @@ struct usb_gadget { struct device dev; unsignedout_epnum; unsignedin_epnum; + struct raw_notifier_headnh; + struct usb_charger *uchger; + spinlock_t lock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1014,6 +1018,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + /* utility to set gadget state
Re: [PATCH 0/2] Introduce usb charger framework to deal with the usb gadget power negotation
On 7 August 2015 at 16:31, Peter Chen peter.c...@freescale.com wrote: Peter, Thanks for your reviewing and comments. Now I just introduce the framework to review for more feedbacks and do not have a useful user to use it. I just can show you some example code to show how to use it. Thanks. Felipe may not accept the code which are no user on it, I remember he said it before. Besides, if no user on it, how you test it? Make sense of it. I'll try to build the user to test it. Thanks for your reminding. Peter -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/2] Introduce usb charger framework to deal with the usb gadget power negotation
On 7 August 2015 at 13:34, Peter Chen peter.c...@freescale.com wrote: On Thu, Aug 06, 2015 at 03:03:47PM +0800, Baolin Wang wrote: Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Baolin, thanks for introducing a framework for doing it, we do support USB Charger for chipidea driver at internal tree, but it is specific for imx, and still have some problems to upstream due to need to change some common code. One suggestion, would you add your user next time? In that case, we can know better for this framework. Peter, Thanks for your reviewing and comments. Now I just introduce the framework to review for more feedbacks and do not have a useful user to use it. I just can show you some example code to show how to use it. Thanks. Baolin Wang (2): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework drivers/usb/gadget/charger.c | 547 + drivers/usb/gadget/udc/udc-core.c | 41 +++ include/linux/usb/gadget.h| 20 ++ include/linux/usb/usb_charger.h | 101 +++ 4 files changed, 709 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- Best Regards, Peter Chen -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] gadget: Introduce the usb charger framework
On 7 August 2015 at 13:41, Peter Chen peter.c...@freescale.com wrote: On Thu, Aug 06, 2015 at 03:03:48PM +0800, Baolin Wang wrote: This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/charger.c| 547 +++ include/linux/usb/usb_charger.h | 101 2 files changed, 648 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..3ca0180 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,547 @@ +/* + * usb charger.c -- USB charger driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT (50) +#define DEFAULT_SDP_CUR_LIMIT(500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT(1500 - DEFAULT_CUR_PROTECT) + +static LIST_HEAD(usb_charger_list); +static DEFINE_MUTEX(usb_charger_list_lock); + +/* + * usb_charger_find_by_name - Get the usb charger device by name. + * @name - usb charger device name. + * + * notes: when this function walks the list and returns a charger + * it's dropped the lock which means that something else could come + * along and delete the charger before we dereference the pointer. + * It's very unlikely but it's a possibility so you should take care + * of it. + * Thus when you get the usb charger by name, you should call + * put_usb_charger() to derease the reference count of the usb charger. + * + * return the instance of usb charger device. + */ +struct usb_charger *usb_charger_find_by_name(char *name) +{ + struct usb_charger *uchger; + + if (!name) + return ERR_PTR(-EINVAL); + + mutex_lock(usb_charger_list_lock); + list_for_each_entry(uchger, usb_charger_list, entry) { + if (!strcmp(uchger-name, name)) { + get_usb_charger(uchger); + mutex_unlock(usb_charger_list_lock); + return uchger; + } + } + mutex_unlock(usb_charger_list_lock); + + return NULL; +} + +/* + * usb_charger_register_notify() - Register a notifiee to get notified by + * any attach status changes from the usb charger type detection. + * @uchger - the usb charger device which is monitored. + * @nb - a notifier block to be registered. + */ +void usb_charger_register_notify(struct usb_charger *uchger, + struct notifier_block *nb) +{ + unsigned long flags; + + spin_lock_irqsave(uchger-lock, flags); + raw_notifier_chain_register(uchger-uchger_nh, nb); + spin_unlock_irqrestore(uchger-lock, flags); +} + +/* + * usb_charger_unregister_notify() - Unregister a notifiee from the usb charger. + * @uchger - the usb charger device which is monitored. + * @nb - a notifier block to be unregistered. + */ +void usb_charger_unregister_notify(struct usb_charger *uchger, +struct notifier_block *nb) +{ + unsigned long flags; + + spin_lock_irqsave(uchger-lock, flags); + raw_notifier_chain_unregister(uchger-uchger_nh, nb); + spin_unlock_irqrestore(uchger-lock, flags); +} + +/* + * usb_charger_register_extcon_notifier() - Register a notifiee of the usb + * charger
Re: [PATCH 2/2] gadget: Support for the usb charger framework
On 7 August 2015 at 13:45, Peter Chen peter.c...@freescale.com wrote: On Thu, Aug 06, 2015 at 03:03:49PM +0800, Baolin Wang wrote: The usb charger framework is based on usb gadget, and each usb gadget can be one usb charger to set the current limitation. This patch adds a notifier mechanism for usb charger to report to usb charger when the usb gadget state is changed. Also we introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 41 + include/linux/usb/gadget.h| 20 ++ 2 files changed, 61 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index d69c355..d5368088 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -127,12 +128,45 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(gadget-lock, flags); I find you use so many spin_lock_irqsave, any reasons for that? Why mutex_lock can't be used? The spin_lock_irqsave() can make it as a atomic notifier, that can make sure the gadget state event can be quickly reported to the user who register a notifier on the gadget device. Is it OK? -- Best Regards, Peter Chen -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] gadget: Support for the usb charger framework
On 7 August 2015 at 17:07, Peter Chen peter.c...@freescale.com wrote: /** * struct usb_udc - describes one usb device controller @@ -127,12 +128,45 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, +struct notifier_block *nb) { + unsigned long flags; + int ret; + + spin_lock_irqsave(gadget-lock, flags); I find you use so many spin_lock_irqsave, any reasons for that? Why mutex_lock can't be used? The spin_lock_irqsave() can make it as a atomic notifier, that can make sure the gadget state event can be quickly reported to the user who register a notifier on the gadget device. Is it OK? I don't think it is a good reason, spin_lock_irqsave is usually used for protecting data which is accessed at atomic environment. Yes, we want the notify process is a atomic environment which do not want to be interrupted by irq or other things to make the notice can be quickly reported to the user. Also i think the notify process is less cost, thus i use the spinlock. Thanks. Peter -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 0/3] Introduce usb charger framework to deal with the usb gadget power negotation
On 14 August 2015 at 16:55, Li Jun b47...@freescale.com wrote: Hi Baolin, On Fri, Aug 14, 2015 at 05:47:43PM +0800, Baolin Wang wrote: Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Why not add power supply class support into this? Hi Jun, We don't need the power supply class support into the usb charger, just introduce the notify mechanism for power to set the current limit when notifying some events from usb charger. Maybe I misunderstand your meanings, please describe it detailedly. Thanks for your comments. Li Jun -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/3] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 561 +++ include/linux/usb/usb_charger.h | 145 ++ 4 files changed, 714 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bcf83c0..3d2b959 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool USB charger support + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source drivers/usb/gadget/udc/Kconfig # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..f24f7b7 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,561 @@ +/* + * usb charger.c -- USB charger driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/device.h +#include linux/err.h +#include linux/extcon.h +#include linux/export.h +#include linux/kernel.h +#include linux/module.h +#include linux/of.h +#include linux/of_device.h +#include linux/of_address.h +#include linux/platform_device.h +#include linux/slab.h +#include linux/usb.h +#include linux/usb/ch9.h +#include linux/usb/gadget.h +#include linux/usb/usb_charger.h + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = usb-charger, + .dev_name = usb-charger, +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t usb_charger_cur_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, %d %d %d %d\n, +uchger-cur_limit.sdp_cur_limit, +uchger-cur_limit.dcp_cur_limit, +uchger-cur_limit.cdp_cur_limit, +uchger-cur_limit.aca_cur_limit); +} + +static ssize_t usb_charger_cur_store(struct device *dev, +struct device_attribute *attr, +const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + struct usb_charger_cur_limit cur; + int ret; + + ret = sscanf(buf, %d %d %d %d, +cur.sdp_cur_limit, cur.dcp_cur_limit, +cur.cdp_cur_limit, cur.aca_cur_limit); + if (ret == 0) + return -EINVAL; + + ret = usb_charger_set_cur_limit(uchger, cur); + if (ret 0) + return ret; + + return count; +} +static DEVICE_ATTR(cur_limit, 0644, usb_charger_cur_show
[PATCH v2 0/3] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v1: - Rebase my branch and re-create the patch series. - Remove the extcon wrappers and gadget wrappers for registering a notifier. - Remove the user count in usb charger. - Use idr instead of my own logic. - Replace the spinlock with mutex. - Use the list of driver core to manage the usb charger device. - Add the Kconfig and Makefile changes. - Add some attribute files to show or store the current limitation. - Introduce one user of usb charger by Mark Brown. - Other modifications. Baolin Wang (3): gadget: Support for the usb charger framework gadget: Introduce the usb charger framework power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 + drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 561 + drivers/usb/gadget/udc/udc-core.c | 38 +++ include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 20 ++ include/linux/usb/usb_charger.h | 145 ++ 8 files changed, 844 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/3] gadget: Support for the usb charger framework
The usb charger framework is based on usb gadget, and each usb gadget can be one usb charger to set the current limitation. This patch adds a notifier mechanism for usb charger to report to usb charger when the usb gadget state is changed. Also we introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/usb/gadget/udc/udc-core.c | 38 + include/linux/usb/gadget.h| 20 +++ 2 files changed, 58 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..47b231c 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include linux/usb/ch9.h #include linux/usb/gadget.h #include linux/usb.h +#include linux/usb/usb_charger.h /** * struct usb_udc - describes one usb device controller @@ -129,6 +130,32 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_register(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + int ret; + + mutex_lock(gadget-lock); + ret = raw_notifier_chain_unregister(gadget-nh, nb); + mutex_unlock(gadget-lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ /** @@ -226,6 +253,10 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget-udc; + mutex_lock(gadget-lock); + raw_notifier_call_chain(gadget-nh, gadget-state, gadget); + mutex_unlock(gadget-lock); + if (udc) sysfs_notify(udc-dev.kobj, NULL, state); } @@ -364,6 +395,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(gadget-dev, gadget); INIT_WORK(gadget-work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(gadget-nh); + mutex_init(gadget-lock); gadget-dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -405,6 +438,10 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(udc_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err4; + return 0; err4: @@ -481,6 +518,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); + usb_charger_exit(gadget); device_unregister(gadget-dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c14a69b..78cc862 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -609,6 +610,9 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + struct raw_notifier_headnh; + struct usb_charger *uchger; + struct mutexlock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1183,6 +1187,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + /* utility to set gadget state properly */ extern void usb_gadget_set_state(struct usb_gadget *gadget, -- 1.7.9.5 -- To unsubscribe from this list: send the line
[PATCH v2 3/3] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown broo...@kernel.org Signed-off-by: Baolin Wang baolin.w...@linaro.org --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..72c661f 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include linux/platform_device.h #include linux/power_supply.h #include linux/slab.h +#include linux/usb/usb_charger.h #include linux/mfd/wm831x/core.h #include linux/mfd/wm831x/auxadc.h @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In miliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit wm831x_usb_limits[i] + wm831x_usb_limits[best] wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power-wm831x-dev, + Limiting USB current to %dmA, wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power-wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata wm831x_pdata-usb_gadget) { + power-usb_charger = + usb_charger_find_by_name(wm831x_pdata-usb_gadget); + if (IS_ERR(power-usb_charger)) { + ret = PTR_ERR(power-usb_charger); + dev_err(pdev-dev, + Failed to find USB gadget: %d\n, ret); + goto err_bat_irq; + } + + power-usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power-usb_charger, + power-usb_notify); + if (ret != 0) { + dev_err(pdev-dev, + Failed to register notifier: %d\n, ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + usb_charger_put(power-usb_charger); err_bat_irq: --i; for (; i = 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power-wm831x; int irq, i; + if (wm831x_power-usb_charger) { + usb_charger_unregister_notify(wm831x_power-usb_charger, + wm831x_power-usb_notify); + usb_charger_put(wm831x_power-usb_charger); + } + for (i = 0; i ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo
[PATCH] usb: gadget: Add the console support for usb-to-serial port
It dose not work when we want to use the usb-to-serial port based on one usb gadget as a console. Thus this patch adds the console initialization to support this request. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |6 + drivers/usb/gadget/function/u_serial.c | 239 2 files changed, 245 insertions(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33834aa..be5aab9 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,12 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config U_SERIAL_CONSOLE + bool "Serial gadget console support" + depends on USB_G_SERIAL + help + It supports the serial gadget can be used as a console. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 9cc6a13..343d530 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "u_serial.h" @@ -79,6 +81,16 @@ */ #define QUEUE_SIZE 16 #define WRITE_BUF_SIZE 8192/* TX only */ +#define GS_BUFFER_SIZE (4096) +#define GS_CONSOLE_BUF_SIZE(2 * GS_BUFFER_SIZE) + +struct gscons_info { + struct gs_port *port; + struct tty_driver *tty_driver; + struct work_struct work; + int buf_tail; + charbuf[GS_CONSOLE_BUF_SIZE]; +}; /* circular buffer */ struct gs_buf { @@ -117,6 +129,7 @@ struct gs_port { /* REVISIT this state ... */ struct usb_cdc_line_coding port_line_coding;/* 8-N-1 etc */ + struct usb_request *console_req; }; static struct portmaster { @@ -1052,6 +1065,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) port->port_num = port_num; port->port_line_coding = *coding; + port->console_req = NULL; ports[port_num].port = port; out: @@ -1141,6 +1155,227 @@ err: } EXPORT_SYMBOL_GPL(gserial_alloc_line); +#ifdef CONFIG_U_SERIAL_CONSOLE + +static struct usb_request *gs_request_new(struct usb_ep *ep, int buffer_size) +{ + struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC); + + if (!req) + return NULL; + + /* now allocate buffers for the requests */ + req->buf = kmalloc(buffer_size, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + + return req; +} + +static void gs_request_free(struct usb_request *req, struct usb_ep *ep) +{ + if (req) { + kfree(req->buf); + usb_ep_free_request(ep, req); + } +} + +static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status != 0 && req->status != -ECONNRESET) + return; +} + +static struct console gserial_cons; +static int gs_console_connect(void) +{ + struct gscons_info *info = gserial_cons.data; + int port_num = gserial_cons.index; + struct usb_request *req; + struct gs_port *port; + struct usb_ep *ep; + + if (port_num >= MAX_U_SERIAL_PORTS || port_num < 0) { + pr_err("%s: port num [%d] exceeds the range.\n", + __func__, port_num); + return -ENXIO; + } + + port = ports[port_num].port; + if (!port) { + pr_err("%s: serial line [%d] not allocated.\n", + __func__, port_num); + return -ENODEV; + } + + if (!port->port_usb) { + pr_err("%s: no port usb.\n", __func__); + return -ENODEV; + } + + ep = port->port_usb->in; + if (!ep) { + pr_err("%s: no usb endpoint.\n", __func__); + return -ENXIO; + } + + req = port->console_req; + if (!req) { + req = gs_request_new(ep, GS_BUFFER_SIZE); + if (!req) { + pr_err("%s: request fail.\n", __func__); + return -ENOMEM; + } + req->complete = gs_complete_out; + } + + info->port = port; + + pr_debug("%s: port[%d] console connect!\n", __func__, port_num); + return 0; +} + +static void gs_console_work(struct work_struct *work) +{ + struct gscons_info *info = container_of(work, struct gscons_info, work); + struct gs_port *port = info->port; + struct usb_request *req; + struct usb_ep *ep; + int xfer, ret, count; + char *p;
Re: [PATCH v5 1/5] gadget: Introduce the notifier functions
On 7 November 2015 at 00:56, Greg KH <gre...@linuxfoundation.org> wrote: > On Fri, Nov 06, 2015 at 07:35:10PM +0800, Baolin Wang wrote: >> #ifdef CONFIG_HAS_DMA >> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h >> index c14a69b..755e8bc 100644 >> --- a/include/linux/usb/gadget.h >> +++ b/include/linux/usb/gadget.h >> @@ -609,6 +609,8 @@ struct usb_gadget { >> unsignedout_epnum; >> unsignedin_epnum; >> struct usb_otg_caps *otg_caps; >> + struct raw_notifier_headnh; >> + struct mutexlock; > > You have to document what this lock protects. OK. > > >> >> unsignedsg_supported:1; >> unsignedis_otg:1; >> @@ -1183,6 +1185,22 @@ extern void usb_gadget_unmap_request(struct >> usb_gadget *gadget, >> >> >> /*-*/ >> >> +/** >> + * Register a notifiee to get notified by any attach status changes from >> + * the usb gadget >> + */ > > kerneldoc does not belong in a .h file. > I'll remove the comments. > And the kbuild system found lots of problems with this series, please > fix those at the very least :( I'm sorry for that, I'll check the patches again. Thanks for your comments. > > thanks, > > greg k-h -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 1/4] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. It also supplies the notification mechanism to userspace When the usb charger state is changed. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. This patch doesn't yet integrate with the gadget code, so some functions which rely on the 'gadget' are not completed, that will be implemented in the following patches. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 574 +++ include/linux/usb/usb_charger.h | 162 +++ 4 files changed, 744 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33834aa..8d69dca 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..921f8e2 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,574 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define UCHGER_STATE_LENGTH(50) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = "usb-charger", + .dev_name = "usb-charger", +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t cur_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, "%d %d %d %d\n", +uchger->cur_limit.sdp_cur_limit, +uchger->cur_limit.dcp_cur_limit, +uchger->cur_limit.cdp_cur_limit, +uchger->cur_limit.aca_cur_limit); +} + +static ssize_t cur_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + struct usb_charger_cur_limit cur; + int ret; + + ret = sscanf(buf, "%d %d %d %d", +_cur_limit, _cur_limit, +_cur_limit, _cur_limit); + if (ret == 0) + return -EINVAL; + + ret = usb_charger_set_cur_limit(uchger, ); + if (ret < 0) + return re
[PATCH v6 4/4] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown <broo...@kernel.org> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> Acked-by: Lee Jones <lee.jo...@linaro.org> Acked-by: Charles Keepax <ckee...@opensource.wolfsonmicro.com> Acked-by: Peter Chen <peter.c...@freescale.com> Acked-by: Sebastian Reichel <s...@kernel.org> --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index 7082301..043f1f4 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %dmA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -607,8 +647,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata && wm831x_pdata->usb_gadget) { + power->usb_charger = + usb_charger_find_by_name(wm831x_pdata->usb_gadget); + if (IS_ERR(power->usb_charger)) { + ret = PTR_ERR(power->usb_charger); + dev_err(>dev, + "Failed to find USB gadget: %d\n", ret); + goto err_bat_irq; + } + + power->usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power->usb_charger, + >usb_notify); + if (ret != 0) { + dev_err(>dev, + "Failed to register notifier: %d\n", ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i >= 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_charger) { + usb_charger_unregister_notify(wm831x_power->usb_charger, + _power->usb_notify); + /* Free charger */ + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpi
[PATCH v6 3/4] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/charger.c | 43 -- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 921f8e2..5d3cda6 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -183,7 +183,11 @@ int usb_charger_unregister_notify(struct usb_charger *uchger, enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { - if (uchger->psy) { + if (uchger->gadget && uchger->gadget->ops + && uchger->gadget->ops->get_charger_type) { + uchger->type = + uchger->gadget->ops->get_charger_type(uchger->gadget); + } else if (uchger->psy) { union power_supply_propval val; power_supply_get_property(uchger->psy, @@ -385,6 +389,29 @@ usb_charger_plug_by_extcon(struct notifier_block *nb, int usb_charger_plug_by_gadget(struct usb_gadget *gadget, unsigned long state) { + struct usb_charger *uchger = gadget->charger; + enum usb_charger_state uchger_state; + + if (!uchger) + return -EINVAL; + + /* Report event to power to setting the current limitation +* for this usb charger when one usb charger state is changed +* with detecting by usb gadget state. +*/ + if (uchger->old_gadget_state != state) { + uchger->old_gadget_state = state; + + if (state >= USB_STATE_ATTACHED) + uchger_state = USB_CHARGER_PRESENT; + else if (state == USB_STATE_NOTATTACHED) + uchger_state = USB_CHARGER_REMOVE; + else + uchger_state = USB_CHARGER_DEFAULT; + + usb_charger_notify_others(uchger, uchger_state); + } + return 0; } @@ -540,6 +567,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger->gadget = ugadget; + ugadget->charger = uchger; uchger->old_gadget_state = ugadget->state; /* register a new usb charger */ @@ -560,7 +588,18 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - return 0; + struct usb_charger *uchger = ugadget->charger; + + if (!uchger) + return -EINVAL; + + if (uchger->extcon_dev) + extcon_unregister_notifier(uchger->extcon_dev, + EXTCON_USB, >extcon_nb.nb); + + ida_simple_remove(_charger_ida, uchger->id); + + return usb_charger_unregister(uchger); } static int __init usb_charger_sysfs_init(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v5: - Remove the notifier chain things from the gadget and introduce one callback function to report to the usb charger when the gadget state is changed. - Flesh out the port type detection which combines the USB negotiation and PMICs detection. - Supply the notification mechanism to userspace when charger state is changed. - Integrate with the vbus staff in the gadget API. Baolin Wang (4): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 + drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 613 + drivers/usb/gadget/udc/udc-core.c | 11 + include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 10 + include/linux/usb/usb_charger.h | 162 ++ 8 files changed, 876 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 2/4] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. It will report to the usb charger when the gadget state is changed, then the usb charger can do the power things. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 11 +++ include/linux/usb/gadget.h| 10 ++ 2 files changed, 21 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..2727f01 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include /** * struct usb_udc - describes one usb device controller @@ -226,6 +227,9 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget->udc; + /* when the gadget state is changed, then report to USB charger */ + usb_charger_plug_by_gadget(gadget, gadget->state); + if (udc) sysfs_notify(>dev.kobj, NULL, "state"); } @@ -405,8 +409,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(>dev); err4: list_del(>list); mutex_unlock(_lock); @@ -481,6 +491,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(>dev.kobj, KOBJ_REMOVE); flush_work(>work); device_unregister(>dev); + usb_charger_exit(gadget); device_unregister(>dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3d583a1..b8a6d38 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -24,6 +24,7 @@ #include #include #include +#include struct usb_ep; @@ -560,6 +561,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -632,6 +634,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + /* negotiate the power with the usb charger */ + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; @@ -836,10 +840,16 @@ static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) * reporting how much power the device may consume. For example, this * could affect how quickly batteries are recharged. * + * It will also notify the USB charger how much power the device may + * consume if there is a USB charger linking with the gadget. + * * Returns zero on success, else negative errno. */ static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { + if (gadget->charger) + usb_charger_set_cur_limit_by_type(gadget->charger, mA); + if (!gadget->ops->vbus_draw) return -EOPNOTSUPP; return gadget->ops->vbus_draw(gadget, mA); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] usb: gadget: Add the console support for usb-to-serial port
It dose not work when we want to use the usb-to-serial port based on one usb gadget as a console. Thus this patch adds the console initialization to support this request. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |6 + drivers/usb/gadget/function/u_serial.c | 238 2 files changed, 244 insertions(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33834aa..be5aab9 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,12 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config U_SERIAL_CONSOLE + bool "Serial gadget console support" + depends on USB_G_SERIAL + help + It supports the serial gadget can be used as a console. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index f7771d8..4ade527 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "u_serial.h" @@ -79,6 +80,16 @@ */ #define QUEUE_SIZE 16 #define WRITE_BUF_SIZE 8192/* TX only */ +#define GS_BUFFER_SIZE (4096) +#define GS_CONSOLE_BUF_SIZE(2 * GS_BUFFER_SIZE) + +struct gscons_info { + struct gs_port *port; + struct tty_driver *tty_driver; + struct work_struct work; + int buf_tail; + charbuf[GS_CONSOLE_BUF_SIZE]; +}; /* circular buffer */ struct gs_buf { @@ -118,6 +129,7 @@ struct gs_port { /* REVISIT this state ... */ struct usb_cdc_line_coding port_line_coding;/* 8-N-1 etc */ + struct usb_request *console_req; }; static struct portmaster { @@ -1054,6 +1066,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) port->port_num = port_num; port->port_line_coding = *coding; + port->console_req = NULL; ports[port_num].port = port; out: @@ -1143,6 +1156,227 @@ err: } EXPORT_SYMBOL_GPL(gserial_alloc_line); +#ifdef CONFIG_U_SERIAL_CONSOLE + +static struct usb_request *gs_request_new(struct usb_ep *ep, int buffer_size) +{ + struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC); + + if (!req) + return NULL; + + /* now allocate buffers for the requests */ + req->buf = kmalloc(buffer_size, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + + return req; +} + +static void gs_request_free(struct usb_request *req, struct usb_ep *ep) +{ + if (req) { + kfree(req->buf); + usb_ep_free_request(ep, req); + } +} + +static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status != 0 && req->status != -ECONNRESET) + return; +} + +static struct console gserial_cons; +static int gs_console_connect(void) +{ + struct gscons_info *info = gserial_cons.data; + int port_num = gserial_cons.index; + struct usb_request *req; + struct gs_port *port; + struct usb_ep *ep; + + if (port_num >= MAX_U_SERIAL_PORTS || port_num < 0) { + pr_err("%s: port num [%d] exceeds the range.\n", + __func__, port_num); + return -ENXIO; + } + + port = ports[port_num].port; + if (!port) { + pr_err("%s: serial line [%d] not allocated.\n", + __func__, port_num); + return -ENODEV; + } + + if (!port->port_usb) { + pr_err("%s: no port usb.\n", __func__); + return -ENODEV; + } + + ep = port->port_usb->in; + if (!ep) { + pr_err("%s: no usb endpoint.\n", __func__); + return -ENXIO; + } + + req = port->console_req; + if (!req) { + req = gs_request_new(ep, GS_BUFFER_SIZE); + if (!req) { + pr_err("%s: request fail.\n", __func__); + return -ENOMEM; + } + req->complete = gs_complete_out; + } + + info->port = port; + + pr_debug("%s: port[%d] console connect!\n", __func__, port_num); + return 0; +} + +static void gs_console_work(struct work_struct *work) +{ + struct gscons_info *info = container_of(work, struct gscons_info, work); + struct gs_port *port = info->port; + struct usb_request *req; + struct usb_ep *ep; + int xfer, ret, count; + char *p;
[PATCH v5 5/5] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown <broo...@kernel.org> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> Acked-by: Lee Jones <lee.jo...@linaro.org> Acked-by: Charles Keepax <ckee...@opensource.wolfsonmicro.com> Acked-by: Peter Chen <peter.c...@freescale.com> Acked-by: Sebastian Reichel <s...@kernel.org> --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..33ae27a 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %dmA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata && wm831x_pdata->usb_gadget) { + power->usb_charger = + usb_charger_find_by_name(wm831x_pdata->usb_gadget); + if (IS_ERR(power->usb_charger)) { + ret = PTR_ERR(power->usb_charger); + dev_err(>dev, + "Failed to find USB gadget: %d\n", ret); + goto err_bat_irq; + } + + power->usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power->usb_charger, + >usb_notify); + if (ret != 0) { + dev_err(>dev, + "Failed to register notifier: %d\n", ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i >= 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_charger) { + usb_charger_unregister_notify(wm831x_power->usb_charger, + _power->usb_notify); + /* Free charger */ + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpi
[PATCH v5 2/5] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. It also supplies the notification mechanism to userspace When the usb charger state is changed. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. This patch doesn't yet integrate with the gadget code, so some functions which rely on the 'gadget' are not completed, that will be implemented in the following patches. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 579 +++ include/linux/usb/usb_charger.h | 152 ++ 4 files changed, 739 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bcf83c0..3d2b959 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..8387820 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,579 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define UCHGER_STATE_LENGTH(50) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = "usb-charger", + .dev_name = "usb-charger", +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t cur_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, "%d %d %d %d\n", +uchger->cur_limit.sdp_cur_limit, +uchger->cur_limit.dcp_cur_limit, +uchger->cur_limit.cdp_cur_limit, +uchger->cur_limit.aca_cur_limit); +} + +static ssize_t cur_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + struct usb_charger_cur_limit cur; + int ret; + + ret = sscanf(buf, "%d %d %d %d", +_cur_limit, _cur_limit, +_cur_limit, _cur_limit); + if (ret == 0) + return -EINVAL; + + ret = usb_charger_set_cur_limit(uchger, ); + if (ret < 0) + return ret; + +
[PATCH v5 3/5] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c |8 include/linux/usb/gadget.h|9 + 2 files changed, 17 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 4238fc3..370376e 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include /** * struct usb_udc - describes one usb device controller @@ -437,8 +438,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(>dev); err4: list_del(>list); mutex_unlock(_lock); @@ -513,6 +520,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(>dev.kobj, KOBJ_REMOVE); flush_work(>work); device_unregister(>dev); + usb_charger_exit(gadget); device_unregister(>dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 755e8bc..c2610c4 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -24,6 +24,7 @@ #include #include #include +#include struct usb_ep; @@ -537,6 +538,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -611,6 +613,7 @@ struct usb_gadget { struct usb_otg_caps *otg_caps; struct raw_notifier_headnh; struct mutexlock; + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; @@ -815,10 +818,16 @@ static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) * reporting how much power the device may consume. For example, this * could affect how quickly batteries are recharged. * + * It will also notify the USB charger how much power the device may + * consume if there is a USB charger linking with the gadget. + * * Returns zero on success, else negative errno. */ static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { + if (gadget->charger) + usb_charger_set_cur_limit_by_type(gadget->charger, mA); + if (!gadget->ops->vbus_draw) return -EOPNOTSUPP; return gadget->ops->vbus_draw(gadget, mA); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 0/5] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v4: - Flesh out the port type detection which combines the USB negotiation and PMICs detection. - Supply the notification mechanism to userspace when charger state is changed. - Integrate with the vbus staff in the gadget API. Baolin Wang (5): gadget: Introduce the notifier functions gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 + drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 620 + drivers/usb/gadget/udc/udc-core.c | 40 +++ include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 27 ++ include/linux/usb/usb_charger.h | 152 + 8 files changed, 919 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 4/5] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/charger.c | 45 -- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 8387820..c260317 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -183,7 +183,11 @@ int usb_charger_unregister_notify(struct usb_charger *uchger, enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { - if (uchger->psy) { + if (uchger->gadget && uchger->gadget->ops + && uchger->gadget->ops->get_charger_type) { + uchger->type = + uchger->gadget->ops->get_charger_type(uchger->gadget); + } else if (uchger->psy) { union power_supply_propval val; power_supply_get_property(uchger->psy, @@ -387,6 +391,30 @@ static int usb_charger_plug_by_gadget(struct notifier_block *nb, unsigned long state, void *data) { + struct usb_gadget *gadget = (struct usb_gadget *)data; + struct usb_charger *uchger = gadget->charger; + enum usb_charger_state uchger_state; + + if (!uchger) + return NOTIFY_BAD; + + /* Report event to power to setting the current limitation +* for this usb charger when one usb charger state is changed +* with detecting by usb gadget state. +*/ + if (uchger->old_gadget_state != state) { + uchger->old_gadget_state = state; + + if (state >= USB_STATE_ATTACHED) + uchger_state = USB_CHARGER_PRESENT; + else if (state == USB_STATE_NOTATTACHED) + uchger_state = USB_CHARGER_REMOVE; + else + uchger_state = USB_CHARGER_DEFAULT; + + usb_charger_notify_others(uchger, uchger_state); + } + return NOTIFY_OK; } @@ -542,6 +570,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger->gadget = ugadget; + ugadget->charger = uchger; uchger->old_gadget_state = ugadget->state; uchger->gadget_nb.notifier_call = usb_charger_plug_by_gadget; usb_gadget_register_notify(ugadget, >gadget_nb); @@ -565,7 +594,19 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - return 0; + struct usb_charger *uchger = ugadget->charger; + + if (!uchger) + return -EINVAL; + + if (uchger->extcon_dev) + extcon_unregister_notifier(uchger->extcon_dev, + EXTCON_USB, >extcon_nb.nb); + + usb_gadget_unregister_notify(uchger->gadget, >gadget_nb); + ida_simple_remove(_charger_ida, uchger->id); + + return usb_charger_unregister(uchger); } static int __init usb_charger_sysfs_init(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 1/5] gadget: Introduce the notifier functions
The usb charger framework is based on usb gadget. The usb charger need to be notified the state changing of usb gadget to confirm the usb charger state. Thus this patch adds a notifier mechanism for usb gadget to report a event to usb charger when the usb gadget state is changed. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 32 include/linux/usb/gadget.h| 18 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..4238fc3 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -129,6 +129,32 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + int ret; + + mutex_lock(>lock); + ret = raw_notifier_chain_register(>nh, nb); + mutex_unlock(>lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + int ret; + + mutex_lock(>lock); + ret = raw_notifier_chain_unregister(>nh, nb); + mutex_unlock(>lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ /** @@ -226,6 +252,10 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget->udc; + mutex_lock(>lock); + raw_notifier_call_chain(>nh, gadget->state, gadget); + mutex_unlock(>lock); + if (udc) sysfs_notify(>dev.kobj, NULL, "state"); } @@ -364,6 +394,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(>dev, "gadget"); INIT_WORK(>work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(>nh); + mutex_init(>lock); gadget->dev.parent = parent; #ifdef CONFIG_HAS_DMA diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c14a69b..755e8bc 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -609,6 +609,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + struct raw_notifier_headnh; + struct mutexlock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1183,6 +1185,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + /* utility to set gadget state properly */ extern void usb_gadget_set_state(struct usb_gadget *gadget, -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
On 17 November 2015 at 21:34, Andy Shevchenko <andy.shevche...@gmail.com> wrote: > On Mon, Nov 16, 2015 at 9:05 AM, Baolin Wang <baolin.w...@linaro.org> wrote: >> It dose not work when we want to use the usb-to-serial port based >> on one usb gadget as a console. Thus this patch adds the console >> initialization to support this request. > > >> @@ -79,6 +80,16 @@ >> */ >> #define QUEUE_SIZE 16 >> #define WRITE_BUF_SIZE 8192/* TX only */ >> +#define GS_BUFFER_SIZE (4096) > > Redundant parens > OK. I'll remove it. >> +#define GS_CONSOLE_BUF_SIZE(2 * GS_BUFFER_SIZE) >> + >> +struct gscons_info { >> + struct gs_port *port; >> + struct tty_driver *tty_driver; >> + struct work_struct work; >> + int buf_tail; >> + charbuf[GS_CONSOLE_BUF_SIZE]; > > Can't be malloced once? > The 'gscons_info' structure is malloced once. > >> +static struct usb_request *gs_request_new(struct usb_ep *ep, int >> buffer_size) >> +{ >> + struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC); >> + >> + if (!req) > > For sake of readability it's better to have assignment explicitly before 'if'. But I think it is very easy to understand the assignment here with saving code lines. > >> + return NULL; >> + >> + /* now allocate buffers for the requests */ >> + req->buf = kmalloc(buffer_size, GFP_ATOMIC); >> + if (!req->buf) { >> + usb_ep_free_request(ep, req); >> + return NULL; >> + } >> + >> + return req; >> +} >> + >> +static void gs_request_free(struct usb_request *req, struct usb_ep *ep) >> +{ >> + if (req) { > > if (!req) > return; > > ? Make sense. > >> + kfree(req->buf); >> + usb_ep_free_request(ep, req); >> + } >> +} >> + >> +static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) >> +{ >> + if (req->status != 0 && req->status != -ECONNRESET) >> + return; > > Something missed here. Currently it's no-op. > Yeah. I didn't realize what need to do in the callback here, so just leave a callback without anything. But maybe something will be added if there are some requirements in future. >> +} >> + >> +static struct console gserial_cons; >> +static int gs_console_connect(void) >> +{ >> + struct gscons_info *info = gserial_cons.data; >> + int port_num = gserial_cons.index; >> + struct usb_request *req; >> + struct gs_port *port; >> + struct usb_ep *ep; >> + >> + if (port_num >= MAX_U_SERIAL_PORTS || port_num < 0) { >> + pr_err("%s: port num [%d] exceeds the range.\n", >> + __func__, port_num); >> + return -ENXIO; >> + } >> + >> + port = ports[port_num].port; >> + if (!port) { >> + pr_err("%s: serial line [%d] not allocated.\n", >> + __func__, port_num); >> + return -ENODEV; >> + } >> + >> + if (!port->port_usb) { >> + pr_err("%s: no port usb.\n", __func__); > > Starting from here could it be dev_err and so on? There are no dev_err things and device things in this file, so pr_xxx is more reasonable. > >> + return -ENODEV; >> + } >> + >> + ep = port->port_usb->in; >> + if (!ep) { >> + pr_err("%s: no usb endpoint.\n", __func__); >> + return -ENXIO; >> + } >> + >> + req = port->console_req; >> + if (!req) { >> + req = gs_request_new(ep, GS_BUFFER_SIZE); >> + if (!req) { >> + pr_err("%s: request fail.\n", __func__); >> + return -ENOMEM; >> + } >> + req->complete = gs_complete_out; >> + } >> + >> + info->port = port; >> + >> + pr_debug("%s: port[%d] console connect!\n", __func__, port_num); > > Dynamic debug will add function name if asked. Sorry, I didn't get your point, you mean print the function name is redundant here? > >> + return 0; >> +} >> + >> +static voi
[PATCH v4 0/5] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Providing a standard framework for doing this in the kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v3: - Re-order the patch and split the patch to avoid breaking build. - Other modifications. Baolin Wang (5): gadget: Introduce the notifier functions gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 + drivers/usb/gadget/Kconfig| 7 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/charger.c | 538 ++ drivers/usb/gadget/udc/udc-core.c | 40 +++ include/linux/mfd/wm831x/pdata.h | 3 + include/linux/usb/gadget.h| 20 ++ include/linux/usb/usb_charger.h | 138 ++ 8 files changed, 816 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 5/5] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown <broo...@kernel.org> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> Acked-by: Lee Jones <lee.jo...@linaro.org> Acked-by: Charles Keepax <ckee...@opensource.wolfsonmicro.com> Acked-by: Peter Chen <peter.c...@freescale.com> Acked-by: Sebastian Reichel <s...@kernel.org> --- drivers/power/wm831x_power.c | 69 include/linux/mfd/wm831x/pdata.h | 3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index db11ae6..33ae27a 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %dmA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -606,8 +646,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata && wm831x_pdata->usb_gadget) { + power->usb_charger = + usb_charger_find_by_name(wm831x_pdata->usb_gadget); + if (IS_ERR(power->usb_charger)) { + ret = PTR_ERR(power->usb_charger); + dev_err(>dev, + "Failed to find USB gadget: %d\n", ret); + goto err_bat_irq; + } + + power->usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power->usb_charger, + >usb_notify); + if (ret != 0) { + dev_err(>dev, + "Failed to register notifier: %d\n", ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i >= 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_charger) { + usb_charger_unregister_notify(wm831x_power->usb_charger, + _power->usb_notify); + /* Free charger */ + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int g
[PATCH v4 2/5] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig | 7 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/charger.c| 529 include/linux/usb/usb_charger.h | 138 +++ 4 files changed, 675 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bcf83c0..3d2b959 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..35b46c1 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,529 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = "usb-charger", + .dev_name = "usb-charger", +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t cur_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return scnprintf(buf, PAGE_SIZE, "%d %d %d %d\n", +uchger->cur_limit.sdp_cur_limit, +uchger->cur_limit.dcp_cur_limit, +uchger->cur_limit.cdp_cur_limit, +uchger->cur_limit.aca_cur_limit); +} + +static ssize_t cur_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + struct usb_charger_cur_limit cur; + int ret; + + ret = sscanf(buf, "%d %d %d %d", +_cur_limit, _cur_limit, +_cur_limit, _cur_limit); + if (ret == 0) + return -EINVAL; + + ret = usb_charger_set_cur_limit(uchger, ); + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_RW(cur_limit); + +static struct attribute *usb_charger_attrs[] = { + _attr_cur_limit.attr, + NULL +}; +ATTRIBUTE_GROUPS(usb_charger); + +/* + * usb_charger_find_by_name - Get the usb charger device by name. + * @name - usb charger device name. +
[PATCH v4 1/5] gadget: Introduce the notifier functions
The usb charger framework is based on usb gadget. The usb charger need to be notified the state changing of usb gadget to confirm the usb charger state. Thus this patch adds a notifier mechanism for usb gadget to report a event to usb charger when the usb gadget state is changed. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 32 include/linux/usb/gadget.h| 18 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..4238fc3 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -129,6 +129,32 @@ void usb_gadget_giveback_request(struct usb_ep *ep, } EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb) +{ + int ret; + + mutex_lock(>lock); + ret = raw_notifier_chain_register(>nh, nb); + mutex_unlock(>lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_notify); + +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb) +{ + int ret; + + mutex_lock(>lock); + ret = raw_notifier_chain_unregister(>nh, nb); + mutex_unlock(>lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_notify); + /* - */ /** @@ -226,6 +252,10 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget->udc; + mutex_lock(>lock); + raw_notifier_call_chain(>nh, gadget->state, gadget); + mutex_unlock(>lock); + if (udc) sysfs_notify(>dev.kobj, NULL, "state"); } @@ -364,6 +394,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, dev_set_name(>dev, "gadget"); INIT_WORK(>work, usb_gadget_state_work); + RAW_INIT_NOTIFIER_HEAD(>nh); + mutex_init(>lock); gadget->dev.parent = parent; #ifdef CONFIG_HAS_DMA diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c14a69b..755e8bc 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -609,6 +609,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + struct raw_notifier_headnh; + struct mutexlock; unsignedsg_supported:1; unsignedis_otg:1; @@ -1183,6 +1185,22 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget, /*-*/ +/** + * Register a notifiee to get notified by any attach status changes from + * the usb gadget + */ +int usb_gadget_register_notify(struct usb_gadget *gadget, + struct notifier_block *nb); + +/*-*/ + + +/* Unregister a notifiee from the usb gadget */ +int usb_gadget_unregister_notify(struct usb_gadget *gadget, +struct notifier_block *nb); + +/*-*/ + /* utility to set gadget state properly */ extern void usb_gadget_set_state(struct usb_gadget *gadget, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 3/5] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 8 include/linux/usb/gadget.h| 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 4238fc3..370376e 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include /** * struct usb_udc - describes one usb device controller @@ -437,8 +438,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(>dev); err4: list_del(>list); mutex_unlock(_lock); @@ -513,6 +520,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(>dev.kobj, KOBJ_REMOVE); flush_work(>work); device_unregister(>dev); + usb_charger_exit(gadget); device_unregister(>dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 755e8bc..451ad32 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -537,6 +537,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -611,6 +612,7 @@ struct usb_gadget { struct usb_otg_caps *otg_caps; struct raw_notifier_headnh; struct mutexlock; + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 4/5] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/charger.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 35b46c1..a919f38 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -181,6 +181,13 @@ int usb_charger_unregister_notify(struct usb_charger *uchger, enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { + if (uchger->gadget && uchger->gadget->ops + && uchger->gadget->ops->get_charger_type) + uchger->type = + uchger->gadget->ops->get_charger_type(uchger->gadget); + else + uchger->type = UNKNOWN_TYPE; + return uchger->type; } @@ -313,7 +320,8 @@ static int usb_charger_plug_by_gadget(struct notifier_block *nb, unsigned long state, void *data) { - struct usb_charger *uchger = NULL; + struct usb_gadget *gadget = (struct usb_gadget *)data; + struct usb_charger *uchger = gadget->charger; enum usb_charger_state uchger_state; if (!uchger) @@ -480,6 +488,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger->gadget = ugadget; + ugadget->charger = uchger; uchger->old_gadget_state = ugadget->state; uchger->gadget_nb.notifier_call = usb_charger_plug_by_gadget; usb_gadget_register_notify(ugadget, >gadget_nb); @@ -503,7 +512,7 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - struct usb_charger *uchger = NULL; + struct usb_charger *uchger = ugadget->charger; if (!uchger) return -EINVAL; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 3/4] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/charger.c | 43 -- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 82a9973..76e1a6f 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -272,7 +272,11 @@ EXPORT_SYMBOL_GPL(usb_charger_unregister_notify); enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { - if (uchger->psy) { + if (uchger->gadget && uchger->gadget->ops + && uchger->gadget->ops->get_charger_type) { + uchger->type = + uchger->gadget->ops->get_charger_type(uchger->gadget); + } else if (uchger->psy) { union power_supply_propval val; power_supply_get_property(uchger->psy, @@ -479,6 +483,29 @@ usb_charger_plug_by_extcon(struct notifier_block *nb, int usb_charger_plug_by_gadget(struct usb_gadget *gadget, unsigned long state) { + struct usb_charger *uchger = gadget->charger; + enum usb_charger_state uchger_state; + + if (!uchger) + return -EINVAL; + + /* Report event to power to setting the current limitation +* for this usb charger when one usb charger state is changed +* with detecting by usb gadget state. +*/ + if (uchger->old_gadget_state != state) { + uchger->old_gadget_state = state; + + if (state >= USB_STATE_ATTACHED) + uchger_state = USB_CHARGER_PRESENT; + else if (state == USB_STATE_NOTATTACHED) + uchger_state = USB_CHARGER_REMOVE; + else + uchger_state = USB_CHARGER_DEFAULT; + + usb_charger_notify_others(uchger, uchger_state); + } + return 0; } EXPORT_SYMBOL_GPL(usb_charger_plug_by_gadget); @@ -635,6 +662,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger->gadget = ugadget; + ugadget->charger = uchger; uchger->old_gadget_state = ugadget->state; /* register a new usb charger */ @@ -655,7 +683,18 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - return 0; + struct usb_charger *uchger = ugadget->charger; + + if (!uchger) + return -EINVAL; + + if (uchger->extcon_dev) + extcon_unregister_notifier(uchger->extcon_dev, + EXTCON_USB, >extcon_nb.nb); + + ida_simple_remove(_charger_ida, uchger->id); + + return usb_charger_unregister(uchger); } static int __init usb_charger_sysfs_init(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 1/4] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. It also supplies the notification mechanism to userspace When the usb charger state is changed. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. This patch doesn't yet integrate with the gadget code, so some functions which rely on the 'gadget' are not completed, that will be implemented in the following patches. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 669 +++ include/linux/usb/usb_charger.h | 164 ++ 4 files changed, 841 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33834aa..8d69dca 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..82a9973 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,669 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define UCHGER_STATE_LENGTH(50) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = "usb-charger", + .dev_name = "usb-charger", +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t sdp_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return sprintf(buf, "%d\n", uchger->cur_limit.sdp_cur_limit); +} + +static ssize_t sdp_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + unsigned int sdp_limit; + int ret; + + ret = kstrtouint(buf, 10, _limit); + if (ret < 0) + return ret; + + ret = usb_charger_set_cur_limit_by_type(uchger, SDP_TYPE, sdp_limit); + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_RW(sdp_limit); + +static ssize_t dcp_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return sprintf(buf, "%d\n&qu
[PATCH v7 2/4] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. It will report to the usb charger when the gadget state is changed, then the usb charger can do the power things. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 11 +++ include/linux/usb/gadget.h| 11 +++ 2 files changed, 22 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..2727f01 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include /** * struct usb_udc - describes one usb device controller @@ -226,6 +227,9 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget->udc; + /* when the gadget state is changed, then report to USB charger */ + usb_charger_plug_by_gadget(gadget, gadget->state); + if (udc) sysfs_notify(>dev.kobj, NULL, "state"); } @@ -405,8 +409,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(>dev); err4: list_del(>list); mutex_unlock(_lock); @@ -481,6 +491,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(>dev.kobj, KOBJ_REMOVE); flush_work(>work); device_unregister(>dev); + usb_charger_exit(gadget); device_unregister(>dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3d583a1..52c19b1 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -24,6 +24,7 @@ #include #include #include +#include struct usb_ep; @@ -560,6 +561,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -632,6 +634,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + /* negotiate the power with the usb charger */ + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; @@ -836,10 +840,17 @@ static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) * reporting how much power the device may consume. For example, this * could affect how quickly batteries are recharged. * + * It will also notify the USB charger how much power the device may + * consume if there is a USB charger linking with the gadget. + * * Returns zero on success, else negative errno. */ static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { + if (gadget->charger) + usb_charger_set_cur_limit_by_type(gadget->charger, + usb_charger_detect_type(gadget->charger), mA); + if (!gadget->ops->vbus_draw) return -EOPNOTSUPP; return gadget->ops->vbus_draw(gadget, mA); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 4/4] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown <broo...@kernel.org> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> Acked-by: Lee Jones <lee.jo...@linaro.org> Acked-by: Charles Keepax <ckee...@opensource.wolfsonmicro.com> Acked-by: Peter Chen <peter.c...@freescale.com> Acked-by: Sebastian Reichel <s...@kernel.org> --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index 7082301..043f1f4 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %dmA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -607,8 +647,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata && wm831x_pdata->usb_gadget) { + power->usb_charger = + usb_charger_find_by_name(wm831x_pdata->usb_gadget); + if (IS_ERR(power->usb_charger)) { + ret = PTR_ERR(power->usb_charger); + dev_err(>dev, + "Failed to find USB gadget: %d\n", ret); + goto err_bat_irq; + } + + power->usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power->usb_charger, + >usb_notify); + if (ret != 0) { + dev_err(>dev, + "Failed to register notifier: %d\n", ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i >= 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_charger) { + usb_charger_unregister_notify(wm831x_power->usb_charger, + _power->usb_notify); + /* Free charger */ + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpi
[PATCH v7 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v5: - Remove the notifier chain things from the gadget and introduce one callback function to report to the usb charger when the gadget state is changed. - Flesh out the port type detection which combines the USB negotiation and PMICs detection. - Supply the notification mechanism to userspace when charger state is changed. - Integrate with the vbus staff in the gadget API. - Spilt up the functionality for userspace with one file per USB charger type. Baolin Wang (4): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 708 + drivers/usb/gadget/udc/udc-core.c | 11 + include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 11 + include/linux/usb/usb_charger.h | 164 + 8 files changed, 974 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 1/4] gadget: Introduce the usb charger framework
On 6 December 2015 at 00:27, Sebastian Reichel <s...@kernel.org> wrote: > Hi, > > On Mon, Nov 16, 2015 at 02:33:31PM +0800, Baolin Wang wrote: >> +static ssize_t cur_limit_show(struct device *dev, >> + struct device_attribute *attr, >> + char *buf) >> +{ >> + struct usb_charger *uchger = dev_to_uchger(dev); >> + >> + return scnprintf(buf, PAGE_SIZE, "%d %d %d %d\n", >> + uchger->cur_limit.sdp_cur_limit, >> + uchger->cur_limit.dcp_cur_limit, >> + uchger->cur_limit.cdp_cur_limit, >> + uchger->cur_limit.aca_cur_limit); >> +} >> + >> +static ssize_t cur_limit_store(struct device *dev, >> +struct device_attribute *attr, >> +const char *buf, size_t count) >> +{ >> + struct usb_charger *uchger = dev_to_uchger(dev); >> + struct usb_charger_cur_limit cur; >> + int ret; >> + >> + ret = sscanf(buf, "%d %d %d %d", >> + _cur_limit, _cur_limit, >> + _cur_limit, _cur_limit); >> + if (ret == 0) >> + return -EINVAL; >> + >> + ret = usb_charger_set_cur_limit(uchger, ); >> + if (ret < 0) >> + return ret; >> + >> + return count; >> +} >> +static DEVICE_ATTR_RW(cur_limit); > > I think this functionality should be provided with one file per > type. This makes it easier to parse the values from userspace > and makes it possible to extend the frameworks functionality > (e.g. when new types are added in a newer revision of the USB > standard). > That sounds reasonable and I'll change that. Thanks. > -- Sebastian -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v5: - Remove the notifier chain things from the gadget and introduce one callback function to report to the usb charger when the gadget state is changed. - Flesh out the port type detection which combines the USB negotiation and PMICs detection. - Supply the notification mechanism to userspace when charger state is changed. - Integrate with the vbus staff in the gadget API. - Spilt up the functionality for userspace with one file per USB charger type. - Rebase on "4.4-rc7". Baolin Wang (4): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c | 708 + drivers/usb/gadget/udc/udc-core.c | 11 + include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/gadget.h| 11 + include/linux/usb/usb_charger.h | 164 + 8 files changed, 974 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 2/4] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. It will report to the usb charger when the gadget state is changed, then the usb charger can do the power things. Introduce a callback 'get_charger_type' which will implemented by user for usb gadget operations to get the usb charger type. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 11 +++ include/linux/usb/gadget.h| 11 +++ 2 files changed, 22 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afb..2727f01 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include /** * struct usb_udc - describes one usb device controller @@ -226,6 +227,9 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget->udc; + /* when the gadget state is changed, then report to USB charger */ + usb_charger_plug_by_gadget(gadget, gadget->state); + if (udc) sysfs_notify(>dev.kobj, NULL, "state"); } @@ -405,8 +409,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, mutex_unlock(_lock); + ret = usb_charger_init(gadget); + if (ret) + goto err5; + return 0; +err5: + device_del(>dev); err4: list_del(>list); mutex_unlock(_lock); @@ -481,6 +491,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(>dev.kobj, KOBJ_REMOVE); flush_work(>work); device_unregister(>dev); + usb_charger_exit(gadget); device_unregister(>dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3d583a1..52c19b1 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -24,6 +24,7 @@ #include #include #include +#include struct usb_ep; @@ -560,6 +561,7 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); + enum usb_charger_type (*get_charger_type)(struct usb_gadget *); }; /** @@ -632,6 +634,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + /* negotiate the power with the usb charger */ + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; @@ -836,10 +840,17 @@ static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) * reporting how much power the device may consume. For example, this * could affect how quickly batteries are recharged. * + * It will also notify the USB charger how much power the device may + * consume if there is a USB charger linking with the gadget. + * * Returns zero on success, else negative errno. */ static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { + if (gadget->charger) + usb_charger_set_cur_limit_by_type(gadget->charger, + usb_charger_detect_type(gadget->charger), mA); + if (!gadget->ops->vbus_draw) return -EOPNOTSUPP; return gadget->ops->vbus_draw(gadget, mA); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 3/4] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger should get the type by the 'get_charger_type' callback which is implemented by the usb gadget operations, and get the usb charger pointer from struct 'usb_gadget'. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/charger.c | 43 -- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c index 82a9973..76e1a6f 100644 --- a/drivers/usb/gadget/charger.c +++ b/drivers/usb/gadget/charger.c @@ -272,7 +272,11 @@ EXPORT_SYMBOL_GPL(usb_charger_unregister_notify); enum usb_charger_type usb_charger_detect_type(struct usb_charger *uchger) { - if (uchger->psy) { + if (uchger->gadget && uchger->gadget->ops + && uchger->gadget->ops->get_charger_type) { + uchger->type = + uchger->gadget->ops->get_charger_type(uchger->gadget); + } else if (uchger->psy) { union power_supply_propval val; power_supply_get_property(uchger->psy, @@ -479,6 +483,29 @@ usb_charger_plug_by_extcon(struct notifier_block *nb, int usb_charger_plug_by_gadget(struct usb_gadget *gadget, unsigned long state) { + struct usb_charger *uchger = gadget->charger; + enum usb_charger_state uchger_state; + + if (!uchger) + return -EINVAL; + + /* Report event to power to setting the current limitation +* for this usb charger when one usb charger state is changed +* with detecting by usb gadget state. +*/ + if (uchger->old_gadget_state != state) { + uchger->old_gadget_state = state; + + if (state >= USB_STATE_ATTACHED) + uchger_state = USB_CHARGER_PRESENT; + else if (state == USB_STATE_NOTATTACHED) + uchger_state = USB_CHARGER_REMOVE; + else + uchger_state = USB_CHARGER_DEFAULT; + + usb_charger_notify_others(uchger, uchger_state); + } + return 0; } EXPORT_SYMBOL_GPL(usb_charger_plug_by_gadget); @@ -635,6 +662,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger->gadget = ugadget; + ugadget->charger = uchger; uchger->old_gadget_state = ugadget->state; /* register a new usb charger */ @@ -655,7 +683,18 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - return 0; + struct usb_charger *uchger = ugadget->charger; + + if (!uchger) + return -EINVAL; + + if (uchger->extcon_dev) + extcon_unregister_notifier(uchger->extcon_dev, + EXTCON_USB, >extcon_nb.nb); + + ida_simple_remove(_charger_ida, uchger->id); + + return usb_charger_unregister(uchger); } static int __init usb_charger_sysfs_init(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 1/4] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. It also supplies the notification mechanism to userspace When the usb charger state is changed. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. This patch doesn't yet integrate with the gadget code, so some functions which rely on the 'gadget' are not completed, that will be implemented in the following patches. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/Makefile |1 + drivers/usb/gadget/charger.c| 669 +++ include/linux/usb/usb_charger.h | 164 ++ 4 files changed, 841 insertions(+) create mode 100644 drivers/usb/gadget/charger.c create mode 100644 include/linux/usb/usb_charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33834aa..8d69dca 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,13 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 598a67d..1e421c1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -10,3 +10,4 @@ libcomposite-y:= usbstring.o config.o epautoconf.o libcomposite-y += composite.o functions.o configfs.o u_f.o obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ +obj-$(CONFIG_USB_CHARGER) += charger.o diff --git a/drivers/usb/gadget/charger.c b/drivers/usb/gadget/charger.c new file mode 100644 index 000..82a9973 --- /dev/null +++ b/drivers/usb/gadget/charger.c @@ -0,0 +1,669 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_CUR_PROTECT(50) +#define DEFAULT_SDP_CUR_LIMIT (500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_DCP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_CDP_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define DEFAULT_ACA_CUR_LIMIT (1500 - DEFAULT_CUR_PROTECT) +#define UCHGER_STATE_LENGTH(50) + +static DEFINE_IDA(usb_charger_ida); +static struct bus_type usb_charger_subsys = { + .name = "usb-charger", + .dev_name = "usb-charger", +}; + +static struct usb_charger *dev_to_uchger(struct device *udev) +{ + return container_of(udev, struct usb_charger, dev); +} + +static ssize_t sdp_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return sprintf(buf, "%d\n", uchger->cur_limit.sdp_cur_limit); +} + +static ssize_t sdp_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + unsigned int sdp_limit; + int ret; + + ret = kstrtouint(buf, 10, _limit); + if (ret < 0) + return ret; + + ret = usb_charger_set_cur_limit_by_type(uchger, SDP_TYPE, sdp_limit); + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_RW(sdp_limit); + +static ssize_t dcp_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return sprintf(buf, "%d\n&qu
[PATCH v7 4/4] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown <broo...@kernel.org> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> Acked-by: Lee Jones <lee.jo...@linaro.org> Acked-by: Charles Keepax <ckee...@opensource.wolfsonmicro.com> Acked-by: Peter Chen <peter.c...@freescale.com> Acked-by: Sebastian Reichel <s...@kernel.org> --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index 7082301..043f1f4 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %dmA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -607,8 +647,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata && wm831x_pdata->usb_gadget) { + power->usb_charger = + usb_charger_find_by_name(wm831x_pdata->usb_gadget); + if (IS_ERR(power->usb_charger)) { + ret = PTR_ERR(power->usb_charger); + dev_err(>dev, + "Failed to find USB gadget: %d\n", ret); + goto err_bat_irq; + } + + power->usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power->usb_charger, + >usb_notify); + if (ret != 0) { + dev_err(>dev, + "Failed to register notifier: %d\n", ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i >= 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_charger) { + usb_charger_unregister_notify(wm831x_power->usb_charger, + _power->usb_notify); + /* Free charger */ + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base; int gpi
Re: [PATCH v7 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
On 7 January 2016 at 19:25, Alex Shiwrote: > Hi, Baolin, > > There is similar gadget/charger driver on QC msm tree, > git://codeaurora.org/quic/la/kernel/msm-3.10 msm-3.10 > You may check that as a reference. > OK. Thanks. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
On 18 November 2015 at 17:32, Andy Shevchenko <andy.shevche...@gmail.com> wrote: > On Wed, Nov 18, 2015 at 4:15 AM, Baolin Wang <baolin.w...@linaro.org> wrote: >> On 17 November 2015 at 21:34, Andy Shevchenko <andy.shevche...@gmail.com> >> wrote: >>> On Mon, Nov 16, 2015 at 9:05 AM, Baolin Wang <baolin.w...@linaro.org> wrote: >>>> It dose not work when we want to use the usb-to-serial port based >>>> on one usb gadget as a console. Thus this patch adds the console >>>> initialization to support this request. >>> > >>>> +#define GS_BUFFER_SIZE (4096) >>> Redundant parens >> OK. I'll remove it. >> >>>> +#define GS_CONSOLE_BUF_SIZE(2 * GS_BUFFER_SIZE) >>>> + >>>> +struct gscons_info { >>>> + struct gs_port *port; >>>> + struct tty_driver *tty_driver; >>>> + struct work_struct work; >>>> + int buf_tail; >>>> + charbuf[GS_CONSOLE_BUF_SIZE]; >>> >>> Can't be malloced once? >> The 'gscons_info' structure is malloced once. > > In state of high fragmentation is quite hard to find big memory chunks. > I would split it to two allocations, though if maintainers are okay > with your code, then I'm also okay. > Make sense. But I think the major memory of the 'struct gscons_info' is for the 'buf' member, so I still think no need to allocate it 2 times. >>>> +static struct usb_request *gs_request_new(struct usb_ep *ep, int >>>> buffer_size) >>>> +{ >>>> + struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC); >>>> + >>>> + if (!req) >>> >>> For sake of readability it's better to have assignment explicitly before >>> 'if'. >> >> But I think it is very easy to understand the assignment here with >> saving code lines. > > It's not a function of couple of lines, so, for me makes sense to > explicitly put the assignment here. Especially that one that does > allocations (for pointer arithmetic I could agree to place the > assignment in the definition block). > OK. Sounds reasonable. >>>> +static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) >>>> +{ >>>> + if (req->status != 0 && req->status != -ECONNRESET) >>>> + return; >>> >>> Something missed here. Currently it's no-op. >>> >> >> Yeah. I didn't realize what need to do in the callback here, so just >> leave a callback without anything. But maybe something will be added >> if there are some requirements in future. > > if () > .. > > will be optimized away, why not to remove it? OK. I'll remove it. > >>>> + port = ports[port_num].port; >>>> + if (!port) { >>>> + pr_err("%s: serial line [%d] not allocated.\n", >>>> + __func__, port_num); >>>> + return -ENODEV; >>>> + } >>>> + >>>> + if (!port->port_usb) { >>>> + pr_err("%s: no port usb.\n", __func__); >>> >>> Starting from here could it be dev_err and so on? >> >> There are no dev_err things and device things in this file, so pr_xxx >> is more reasonable. > > This is understandable, but if in case you have device in place why > not to use its name? Yes, that's right. > >>>> + pr_debug("%s: port[%d] console connect!\n", __func__, port_num); >>> >>> Dynamic debug will add function name if asked. >> >> Sorry, I didn't get your point, you mean print the function name is >> redundant here? > > Right. > > Just pr_debug("port[%d] …", …); > OK. Very thanks for your suggestions. > -- > With Best Regards, > Andy Shevchenko -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
On 18 November 2015 at 20:05, David Laight <david.lai...@aculab.com> wrote: > From: Baolin Wang >> Sent: 18 November 2015 10:45 >> On 18 November 2015 at 17:32, Andy Shevchenko <andy.shevche...@gmail.com> >> wrote: >> > On Wed, Nov 18, 2015 at 4:15 AM, Baolin Wang <baolin.w...@linaro.org> >> > wrote: >> >> On 17 November 2015 at 21:34, Andy Shevchenko <andy.shevche...@gmail.com> >> >> wrote: >> >>> On Mon, Nov 16, 2015 at 9:05 AM, Baolin Wang <baolin.w...@linaro.org> >> >>> wrote: >> >>>> It dose not work when we want to use the usb-to-serial port based >> >>>> on one usb gadget as a console. Thus this patch adds the console >> >>>> initialization to support this request. >> >>> >> > >> >>>> +#define GS_BUFFER_SIZE (4096) >> >>> Redundant parens >> >> OK. I'll remove it. >> >> >> >>>> +#define GS_CONSOLE_BUF_SIZE(2 * GS_BUFFER_SIZE) >> >>>> + >> >>>> +struct gscons_info { >> >>>> + struct gs_port *port; >> >>>> + struct tty_driver *tty_driver; >> >>>> + struct work_struct work; >> >>>> + int buf_tail; >> >>>> + charbuf[GS_CONSOLE_BUF_SIZE]; >> >>> >> >>> Can't be malloced once? >> >> The 'gscons_info' structure is malloced once. >> > >> > In state of high fragmentation is quite hard to find big memory chunks. >> > I would split it to two allocations, though if maintainers are okay >> > with your code, then I'm also okay. >> > >> >> Make sense. But I think the major memory of the 'struct gscons_info' >> is for the 'buf' member, so I still think no need to allocate it 2 >> times. > > It may be worth just reducing GS_BUFFER_SIZE slightly so that the gscons_info > structure itself is less than 8k. > If you can't get 2 adjacent pages then a lot of things will fail. > But its allocation is called in early booting time, I think there are not many memory fragments now. > David > -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
On 18 November 2015 at 23:32, Peter Hurley <pe...@hurleysoftware.com> wrote: > Hi Baolin, > > On 11/16/2015 02:05 AM, Baolin Wang wrote: >> It dose not work when we want to use the usb-to-serial port based >> on one usb gadget as a console. Thus this patch adds the console >> initialization to support this request. > > I have some high level concerns. > > 1. I would defer registering the console until the port has at least been >allocated in gserial_alloc_line(), and unregister when the line is freed. >That also reduces many of the conditions that you shouldn't need to >check, like port number range and so on. The 'setup' callback of 'struct console' is just do some memory allocation and member initialization, that no need to defer registering the console in gserial_alloc_line(). But the 'gs_console_connect()' which will use the port need to be called in gserial_connect(). > >Further, consider deferring the console registration until > gserial_connect(); >that would further simplify things. In this case, unregistration would >happen at disconnect. That sounds reasonable. I would try. > > 2. Why are you using a kworker for actual device i/o when all of the i/o >is done with interrupts disabled anyway? >Getting rid of the work would eliminate using the 8K intermediate buffer >as well. If remove the kworker, there are some deadlocks to call the printk() when in the process of transferring data with usb endpoint. So we need a async kworker to complete the io or it can not work. > > 3. If for some reason i/o deferral is really necessary, consider using a > kthread >kworker instead of the pooled kworker. The scheduler response will be _way_ >better. > OK, make sense. > 4. If for some reason i/o deferral is really necessary, use a circular buffer >for the intermediate buffer, preferably lockless since there is only >one producer and one consumer. > Yeah, the circular buffer is better but more tricky. I would try. > Some other review comments below; please ignore anything other reviewers > have already noted. > > Regards, > Peter Hurley > >> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> >> --- >> drivers/usb/gadget/Kconfig |6 + >> drivers/usb/gadget/function/u_serial.c | 238 >> >> 2 files changed, 244 insertions(+) >> >> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig >> index 33834aa..be5aab9 100644 >> --- a/drivers/usb/gadget/Kconfig >> +++ b/drivers/usb/gadget/Kconfig >> @@ -127,6 +127,12 @@ config USB_GADGET_STORAGE_NUM_BUFFERS >> a module parameter as well. >> If unsure, say 2. >> >> +config U_SERIAL_CONSOLE >> + bool "Serial gadget console support" >> + depends on USB_G_SERIAL >> + help >> +It supports the serial gadget can be used as a console. >> + >> source "drivers/usb/gadget/udc/Kconfig" >> >> # >> diff --git a/drivers/usb/gadget/function/u_serial.c >> b/drivers/usb/gadget/function/u_serial.c >> index f7771d8..4ade527 100644 >> --- a/drivers/usb/gadget/function/u_serial.c >> +++ b/drivers/usb/gadget/function/u_serial.c >> @@ -27,6 +27,7 @@ >> #include >> #include >> #include >> +#include >> >> #include "u_serial.h" >> >> @@ -79,6 +80,16 @@ >> */ >> #define QUEUE_SIZE 16 >> #define WRITE_BUF_SIZE 8192/* TX only */ >> +#define GS_BUFFER_SIZE (4096) >> +#define GS_CONSOLE_BUF_SIZE (2 * GS_BUFFER_SIZE) >> + >> +struct gscons_info { >> + struct gs_port *port; >> + struct tty_driver *tty_driver; >> + struct work_struct work; >> + int buf_tail; >> + charbuf[GS_CONSOLE_BUF_SIZE]; >> +}; > > Make struct gscons_info a static declaration instead of > allocating it. But I think the dynamic allocation is more reasonable with reducing some global variables. > >> >> /* circular buffer */ >> struct gs_buf { >> @@ -118,6 +129,7 @@ struct gs_port { >> >> /* REVISIT this state ... */ >> struct usb_cdc_line_coding port_line_coding;/* 8-N-1 etc */ >> + struct usb_request *console_req; >> }; >> >> static struct portmaster { >> @@ -1054,6 +1066,7 @@ gs_port_alloc(unsigned port_num, struct >> usb_cdc_line_coding *coding) >> >> port->port_num = port_num; >> port->port_line_codi
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
> >> +{ >> + struct gscons_info *info = gserial_cons.data; >> + int port_num = gserial_cons.index; >> + struct usb_request *req; >> + struct gs_port *port; >> + struct usb_ep *ep; >> + >> + if (port_num >= MAX_U_SERIAL_PORTS || port_num < 0) { >> + pr_err("%s: port num [%d] exceeds the range.\n", >> +__func__, port_num); >> + return -ENXIO; >> + } >> + >> + port = ports[port_num].port; >> + if (!port) { >> + pr_err("%s: serial line [%d] not allocated.\n", >> +__func__, port_num); >> + return -ENODEV; >> + } >> + >> + if (!port->port_usb) { >> + pr_err("%s: no port usb.\n", __func__); >> + return -ENODEV; >> + } >> + >> + ep = port->port_usb->in; >> + if (!ep) { >> + pr_err("%s: no usb endpoint.\n", __func__); >> + return -ENXIO; >> + } > > Looking at the caller, gserial_connect(), none of the error > conditions above look possible. > I re-look the code and do some tests, I found the checking is necessary. Cause we get the port number from the console->index, if the cmdline is not set the ttyGS0 as the console, the console->index will be -1 that is a wrong value. Also the serial.c file will create 1 usb-to-seial port as default (default n_ports = 1), so we need to check the port and the endpoint of the port. So I think here checking is necessary and I have tested it. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
On 19 November 2015 at 17:36, Peter Hurley <pe...@hurleysoftware.com> wrote: > On 11/19/2015 01:48 AM, Baolin Wang wrote: >>> >>>> +{ >>>> + struct gscons_info *info = gserial_cons.data; >>>> + int port_num = gserial_cons.index; >>>> + struct usb_request *req; >>>> + struct gs_port *port; >>>> + struct usb_ep *ep; >>>> + >>>> + if (port_num >= MAX_U_SERIAL_PORTS || port_num < 0) { >>>> + pr_err("%s: port num [%d] exceeds the range.\n", >>>> +__func__, port_num); >>>> + return -ENXIO; >>>> + } >>>> + >>>> + port = ports[port_num].port; >>>> + if (!port) { >>>> + pr_err("%s: serial line [%d] not allocated.\n", >>>> +__func__, port_num); >>>> + return -ENODEV; >>>> + } >>>> + >>>> + if (!port->port_usb) { >>>> + pr_err("%s: no port usb.\n", __func__); >>>> + return -ENODEV; >>>> + } >>>> + >>>> + ep = port->port_usb->in; >>>> + if (!ep) { >>>> + pr_err("%s: no usb endpoint.\n", __func__); >>>> + return -ENXIO; >>>> + } >>> >>> Looking at the caller, gserial_connect(), none of the error >>> conditions above look possible. >>> >> >> I re-look the code and do some tests, I found the checking is >> necessary. Cause we get the port number from the console->index, if >> the cmdline is not set the ttyGS0 as the console, the console->index >> will be -1 that is a wrong value. Also the serial.c file will create 1 >> usb-to-seial port as default (default n_ports = 1), so we need to >> check the port and the endpoint of the port. So I think here checking >> is necessary and I have tested it. > > static void gs_console_connect(int port_num) > { > . > . > if (port_num != gserial_cons.index) > return; > . OK. Thanks. > . > > > @@ -1219,6 +1453,7 @@ int gserial_connect(struct gserial *gser, u8 port_num) > gser->disconnect(gser); > } > > + status = gs_console_connect(port_num); > spin_unlock_irqrestore(>port_lock, flags); > > return status; > > > > > > > -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: gadget: Add the console support for usb-to-serial port
On 19 November 2015 at 18:28, Peter Hurley <pe...@hurleysoftware.com> wrote: > On 11/18/2015 09:35 PM, Baolin Wang wrote: >> On 18 November 2015 at 23:32, Peter Hurley <pe...@hurleysoftware.com> wrote: >>> Hi Baolin, >>> >>> On 11/16/2015 02:05 AM, Baolin Wang wrote: >>>> It dose not work when we want to use the usb-to-serial port based >>>> on one usb gadget as a console. Thus this patch adds the console >>>> initialization to support this request. >>> >>> I have some high level concerns. >>> >>> 1. I would defer registering the console until the port has at least been >>>allocated in gserial_alloc_line(), and unregister when the line is freed. >>>That also reduces many of the conditions that you shouldn't need to >>>check, like port number range and so on. >> >> The 'setup' callback of 'struct console' is just do some memory >> allocation and member initialization, that no need to defer >> registering the console in gserial_alloc_line(). But the >> 'gs_console_connect()' which will use the port need to be called in >> gserial_connect(). > > My point here was why are you registering the console before the port > table is even allocated and initialized? The console can't possibly > perform i/o that early because the port doesn't even exist. > Which is why I suggested waiting until gserial_alloc_line() to > register the console. > > A typical console setup() performs the cross-reference linking between > the console data structure and the port table. The reason for that > is the console needs to be cleaned up if the port is being torn down. > > For example, in gserial_disconnect() the port->port_usb is reset to NULL, > and later in gserial_console_exit(): > > if (port && port->port_usb) { > > gs_request_free(req, ep); > } > > which means your leaking the request allocation when the port has been > disconnected. > Yeah, that's right. I'll defer the console registration until gserial_connect() and unregistration in disconnect. > >>>Further, consider deferring the console registration until >>> gserial_connect(); >>>that would further simplify things. In this case, unregistration would >>>happen at disconnect. >> >> That sounds reasonable. I would try. >> >>> >>> 2. Why are you using a kworker for actual device i/o when all of the i/o >>>is done with interrupts disabled anyway? >>>Getting rid of the work would eliminate using the 8K intermediate buffer >>>as well. >> >> If remove the kworker, there are some deadlocks to call the printk() >> when in the process of transferring data with usb endpoint. So we need >> a async kworker to complete the io or it can not work. > > The commit log should detail the major design choices, including why you > used the kworker (because of re-entrancy issues with usb endpoint). > OK. > > >>> 3. If for some reason i/o deferral is really necessary, consider using a >>> kthread >>>kworker instead of the pooled kworker. The scheduler response will be >>> _way_ >>>better. >>> >> >> OK, make sense. >> >>> 4. If for some reason i/o deferral is really necessary, use a circular >>> buffer >>>for the intermediate buffer, preferably lockless since there is only >>>one producer and one consumer. >>> >> >> Yeah, the circular buffer is better but more tricky. I would try. >> >>> Some other review comments below; please ignore anything other reviewers >>> have already noted. >>> >>> Regards, >>> Peter Hurley >>> >>>> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> >>>> --- >>>> drivers/usb/gadget/Kconfig |6 + >>>> drivers/usb/gadget/function/u_serial.c | 238 >>>> >>>> 2 files changed, 244 insertions(+) >>>> >>>> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig >>>> index 33834aa..be5aab9 100644 >>>> --- a/drivers/usb/gadget/Kconfig >>>> +++ b/drivers/usb/gadget/Kconfig >>>> @@ -127,6 +127,12 @@ config USB_GADGET_STORAGE_NUM_BUFFERS >>>> a module parameter as well. >>>> If unsure, say 2. >>>> >>>> +config U_SERIAL_CONSOLE >>>> + bool "Serial gadget console support" >&
[PATCH v2] usb: gadget: Add the console support for usb-to-serial port
It dose not work when we want to use the usb-to-serial port based on one usb gadget as a console. Thus this patch adds the console initialization to support this request. To avoid the re-entrance when transferring data with usb endpoint, it introduces a kthread to do the IO transmission. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |6 + drivers/usb/gadget/function/u_serial.c | 258 2 files changed, 264 insertions(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33834aa..be5aab9 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -127,6 +127,12 @@ config USB_GADGET_STORAGE_NUM_BUFFERS a module parameter as well. If unsure, say 2. +config U_SERIAL_CONSOLE + bool "Serial gadget console support" + depends on USB_G_SERIAL + help + It supports the serial gadget can be used as a console. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index f7771d8..6af145f 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "u_serial.h" @@ -79,6 +81,7 @@ */ #define QUEUE_SIZE 16 #define WRITE_BUF_SIZE 8192/* TX only */ +#define GS_CONSOLE_BUF_SIZE8192 /* circular buffer */ struct gs_buf { @@ -88,6 +91,17 @@ struct gs_buf { char*buf_put; }; +/* console info */ +struct gscons_info { + struct gs_port *port; + struct task_struct *console_thread; + struct gs_buf con_buf; + /* protect the buf and busy flag */ + spinlock_t con_lock; + int req_busy; + struct usb_request *console_req; +}; + /* * The port structure holds info for each port, one for each minor number * (and thus for each /dev/ node). @@ -1023,6 +1037,246 @@ static const struct tty_operations gs_tty_ops = { static struct tty_driver *gs_tty_driver; +#ifdef CONFIG_U_SERIAL_CONSOLE + +static struct gscons_info gscons_info; +static struct console gserial_cons; + +static struct usb_request *gs_request_new(struct usb_ep *ep) +{ + struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (!req) + return NULL; + + req->buf = kmalloc(ep->maxpacket, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + + return req; +} + +static void gs_request_free(struct usb_request *req, struct usb_ep *ep) +{ + if (!req) + return; + + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) +{ + struct gscons_info *info = _info; + + switch (req->status) { + default: + pr_warn("%s: unexpected %s status %d\n", + __func__, ep->name, req->status); + case 0: + /* normal completion */ + spin_lock(>con_lock); + info->req_busy = 0; + spin_unlock(>con_lock); + + wake_up_process(info->console_thread); + break; + case -ESHUTDOWN: + /* disconnect */ + pr_vdebug("%s: %s shutdown\n", __func__, ep->name); + break; + } +} + +static int gs_console_connect(int port_num) +{ + struct gscons_info *info = _info; + struct gs_port *port; + struct usb_ep *ep; + + if (port_num != gserial_cons.index) { + pr_err("%s: port num [%d] is not support console\n", + __func__, port_num); + return -ENXIO; + } + + port = ports[port_num].port; + ep = port->port_usb->in; + if (!info->console_req) { + info->console_req = gs_request_new(ep); + if (!info->console_req) + return -ENOMEM; + info->console_req->complete = gs_complete_out; + } + + info->port = port; + spin_lock(>con_lock); + info->req_busy = 0; + spin_unlock(>con_lock); + pr_vdebug("port[%d] console connect!\n", port_num); + return 0; +} + +static void gs_console_disconnect(struct usb_ep *ep) +{ + struct gscons_info *info = _info; + struct usb_request *req = info->console_req; + + gs_request_free(req, ep); + info->console_req = NULL; +} + +static int gs_console_thread(void *data) +{ + struct gscons_info *info = _info; + struct gs_port *port; + struct usb_request *
Re: [PATCH v2] usb: dwc3: host: Set the dma_ops for xhci device
On 6 June 2016 at 22:59, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >> On ARM64 platform, it will set 'dummy_dma_ops' for device dma_ops if >> it did not call 'arch_setup_dma_ops' at device creation time, that will >> cause failure when setting the dma mask for device. >> >> Thus this patch set the xhci device dma_ops from the parent device if >> the xhci device dma_ops is 'dummy_dma_ops'. >> >> Changes since v1: >> - Add CONFIG_ARM64 macro. >> >> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> >> --- >> drivers/usb/dwc3/host.c |5 + >> 1 file changed, 5 insertions(+) >> >> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c >> index c679f63..edb666d 100644 >> --- a/drivers/usb/dwc3/host.c >> +++ b/drivers/usb/dwc3/host.c >> @@ -32,6 +32,11 @@ int dwc3_host_init(struct dwc3 *dwc) >> return -ENOMEM; >> } >> >> +#ifdef CONFIG_ARM64 >> + if (get_dma_ops(>dev) == get_dma_ops(NULL)) >> + xhci->dev.archdata.dma_ops = get_dma_ops(dwc->dev); >> +#endif > > I don't like the ifdef and also don't like that this is done in dwc3 > itself. Seems like we need something like this done from the > platform_bus core. OK. I will try to fix this issue in platform_bus core. Thanks. > > -- > balbi -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] usb: dwc3: host: Set the dma_ops for xhci device
Hi, On 6 June 2016 at 22:59, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >> On ARM64 platform, it will set 'dummy_dma_ops' for device dma_ops if >> it did not call 'arch_setup_dma_ops' at device creation time, that will >> cause failure when setting the dma mask for device. >> >> Thus this patch set the xhci device dma_ops from the parent device if >> the xhci device dma_ops is 'dummy_dma_ops'. >> >> Changes since v1: >> - Add CONFIG_ARM64 macro. >> >> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> >> --- >> drivers/usb/dwc3/host.c |5 + >> 1 file changed, 5 insertions(+) >> >> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c >> index c679f63..edb666d 100644 >> --- a/drivers/usb/dwc3/host.c >> +++ b/drivers/usb/dwc3/host.c >> @@ -32,6 +32,11 @@ int dwc3_host_init(struct dwc3 *dwc) >> return -ENOMEM; >> } >> >> +#ifdef CONFIG_ARM64 >> + if (get_dma_ops(>dev) == get_dma_ops(NULL)) >> + xhci->dev.archdata.dma_ops = get_dma_ops(dwc->dev); >> +#endif > > I don't like the ifdef and also don't like that this is done in dwc3 > itself. Seems like we need something like this done from the > platform_bus core. I've sent one patch to fix this issue in platform_bus core, and Robin explained "DMA-capable devices are real hardware, therefore don't spring out of thin air without being described in DT or ACPI." But the problem is here, how can we handle this issue to make the host work well? What about below modification? Thanks. diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index c679f63..f7c58f9 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -17,6 +17,7 @@ #include #include +#include #include "core.h" @@ -37,6 +38,7 @@ int dwc3_host_init(struct dwc3 *dwc) xhci->dev.parent= dwc->dev; xhci->dev.dma_mask = dwc->dev->dma_mask; xhci->dev.dma_parms = dwc->dev->dma_parms; + of_dma_configure(>dev, dwc->dev->of_node); dwc->xhci = xhci; -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] usb: dwc3: host: Set the dma_ops for xhci device
It will be failed when xhci device set the dma mask, if the xhci device dma_ops is dummy. Thus set the xhci device dma_ops from the parent device. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/dwc3/host.c |3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index c679f63..7ce55c9 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -32,6 +32,9 @@ int dwc3_host_init(struct dwc3 *dwc) return -ENOMEM; } + if (get_dma_ops(>dev) == get_dma_ops(NULL)) + xhci->dev.archdata.dma_ops = get_dma_ops(dwc->dev); + dma_set_coherent_mask(>dev, dwc->dev->coherent_dma_mask); xhci->dev.parent= dwc->dev; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RESEND PATCH v11 4/4] power: wm831x_power: Support USB charger current limit management
Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown <broo...@kernel.org> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> Acked-by: Lee Jones <lee.jo...@linaro.org> Acked-by: Charles Keepax <ckee...@opensource.wolfsonmicro.com> Acked-by: Peter Chen <peter.c...@freescale.com> Acked-by: Sebastian Reichel <s...@kernel.org> --- drivers/power/wm831x_power.c | 69 ++ include/linux/mfd/wm831x/pdata.h |3 ++ 2 files changed, 72 insertions(+) diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index 7082301..cef1812 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_charger *usb_charger; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static const unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, +struct wm831x_power, +usb_notify); + unsigned int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %umA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /* * Battery properties */ @@ -607,8 +647,31 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + if (wm831x_pdata && wm831x_pdata->usb_gadget) { + power->usb_charger = + usb_charger_find_by_name(wm831x_pdata->usb_gadget); + if (IS_ERR(power->usb_charger)) { + ret = PTR_ERR(power->usb_charger); + dev_err(>dev, + "Failed to find USB gadget: %d\n", ret); + goto err_bat_irq; + } + + power->usb_notify.notifier_call = wm831x_usb_limit_change; + + ret = usb_charger_register_notify(power->usb_charger, + >usb_notify); + if (ret != 0) { + dev_err(>dev, + "Failed to register notifier: %d\n", ret); + goto err_usb_charger; + } + } + return ret; +err_usb_charger: + /* put_device on charger */ err_bat_irq: --i; for (; i >= 0; i--) { @@ -637,6 +700,12 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_charger) { + usb_charger_unregister_notify(wm831x_power->usb_charger, + _power->usb_notify); + /* Free charger */ + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index dcc9631..5af8399 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -126,6 +126,9 @@ struct wm831x_pdata { /** The driver should initiate a power off sequence during shutdown */ bool soft_shutdown; + /** dev_name of USB charger gadget to integrate with */ + const char *usb_gadget; + int irq_base
[RESEND PATCH v11 1/4] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. It also supplies the notification mechanism to userspace When the usb charger state is changed. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. This patch doesn't yet integrate with the gadget code, so some functions which rely on the 'gadget' are not completed, that will be implemented in the following patches. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/udc/Makefile |1 + drivers/usb/gadget/udc/charger.c | 770 ++ include/linux/usb/charger.h | 191 ++ include/uapi/linux/usb/charger.h | 31 ++ 5 files changed, 1000 insertions(+) create mode 100644 drivers/usb/gadget/udc/charger.c create mode 100644 include/linux/usb/charger.h create mode 100644 include/uapi/linux/usb/charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2057add..89f4e9b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -134,6 +134,13 @@ config U_SERIAL_CONSOLE help It supports the serial gadget can be used as a console. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index dfee534..0e9564c 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -2,6 +2,7 @@ # USB peripheral controller drivers # obj-$(CONFIG_USB_GADGET) += udc-core.o +obj-$(CONFIG_USB_CHARGER) += charger.o obj-$(CONFIG_USB_DUMMY_HCD)+= dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o diff --git a/drivers/usb/gadget/udc/charger.c b/drivers/usb/gadget/udc/charger.c new file mode 100644 index 000..7be4c76 --- /dev/null +++ b/drivers/usb/gadget/udc/charger.c @@ -0,0 +1,770 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SDP_CUR_LIMIT 500 +#define DEFAULT_SDP_CUR_LIMIT_SS 900 +#define DEFAULT_DCP_CUR_LIMIT 1500 +#define DEFAULT_CDP_CUR_LIMIT 1500 +#define DEFAULT_ACA_CUR_LIMIT 1500 + +static DEFINE_IDA(usb_charger_ida); +struct class *usb_charger_class; +static unsigned int usb_charger_get_cur_limit(struct usb_charger *uchger); + +static struct usb_charger *dev_to_uchger(struct device *dev) +{ + return container_of(dev, struct usb_charger, dev); +} + +/* + * charger_current_show() - Show the charger current limit. + */ +static ssize_t charger_current_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return sprintf(buf, "%u\n", usb_charger_get_cur_limit(uchger)); +} +static DEVICE_ATTR_RO(charger_current); + +/* + * charger_type_show() - Show the charger type. + * + * It can be SDP/DCP/CDP/ACA type, else for unknown type. + */ +static ssize_t charger_type_show(struct device *dev, +struct device_attribute *attr, +char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + int cnt; + + switch (uchger->type) { + case SDP_TYPE: + cnt = sprintf(buf, "%s\n", "SDP"); + break; + case DCP_TYPE: + cnt = sprintf(buf, "%s\n", "DCP"); + break; + case CDP_TYPE: + cnt = sprintf(buf, "%s\n", "CDP"); + break; + case
[RESEND PATCH v11 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v10: - Introduce usb_charger_get_state() function to check charger state. - Remove the mutex lock in usb_charger_set_cur_limit_by_type() function in case will be issued in atomic context. Baolin Wang (4): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/udc/Makefile |1 + drivers/usb/gadget/udc/charger.c | 807 + drivers/usb/gadget/udc/udc-core.c | 11 + include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/charger.h | 191 + include/linux/usb/gadget.h| 11 + include/uapi/linux/usb/charger.h | 31 ++ 9 files changed, 1131 insertions(+) create mode 100644 drivers/usb/gadget/udc/charger.c create mode 100644 include/linux/usb/charger.h create mode 100644 include/uapi/linux/usb/charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RESEND PATCH v11 2/4] gadget: Support for the usb charger framework
For supporting the usb charger, it adds the usb_charger_init() and usb_charger_exit() functions for usb charger initialization and exit. It will report to the usb charger when the gadget state is changed, then the usb charger can do the power things. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/udc-core.c | 11 +++ include/linux/usb/gadget.h| 11 +++ 2 files changed, 22 insertions(+) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 6e8300d..84c098c 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include /** * struct usb_udc - describes one usb device controller @@ -242,6 +243,9 @@ static void usb_gadget_state_work(struct work_struct *work) struct usb_gadget *gadget = work_to_gadget(work); struct usb_udc *udc = gadget->udc; + /* when the gadget state is changed, then report to USB charger */ + usb_charger_plug_by_gadget(gadget, gadget->state); + if (udc) sysfs_notify(>dev.kobj, NULL, "state"); } @@ -411,6 +415,10 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, if (ret) goto err4; + ret = usb_charger_init(gadget); + if (ret) + goto err5; + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); udc->vbus = true; @@ -431,6 +439,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, return 0; +err5: + device_del(>dev); err4: list_del(>list); mutex_unlock(_lock); @@ -539,6 +549,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) kobject_uevent(>dev.kobj, KOBJ_REMOVE); flush_work(>work); device_unregister(>dev); + usb_charger_exit(gadget); device_unregister(>dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 457651b..40390ec 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -24,6 +24,7 @@ #include #include #include +#include struct usb_ep; @@ -639,6 +640,8 @@ struct usb_gadget { unsignedout_epnum; unsignedin_epnum; struct usb_otg_caps *otg_caps; + /* negotiate the power with the usb charger */ + struct usb_charger *charger; unsignedsg_supported:1; unsignedis_otg:1; @@ -855,10 +858,18 @@ static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) * reporting how much power the device may consume. For example, this * could affect how quickly batteries are recharged. * + * It will also notify the USB charger how much power the device may + * consume if there is a USB charger linking with the gadget. + * * Returns zero on success, else negative errno. */ static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { + if (gadget->charger) + usb_charger_set_cur_limit_by_type(gadget->charger, + gadget->charger->type, + mA); + if (!gadget->ops->vbus_draw) return -EOPNOTSUPP; return gadget->ops->vbus_draw(gadget, mA); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RESEND PATCH v11 3/4] gadget: Integrate with the usb gadget supporting for usb charger
When the usb gadget supporting for usb charger is ready, the usb charger can implement the usb_charger_plug_by_gadget() function and usb_charger_exit() function by getting 'struct usb_charger' from 'struct gadget'. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/udc/charger.c | 39 +- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/charger.c b/drivers/usb/gadget/udc/charger.c index 7be4c76..949396f 100644 --- a/drivers/usb/gadget/udc/charger.c +++ b/drivers/usb/gadget/udc/charger.c @@ -568,6 +568,30 @@ usb_charger_plug_by_extcon(struct notifier_block *nb, int usb_charger_plug_by_gadget(struct usb_gadget *gadget, unsigned long state) { + struct usb_charger *uchger = gadget->charger; + enum usb_charger_state uchger_state; + + if (WARN(!uchger, "charger can not be NULL")) + return -EINVAL; + + /* +* Report event to power to setting the current limitation +* for this usb charger when one usb charger state is changed +* with detecting by usb gadget state. +*/ + if (uchger->old_gadget_state != state) { + uchger->old_gadget_state = state; + + if (state >= USB_STATE_ATTACHED) + uchger_state = USB_CHARGER_PRESENT; + else if (state == USB_STATE_NOTATTACHED) + uchger_state = USB_CHARGER_REMOVE; + else + uchger_state = USB_CHARGER_DEFAULT; + + usb_charger_notify_others(uchger, uchger_state); + } + return 0; } EXPORT_SYMBOL_GPL(usb_charger_plug_by_gadget); @@ -724,6 +748,7 @@ int usb_charger_init(struct usb_gadget *ugadget) /* register a notifier on a usb gadget device */ uchger->gadget = ugadget; + ugadget->charger = uchger; uchger->old_gadget_state = USB_STATE_NOTATTACHED; /* register a new usb charger */ @@ -744,7 +769,19 @@ fail: int usb_charger_exit(struct usb_gadget *ugadget) { - return 0; + struct usb_charger *uchger = ugadget->charger; + + if (WARN(!uchger, "charger can not be NULL")) + return -EINVAL; + + if (uchger->extcon_dev) + extcon_unregister_notifier(uchger->extcon_dev, + EXTCON_USB, + >extcon_nb.nb); + + ida_simple_remove(_charger_ida, uchger->id); + + return usb_charger_unregister(uchger); } static int __init usb_charger_class_init(void) -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RESEND PATCH v11 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
From: Baolin Wang <baolin.w...@spreadtrum.com> Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v10: - Introduce usb_charger_get_state() function to check charger state. - Remove the mutex lock in usb_charger_set_cur_limit_by_type() function in case will be issued in atomic context. Baolin Wang (4): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/udc/Makefile |1 + drivers/usb/gadget/udc/charger.c | 807 + drivers/usb/gadget/udc/udc-core.c | 11 + include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/charger.h | 191 + include/linux/usb/gadget.h| 11 + include/uapi/linux/usb/charger.h | 31 ++ 9 files changed, 1131 insertions(+) create mode 100644 drivers/usb/gadget/udc/charger.c create mode 100644 include/linux/usb/charger.h create mode 100644 include/uapi/linux/usb/charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RESEND PATCH v11 1/4] gadget: Introduce the usb charger framework
This patch introduces the usb charger driver based on usb gadget that makes an enhancement to a power driver. It works well in practice but that requires a system with suitable hardware. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the usb gadget state change or the extcon device state change, the usb charger will report to power user to set the current limitation. The usb charger will register notifiees on the usb gadget or the extcon device to get notified the usb charger state. It also supplies the notification mechanism to userspace When the usb charger state is changed. Power user will register a notifiee on the usb charger to get notified by status changes from the usb charger. It will report to power user to set the current limitation when detecting the usb charger is added or removed from extcon device state or usb gadget state. This patch doesn't yet integrate with the gadget code, so some functions which rely on the 'gadget' are not completed, that will be implemented in the following patches. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/gadget/Kconfig |7 + drivers/usb/gadget/udc/Makefile |1 + drivers/usb/gadget/udc/charger.c | 770 ++ include/linux/usb/charger.h | 191 ++ include/uapi/linux/usb/charger.h | 31 ++ 5 files changed, 1000 insertions(+) create mode 100644 drivers/usb/gadget/udc/charger.c create mode 100644 include/linux/usb/charger.h create mode 100644 include/uapi/linux/usb/charger.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2057add..89f4e9b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -134,6 +134,13 @@ config U_SERIAL_CONSOLE help It supports the serial gadget can be used as a console. +config USB_CHARGER + bool "USB charger support" + help + The usb charger driver based on the usb gadget that makes an + enhancement to a power driver which can set the current limitation + when the usb charger is added or removed. + source "drivers/usb/gadget/udc/Kconfig" # diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index dfee534..0e9564c 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -2,6 +2,7 @@ # USB peripheral controller drivers # obj-$(CONFIG_USB_GADGET) += udc-core.o +obj-$(CONFIG_USB_CHARGER) += charger.o obj-$(CONFIG_USB_DUMMY_HCD)+= dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o diff --git a/drivers/usb/gadget/udc/charger.c b/drivers/usb/gadget/udc/charger.c new file mode 100644 index 000..7be4c76 --- /dev/null +++ b/drivers/usb/gadget/udc/charger.c @@ -0,0 +1,770 @@ +/* + * charger.c -- USB charger driver + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SDP_CUR_LIMIT 500 +#define DEFAULT_SDP_CUR_LIMIT_SS 900 +#define DEFAULT_DCP_CUR_LIMIT 1500 +#define DEFAULT_CDP_CUR_LIMIT 1500 +#define DEFAULT_ACA_CUR_LIMIT 1500 + +static DEFINE_IDA(usb_charger_ida); +struct class *usb_charger_class; +static unsigned int usb_charger_get_cur_limit(struct usb_charger *uchger); + +static struct usb_charger *dev_to_uchger(struct device *dev) +{ + return container_of(dev, struct usb_charger, dev); +} + +/* + * charger_current_show() - Show the charger current limit. + */ +static ssize_t charger_current_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + + return sprintf(buf, "%u\n", usb_charger_get_cur_limit(uchger)); +} +static DEVICE_ATTR_RO(charger_current); + +/* + * charger_type_show() - Show the charger type. + * + * It can be SDP/DCP/CDP/ACA type, else for unknown type. + */ +static ssize_t charger_type_show(struct device *dev, +struct device_attribute *attr, +char *buf) +{ + struct usb_charger *uchger = dev_to_uchger(dev); + int cnt; + + switch (uchger->type) { + case SDP_TYPE: + cnt = sprintf(buf, "%s\n", "SDP"); + break; + case DCP_TYPE: + cnt = sprintf(buf, "%s\n", "DCP"); + break; + case CDP_TYPE: + cnt = sprintf(buf, "%s\n", "CDP"); + break; + case
[PATCH v2] usb: dwc3: host: Set the dma_ops for xhci device
On ARM64 platform, it will set 'dummy_dma_ops' for device dma_ops if it did not call 'arch_setup_dma_ops' at device creation time, that will cause failure when setting the dma mask for device. Thus this patch set the xhci device dma_ops from the parent device if the xhci device dma_ops is 'dummy_dma_ops'. Changes since v1: - Add CONFIG_ARM64 macro. Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/dwc3/host.c |5 + 1 file changed, 5 insertions(+) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index c679f63..edb666d 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -32,6 +32,11 @@ int dwc3_host_init(struct dwc3 *dwc) return -ENOMEM; } +#ifdef CONFIG_ARM64 + if (get_dma_ops(>dev) == get_dma_ops(NULL)) + xhci->dev.archdata.dma_ops = get_dma_ops(dwc->dev); +#endif + dma_set_coherent_mask(>dev, dwc->dev->coherent_dma_mask); xhci->dev.parent= dwc->dev; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] dwc3: gadget: Introduce dwc3_endpoint_xfer_xxx() to check endpoint type
When handling the endpoint interrupt handler, it maybe disable the endpoint from another core user to set the USB endpoint descriptor pointor to be NULL while issuing usb_gadget_giveback_request() function to release lock. So it will be one bug to check the endpoint type by usb_endpoint_xfer_xxx() APIs with one NULL USB endpoint descriptor. Thus this patch introduces safety dwc3_endpoint_xfer_xxx() APIs to check endpoint type with checking if the endpoint flag 'DWC3_EP_ENABLED' is set or not. [ 4007.812527] c1 init(1) call enable_store(0) [ 4007.812633] c0 dwc3 2050.dwc3: ep1out disabled while handling ep event [ 4007.812657] c0 Unable to handle kernel NULL pointer dereference at virtual address 0003 [ 4007.812669] c0 pgd = ffc0260a8000 [ 4007.812681] c0 [0003] *pgd=b4ab4003, *pud=b4ab4003, *pmd= [ 4007.812709] c0 Internal error: Oops: 9606 [#1] PREEMPT SMP [ 4007.818441] c0 Modules linked in: bcmdhd [ 4007.821854] c3 warning saudio_recv cache is empty! [ 4007.821860] c3 aud_recv_cmd ENODATA [ 4007.821869] c3 aud_send_cmd in,cmd =11 id:10 ret-value:0 [ 4007.821876] c3 saudio_send: dst=1, channel=0, timeout=-1 [ 4007.840767] c0 mali_kbase(O) [ 4007.843707] c0 [ 4007.843889] c0 CPU: 0 PID: 8126 Comm: adbd Tainted: GW O 3.18.12+ #1 [ 4007.851153] c0 Hardware name: Spreadtrum SP9860g Board (DT) [ 4007.856693] c0 task: ffc02638a400 ti: ffc026148000 task.ti: ffc026148000 [ 4007.864404] c0 PC is at dwc3_interrupt_bh+0x710/0x112c [ 4007.869503] c0 LR is at dwc3_interrupt_bh+0x70c/0x112c [ 4007.874604] c0 pc : [] lr : [] pstate: 21c5 [ 4007.882218] c0 sp : ffc02614b970 [ 4007.885766] c0 x29: ffc02614b970 x28: ffc000c75f90 [ 4007.891044] c0 x27: 0008 x26: [ 4007.896323] c0 x25: x24: 030c [ 4007.901602] c0 x23: ffc000ff1000 x22: 0004 [ 4007.906881] c0 x21: ffc03d9fb5d8 x20: ffc13e573600 [ 4007.912160] c0 x19: ffc13e133020 x18: 0007 [ 4007.917437] c0 x17: 000e x16: 0001 [ 4007.922717] c0 x15: 0007 x14: 0fff [ 4007.927996] c0 x13: 0001 x12: 0101010101010101 [ 4007.933274] c0 x11: 000c4f5d x10: 0002 [ 4007.938553] c0 x9 : x8 : 000c4f5e [ 4007.943833] c0 x7 : 696c646e61682065 x6 : ffc000fa6cdc [ 4007.949111] c0 x5 : x4 : 0105 [ 4007.954390] c0 x3 : x2 : [ 4007.959669] c0 x1 : 5533250a x0 : .. [ 4009.150699] c0 Call trace: [ 4009.153394] c0 [] dwc3_interrupt_bh+0x710/0x112c [ 4009.159532] c0 [] tasklet_action+0xb0/0x188 [ 4009.165243] c0 [] __do_softirq+0x114/0x3b4 [ 4009.170867] c0 [] irq_exit+0xa8/0xdc [ 4009.175975] c0 [] __handle_domain_irq+0x90/0xf8 [ 4009.182030] c0 [] gic_handle_irq+0x58/0x1b4 [ 4009.187739] c0 Exception stack(0xffc02614bb70 to 0xffc02614bc90) [ 4009.194404] c0 bb60: 0140 3e133108 ffc1 [ 4009.202802] c0 bb80: 2614bcd0 ffc0 009cff0c ffc0 8145 0018 [ 4009.211194] c0 bba0: 0400 00459900 ffc0 00d1aa50 ffc0 [ 4009.219589] c0 bbc0: 2614bc00 ffc0 26148000 ffc0 0001 3d2ce4e0 ffc1 [ 4009.227984] c0 bbe0: bdc0 0001 2638a980 ffc0 2614ba40 ffc0 [ 4009.236379] c0 bc00: 0400 0001 1d37bbb0 ffc0 0013 [ 4009.244772] c0 bc20: 000e 0007 0001 000e [ 4009.253167] c0 bc40: 0007 0140 3e133108 ffc1 3e133108 ffc1 [ 4009.261560] c0 bc60: 0140 3eb833c0 ffc1 0018 0400 [ 4009.269951] c0 bc80: 1eb29b80 ffc1 3acd7c00 ffc0 [ 4009.275233] c0 [] el1_irq+0x68/0xdc [ 4009.280255] c0 [] dwc3_gadget_ep_dequeue+0x180/0x1b8 [ 4009.286741] c0 [] ffs_epfile_io+0x330/0x374 [ 4009.292453] c0 [] ffs_epfile_read+0x30/0x40 [ 4009.298169] c0 [] vfs_read+0xa0/0x1dc [ 4009.303357] c0 [] SyS_read+0x50/0xb0 Signed-off-by: Baolin Wang <baolin.w...@linaro.org> --- drivers/usb/dwc3/gadget.c | 95 ++--- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8e4a1b1..5d095f2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -36,6 +36,56 @@ #include "io.h" /** +* dwc3_endpoint_xfer_bulk - check if the endpoint has bulk transfer type +* @ep: endpoint to be checked +* +* Returns true if the endpoint is of type bulk, otherwise it returns false. +*/ +static inline int dwc3_endpoint_xfer_bulk(struct dwc3_ep *ep) +{ + return ((ep->flags & DWC3_EP_ENABLED) && + ep->type == USB_ENDPOINT_XFER_BULK); +} +
Re: [PATCH] dwc3: gadget: Introduce dwc3_endpoint_xfer_xxx() to check endpoint type
Hi Felipe, On 26 May 2016 at 14:22, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >> When handling the endpoint interrupt handler, it maybe disable the endpoint >> from another core user to set the USB endpoint descriptor pointor to be NULL >> while issuing usb_gadget_giveback_request() function to release lock. So it >> will be one bug to check the endpoint type by usb_endpoint_xfer_xxx() APIs >> with >> one NULL USB endpoint descriptor. > > too complex, Baolin :-) Can you see if this helps: > > https://git.kernel.org/cgit/linux/kernel/git/balbi/usb.git/commit/?id=88bf752cfb55e57a78e27c931c9fef63240c739a > > The only situation when that can happen is while we drop our lock on > dwc3_gadget_giveback(). OK, But line 1974 and line 2025 as below may be at risk? So I think can we have a common place to solve the problem in case usb_endpoint_xfer_xxx() APIs are issued at this risk? What do you think? Thanks. 1956 static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, 1957 const struct dwc3_event_depevt *event, int status) 1958 { 1959 struct dwc3_request *req; 1960 struct dwc3_trb *trb; 1961 unsigned intslot; 1962 unsigned inti; 1963 int ret; 1964 1965 do { 1966 req = next_request(>req_queued); 1967 if (WARN_ON_ONCE(!req)) 1968 return 1; 1969 1970 i = 0; 1971 do { 1972 slot = req->start_slot + i; 1973 if ((slot == DWC3_TRB_NUM - 1) && 1974 usb_endpoint_xfer_isoc(dep->endpoint.desc)) 1975 slot++; 1976 slot %= DWC3_TRB_NUM; 1977 trb = >trb_pool[slot]; 1978 1979 ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, 1980 event, status); 1981 if (ret) 1982 break; 1983 } while (++i < req->request.num_mapped_sgs); 1984 1985 dwc3_gadget_giveback(dep, req, status); 1986 1987 if (ret) 1988 break; 1989 } while (1); ... 2011 static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, 2012 struct dwc3_ep *dep, const struct dwc3_event_depevt *event) 2013 { 2014 unsignedstatus = 0; 2015 int clean_busy; 2016 u32 is_xfer_complete; 2017 2018 is_xfer_complete = (event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE); 2019 2020 if (event->status & DEPEVT_STATUS_BUSERR) 2021 status = -ECONNRESET; 2022 2023 clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); 2024 if (clean_busy && (is_xfer_complete || 2025 usb_endpoint_xfer_isoc(dep->endpoint.desc))) 2026 dep->flags &= ~DWC3_EP_BUSY; > > -- > balbi -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] dwc3: gadget: Introduce dwc3_endpoint_xfer_xxx() to check endpoint type
On 26 May 2016 at 18:27, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >> On 26 May 2016 at 17:45, Felipe Balbi <ba...@kernel.org> wrote: >>> >>> Hi, >>> >>> Baolin Wang <baolin.w...@linaro.org> writes: >>> >>> >>> >>>>> Also note that the usb_endpoint_xfer_isoc() call on line 2067 of >>>>> gadget.c (as in my testing/next from today) won't even get executed, so >>>>> we're safe there. >>>> >>>> Never will be executed? then we can remove the >>>> usb_endpoint_xfer_isoc() (line 2025) at risk? >>>> >>>> 2023 clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); >>>> 2024 if (clean_busy && (is_xfer_complete || >>>> 2025 >>>> usb_endpoint_xfer_isoc(dep->endpoint.desc))) >>>> 2026 dep->flags &= ~DWC3_EP_BUSY; >>> >>> hmm, now that I look at this again, in case of XferInProgress, we could >>> still have a problem. >>> >>> I'll fix it up in that commit I pointed you to. >> >> Great. Thanks. > > fixed now: > > https://git.kernel.org/cgit/linux/kernel/git/balbi/usb.git/commit/?h=testing/next=983b84268656ff2686253b05097d28003bbec52f OK. I'll test it again with applying your patch. Thanks. > > -- > balbi -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] dwc3: gadget: Introduce dwc3_endpoint_xfer_xxx() to check endpoint type
On 26 May 2016 at 17:45, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: > > > >>> Also note that the usb_endpoint_xfer_isoc() call on line 2067 of >>> gadget.c (as in my testing/next from today) won't even get executed, so >>> we're safe there. >> >> Never will be executed? then we can remove the >> usb_endpoint_xfer_isoc() (line 2025) at risk? >> >> 2023 clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); >> 2024 if (clean_busy && (is_xfer_complete || >> 2025 >> usb_endpoint_xfer_isoc(dep->endpoint.desc))) >> 2026 dep->flags &= ~DWC3_EP_BUSY; > > hmm, now that I look at this again, in case of XferInProgress, we could > still have a problem. > > I'll fix it up in that commit I pointed you to. Great. Thanks. > > -- > balbi -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v12 2/4] gadget: Support for the usb charger framework
On 21 June 2016 at 18:27, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >> For supporting the usb charger, it adds the usb_charger_init() and >> usb_charger_exit() functions for usb charger initialization and exit. >> >> It will report to the usb charger when the gadget state is changed, >> then the usb charger can do the power things. >> >> Signed-off-by: Baolin Wang <baolin.w...@linaro.org> >> Reviewed-by: Li Jun <jun...@nxp.com> >> Tested-by: Li Jun <jun...@nxp.com> > > Before anything, I must say that I really liked this patch. It's Thanks. > minimaly invasive to udc core and does all the necessary changes. If it > wasn't for the extra charger class, this would've been perfect. > > Can't you just tie a charger to a UDC and avoid the charger class > completely? Yeah, I also hope so. But we really want something to manage the charger devices, do you have any good suggestion to avoid the 'class' but also can manage the charger devices? > >> static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned >> mA) >> { >> + if (gadget->charger) > > I guess you could do this check inside > usb_gadget_set_cur_limit_by_type() itself. OK. > > -- > balbi -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v12 4/4] power: wm831x_power: Support USB charger current limit management
On 21 June 2016 at 19:53, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >> On 21 June 2016 at 19:03, Mark Brown <broo...@kernel.org> wrote: >>> On Tue, Jun 21, 2016 at 01:30:49PM +0300, Felipe Balbi wrote: >>>> Baolin Wang <baolin.w...@linaro.org> writes: >>>> > @@ -607,8 +647,31 @@ static int wm831x_power_probe(struct >>>> > platform_device *pdev) >>>> > } >>>> > } >>> >>>> > + if (wm831x_pdata && wm831x_pdata->usb_gadget) { >>>> > + power->usb_charger = >>>> > + usb_charger_find_by_name(wm831x_pdata->usb_gadget); >>> >>>> the fact that you rely on strings and pass them via pdata is an >>>> indication that you don't have enough description of the HW. Seems like >>>> we need to come up with a set of DT properties which tie a charger to a >>>> UDC. >>> >>>> I'm thinking a phandle would be enough? >>> >>> The wm831x has no DT support currently. >> >> Another hand I suppose the usb charger is one virtual device and does >> not need be described from DT. > > Right, I don't think that should be a device at all. But you can pass a > phandle to the UDC controller and use that to get to struct usb_gadget > from which you could reach ->charger. Ah, make sense. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v12 2/4] gadget: Support for the usb charger framework
On 21 June 2016 at 19:49, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Baolin Wang <baolin.w...@linaro.org> writes: >>> Can't you just tie a charger to a UDC and avoid the charger class >>> completely? >> >> Yeah, I also hope so. But we really want something to manage the >> charger devices, do you have any good suggestion to avoid the 'class' >> but also can manage the charger devices? > > manage in what way? It seems to me that they don't need to be real > devices, just a handle as part of struct usb_gadget, no? Although charger device is not one real hardware device, we also use one 'struct device' to describe it in charger.c file. So we should manage the 'struct device' with one proper way. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v12 4/4] power: wm831x_power: Support USB charger current limit management
On 21 June 2016 at 19:03, Mark Brown <broo...@kernel.org> wrote: > On Tue, Jun 21, 2016 at 01:30:49PM +0300, Felipe Balbi wrote: >> Baolin Wang <baolin.w...@linaro.org> writes: >> > @@ -607,8 +647,31 @@ static int wm831x_power_probe(struct platform_device >> > *pdev) >> > } >> > } > >> > + if (wm831x_pdata && wm831x_pdata->usb_gadget) { >> > + power->usb_charger = >> > + usb_charger_find_by_name(wm831x_pdata->usb_gadget); > >> the fact that you rely on strings and pass them via pdata is an >> indication that you don't have enough description of the HW. Seems like >> we need to come up with a set of DT properties which tie a charger to a >> UDC. > >> I'm thinking a phandle would be enough? > > The wm831x has no DT support currently. Another hand I suppose the usb charger is one virtual device and does not need be described from DT. -- Baolin.wang Best Regards -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v12 0/4] Introduce usb charger framework to deal with the usb gadget power negotation
Currently the Linux kernel does not provide any standard integration of this feature that integrates the USB subsystem with the system power regulation provided by PMICs meaning that either vendors must add this in their kernels or USB gadget devices based on Linux (such as mobile phones) may not behave as they should. Thus provide a standard framework for doing this in kernel. Now introduce one user with wm831x_power to support and test the usb charger, which is pending testing. Moreover there may be other potential users will use it in future. Changes since v11: - Reviewed and tested by Li Jun. Changes since v10: - Introduce usb_charger_get_state() function to check charger state. - Remove the mutex lock in usb_charger_set_cur_limit_by_type() function in case will be issued in atomic context. Baolin Wang (4): gadget: Introduce the usb charger framework gadget: Support for the usb charger framework gadget: Integrate with the usb gadget supporting for usb charger power: wm831x_power: Support USB charger current limit management drivers/power/wm831x_power.c | 69 drivers/usb/gadget/Kconfig|7 + drivers/usb/gadget/udc/Makefile |1 + drivers/usb/gadget/udc/charger.c | 807 + drivers/usb/gadget/udc/udc-core.c | 11 + include/linux/mfd/wm831x/pdata.h |3 + include/linux/usb/charger.h | 191 + include/linux/usb/gadget.h| 11 + include/uapi/linux/usb/charger.h | 31 ++ 9 files changed, 1131 insertions(+) create mode 100644 drivers/usb/gadget/udc/charger.c create mode 100644 include/linux/usb/charger.h create mode 100644 include/uapi/linux/usb/charger.h -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html