On Fri, Apr 01, 2016 at 03:21:49PM +0800, Baolin Wang wrote:
> +
> +int devm_usb_charger_register(struct device *dev,
> +                           struct usb_charger *uchger)
> +{
> +     struct usb_charger **ptr;
> +     int ret;
> +
> +     ptr = devres_alloc(devm_uchger_dev_unreg, sizeof(*ptr), GFP_KERNEL);
> +     if (!ptr)
> +             return -ENOMEM;
> +
> +     ret = usb_charger_register(dev, uchger);
> +     if (ret) {
> +             devres_free(ptr);
> +             return ret;
> +     }
> +
> +     *ptr = uchger;
> +     devres_add(dev, ptr);
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL(devm_usb_charger_register);

When the above API is expected to call? Can we use the USB charger
without USB gadget?

> +
> +int usb_charger_init(struct usb_gadget *ugadget)
> +{
> +     struct usb_charger *uchger;
> +     struct extcon_dev *edev;
> +     struct power_supply *psy;
> +     int ret;
> +
> +     uchger = kzalloc(sizeof(struct usb_charger), GFP_KERNEL);
> +     if (!uchger)
> +             return -ENOMEM;
> +
> +     uchger->type = UNKNOWN_TYPE;
> +     uchger->state = USB_CHARGER_DEFAULT;
> +     uchger->id = -1;
> +
> +     if (ugadget->speed >= USB_SPEED_SUPER)
> +             uchger->cur_limit.sdp_cur_limit = DEFAULT_SDP_CUR_LIMIT_SS;
> +     else
> +             uchger->cur_limit.sdp_cur_limit = DEFAULT_SDP_CUR_LIMIT;

We still haven't known bus speed here, it is better do it after
setting configuration has finished.

Peter

> +     uchger->cur_limit.dcp_cur_limit = DEFAULT_DCP_CUR_LIMIT;
> +     uchger->cur_limit.cdp_cur_limit = DEFAULT_CDP_CUR_LIMIT;
> +     uchger->cur_limit.aca_cur_limit = DEFAULT_ACA_CUR_LIMIT;
> +
> +     mutex_init(&uchger->lock);
> +     RAW_INIT_NOTIFIER_HEAD(&uchger->uchger_nh);
> +
> +     /* register a notifier on a extcon device if it is exsited */
> +     edev = extcon_get_edev_by_phandle(ugadget->dev.parent, 0);
> +     if (!IS_ERR_OR_NULL(edev)) {
> +             uchger->extcon_dev = edev;
> +             uchger->extcon_nb.nb.notifier_call = usb_charger_plug_by_extcon;
> +             uchger->extcon_nb.uchger = uchger;
> +             extcon_register_notifier(edev, EXTCON_USB,
> +                                      &uchger->extcon_nb.nb);
> +     }
> +
> +     /* to check if the usb charger is link to a power supply */
> +     psy = devm_power_supply_get_by_phandle(ugadget->dev.parent,
> +                                            "power-supplies");
> +     if (!IS_ERR_OR_NULL(psy))
> +             uchger->psy = psy;
> +     else
> +             uchger->psy = NULL;
> +
> +     /* register a notifier on a usb gadget device */
> +     uchger->gadget = ugadget;
> +     uchger->old_gadget_state = ugadget->state;
> +
> +     /* register a new usb charger */
> +     ret = usb_charger_register(&ugadget->dev, uchger);
> +     if (ret)
> +             goto fail;
> +
> +     return 0;
> +
> +fail:
> +     if (uchger->extcon_dev)
> +             extcon_unregister_notifier(uchger->extcon_dev,
> +                                        EXTCON_USB, &uchger->extcon_nb.nb);
> +
> +     kfree(uchger);
> +     return ret;
> +}
> +
> +int usb_charger_exit(struct usb_gadget *ugadget)
> +{
> +     return 0;
> +}
> +
> +static int __init usb_charger_class_init(void)
> +{
> +     usb_charger_class = class_create(THIS_MODULE, "usb_charger");
> +     if (IS_ERR(usb_charger_class)) {
> +             pr_err("couldn't create class\n");
> +             return PTR_ERR(usb_charger_class);
> +     }
> +
> +     return 0;
> +}
> +
> +static void __exit usb_charger_class_exit(void)
> +{
> +     class_destroy(usb_charger_class);
> +}
> +subsys_initcall(usb_charger_class_init);
> +module_exit(usb_charger_class_exit);
> +
> +MODULE_AUTHOR("Baolin Wang <baolin.w...@linaro.org>");
> +MODULE_DESCRIPTION("USB charger driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/usb/charger.h b/include/linux/usb/charger.h
> new file mode 100644
> index 0000000..1bf1d55
> --- /dev/null
> +++ b/include/linux/usb/charger.h
> @@ -0,0 +1,171 @@
> +#ifndef __LINUX_USB_CHARGER_H__
> +#define __LINUX_USB_CHARGER_H__
> +
> +#include <uapi/linux/usb/ch9.h>
> +#include <uapi/linux/usb/charger.h>
> +
> +/* Current limitation by charger type */
> +struct usb_charger_cur_limit {
> +     unsigned int sdp_cur_limit;
> +     unsigned int dcp_cur_limit;
> +     unsigned int cdp_cur_limit;
> +     unsigned int aca_cur_limit;
> +};
> +
> +struct usb_charger_nb {
> +     struct notifier_block   nb;
> +     struct usb_charger      *uchger;
> +};
> +
> +struct usb_charger {
> +     struct device           dev;
> +     struct raw_notifier_head        uchger_nh;
> +     /* protect the notifier head and charger */
> +     struct mutex            lock;
> +     int                     id;
> +     enum usb_charger_type   type;
> +     enum usb_charger_state  state;
> +
> +     /* for supporting extcon usb gpio */
> +     struct extcon_dev       *extcon_dev;
> +     struct usb_charger_nb   extcon_nb;
> +
> +     /* for supporting usb gadget */
> +     struct usb_gadget       *gadget;
> +     enum usb_device_state   old_gadget_state;
> +
> +     /* for supporting power supply */
> +     struct power_supply     *psy;
> +
> +     /* user can get charger type by implementing this callback */
> +     enum usb_charger_type   (*get_charger_type)(struct usb_charger *);
> +     /*
> +      * charger detection method can be implemented if you need to
> +      * manually detect the charger type.
> +      */
> +     enum usb_charger_type   (*charger_detect)(struct usb_charger *);
> +
> +     /* current limitation */
> +     struct usb_charger_cur_limit    cur_limit;
> +};
> +
> +#ifdef CONFIG_USB_CHARGER
> +extern struct usb_charger *usb_charger_find_by_name(const char *name);
> +
> +extern struct usb_charger *usb_charger_get(struct usb_charger *uchger);
> +extern void usb_charger_put(struct usb_charger *uchger);
> +
> +extern int usb_charger_register_notify(struct usb_charger *uchger,
> +                                    struct notifier_block *nb);
> +extern int usb_charger_unregister_notify(struct usb_charger *uchger,
> +                                      struct notifier_block *nb);
> +
> +extern int usb_charger_set_cur_limit(struct usb_charger *uchger,
> +                             struct usb_charger_cur_limit *cur_limit_set);
> +extern int usb_charger_set_cur_limit_by_type(struct usb_charger *uchger,
> +                                          enum usb_charger_type type,
> +                                          unsigned int cur_limit);
> +extern unsigned int usb_charger_get_current(struct usb_charger *uchger);
> +
> +extern int usb_charger_plug_by_gadget(struct usb_gadget *gadget,
> +                                   unsigned long state);
> +extern enum usb_charger_type usb_charger_get_type(struct usb_charger 
> *uchger);
> +extern int usb_charger_detect_type(struct usb_charger *uchger);
> +
> +extern void devm_usb_charger_unregister(struct device *dev,
> +                                     struct usb_charger *uchger);
> +extern int devm_usb_charger_register(struct device *dev,
> +                                  struct usb_charger *uchger);
> +
> +extern int usb_charger_init(struct usb_gadget *ugadget);
> +extern int usb_charger_exit(struct usb_gadget *ugadget);
> +#else
> +static inline struct usb_charger *usb_charger_find_by_name(const char *name)
> +{
> +     return ERR_PTR(-ENODEV);
> +}
> +
> +static inline struct usb_charger *usb_charger_get(struct usb_charger *uchger)
> +{
> +     return NULL;
> +}
> +
> +static inline void usb_charger_put(struct usb_charger *uchger)
> +{
> +}
> +
> +static inline int
> +usb_charger_register_notify(struct usb_charger *uchger,
> +                         struct notifier_block *nb)
> +{
> +     return 0;
> +}
> +
> +static inline int
> +usb_charger_unregister_notify(struct usb_charger *uchger,
> +                           struct notifier_block *nb)
> +{
> +     return 0;
> +}
> +
> +static inline int
> +usb_charger_set_cur_limit(struct usb_charger *uchger,
> +                       struct usb_charger_cur_limit *cur_limit_set)
> +{
> +     return 0;
> +}
> +
> +static inline int
> +usb_charger_set_cur_limit_by_type(struct usb_charger *uchger,
> +                               enum usb_charger_type type,
> +                               unsigned int cur_limit)
> +{
> +     return 0;
> +}
> +
> +static inline unsigned int
> +usb_charger_get_current(struct usb_charger *uchger)
> +{
> +     return 0;
> +}
> +
> +static inline enum usb_charger_type
> +usb_charger_get_type(struct usb_charger *uchger)
> +{
> +     return UNKNOWN_TYPE;
> +}
> +
> +static inline int usb_charger_detect_type(struct usb_charger *uchger)
> +{
> +     return 0;
> +}
> +
> +static inline int
> +usb_charger_plug_by_gadget(struct usb_gadget *gadget, unsigned long state)
> +{
> +     return 0;
> +}
> +
> +static inline void devm_usb_charger_unregister(struct device *dev,
> +                                            struct usb_charger *uchger)
> +{
> +}
> +
> +static inline int devm_usb_charger_register(struct device *dev,
> +                                         struct usb_charger *uchger)
> +{
> +     return 0;
> +}
> +
> +static inline int usb_charger_init(struct usb_gadget *ugadget)
> +{
> +     return 0;
> +}
> +
> +static inline int usb_charger_exit(struct usb_gadget *ugadget)
> +{
> +     return 0;
> +}
> +#endif
> +
> +#endif /* __LINUX_USB_CHARGER_H__ */
> diff --git a/include/uapi/linux/usb/charger.h 
> b/include/uapi/linux/usb/charger.h
> new file mode 100644
> index 0000000..3c56ec4
> --- /dev/null
> +++ b/include/uapi/linux/usb/charger.h
> @@ -0,0 +1,31 @@
> +/*
> + * This file defines the USB charger type and state that are needed for
> + * USB device APIs.
> + */
> +
> +#ifndef _UAPI__LINUX_USB_CHARGER_H
> +#define _UAPI__LINUX_USB_CHARGER_H
> +
> +/*
> + * USB charger type:
> + * SDP (Standard Downstream Port)
> + * DCP (Dedicated Charging Port)
> + * CDP (Charging Downstream Port)
> + * ACA (Accessory Charger Adapters)
> + */
> +enum usb_charger_type {
> +     UNKNOWN_TYPE,
> +     SDP_TYPE,
> +     DCP_TYPE,
> +     CDP_TYPE,
> +     ACA_TYPE,
> +};
> +
> +/* USB charger state */
> +enum usb_charger_state {
> +     USB_CHARGER_DEFAULT,
> +     USB_CHARGER_PRESENT,
> +     USB_CHARGER_REMOVE,
> +};
> +
> +#endif /* _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

-- 

Best Regards,
Peter Chen
--
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

Reply via email to