usb: phy: Introduce one extcon device into usb phy
authorBaolin Wang <baolin.wang@linaro.org>
Fri, 5 May 2017 06:12:24 +0000 (14:12 +0800)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Wed, 17 May 2017 11:15:28 +0000 (14:15 +0300)
Usually usb phy need register one extcon device to get the connection
notifications. It will remove some duplicate code if the extcon device
is registered using common code instead of each phy driver having its
own related extcon APIs. So we add one pointer of extcon device into
usb phy structure, and some other helper functions to register extcon.

Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/phy/Kconfig
drivers/usb/phy/phy.c
include/linux/usb/phy.h

index 3006f569c068106559b64d15c8acdb0c53e8c10c..aff702c0eb9fb5b83e210258d21f52827d75e134 100644 (file)
@@ -4,6 +4,7 @@
 menu "USB Physical Layer drivers"
 
 config USB_PHY
+       select EXTCON
        def_bool n
 
 #
@@ -109,7 +110,7 @@ config OMAP_OTG
 
 config TAHVO_USB
        tristate "Tahvo USB transceiver driver"
-       depends on MFD_RETU && EXTCON
+       depends on MFD_RETU
        depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        select USB_PHY
        help
@@ -141,7 +142,6 @@ config USB_MSM_OTG
        depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
        depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        depends on RESET_CONTROLLER
-       depends on EXTCON
        select USB_PHY
        help
          Enable this to support the USB OTG transceiver on Qualcomm chips. It
@@ -155,7 +155,7 @@ config USB_MSM_OTG
 config USB_QCOM_8X16_PHY
        tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support"
        depends on ARCH_QCOM || COMPILE_TEST
-       depends on RESET_CONTROLLER && EXTCON
+       depends on RESET_CONTROLLER
        select USB_PHY
        select USB_ULPI_VIEWPORT
        help
index 98f75d2842b7a0ba773fe3af641bb4b830faaf29..032f5afaad4b1be30e64b0cb1f7644f9ba696b00 100644 (file)
@@ -100,6 +100,54 @@ static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
        return *phy == match_data;
 }
 
+static int usb_add_extcon(struct usb_phy *x)
+{
+       int ret;
+
+       if (of_property_read_bool(x->dev->of_node, "extcon")) {
+               x->edev = extcon_get_edev_by_phandle(x->dev, 0);
+               if (IS_ERR(x->edev))
+                       return PTR_ERR(x->edev);
+
+               x->id_edev = extcon_get_edev_by_phandle(x->dev, 1);
+               if (IS_ERR(x->id_edev)) {
+                       x->id_edev = NULL;
+                       dev_info(x->dev, "No separate ID extcon device\n");
+               }
+
+               if (x->vbus_nb.notifier_call) {
+                       ret = devm_extcon_register_notifier(x->dev, x->edev,
+                                                           EXTCON_USB,
+                                                           &x->vbus_nb);
+                       if (ret < 0) {
+                               dev_err(x->dev,
+                                       "register VBUS notifier failed\n");
+                               return ret;
+                       }
+               }
+
+               if (x->id_nb.notifier_call) {
+                       struct extcon_dev *id_ext;
+
+                       if (x->id_edev)
+                               id_ext = x->id_edev;
+                       else
+                               id_ext = x->edev;
+
+                       ret = devm_extcon_register_notifier(x->dev, id_ext,
+                                                           EXTCON_USB_HOST,
+                                                           &x->id_nb);
+                       if (ret < 0) {
+                               dev_err(x->dev,
+                                       "register ID notifier failed\n");
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /**
  * devm_usb_get_phy - find the USB PHY
  * @dev - device that requests this phy
@@ -388,6 +436,10 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
                return -EINVAL;
        }
 
+       ret = usb_add_extcon(x);
+       if (ret)
+               return ret;
+
        ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
 
        spin_lock_irqsave(&phy_lock, flags);
@@ -422,12 +474,17 @@ int usb_add_phy_dev(struct usb_phy *x)
 {
        struct usb_phy_bind *phy_bind;
        unsigned long flags;
+       int ret;
 
        if (!x->dev) {
                dev_err(x->dev, "no device provided for PHY\n");
                return -EINVAL;
        }
 
+       ret = usb_add_extcon(x);
+       if (ret)
+               return ret;
+
        ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
 
        spin_lock_irqsave(&phy_lock, flags);
index 31a8068c42a56aded5bbdf0d779eebc5b9d628c2..299245105610f271aa68399508a0486aca595db7 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef __LINUX_USB_PHY_H
 #define __LINUX_USB_PHY_H
 
+#include <linux/extcon.h>
 #include <linux/notifier.h>
 #include <linux/usb.h>
 
@@ -85,6 +86,12 @@ struct usb_phy {
        struct usb_phy_io_ops   *io_ops;
        void __iomem            *io_priv;
 
+       /* to support extcon device */
+       struct extcon_dev       *edev;
+       struct extcon_dev       *id_edev;
+       struct notifier_block   vbus_nb;
+       struct notifier_block   id_nb;
+
        /* for notification of usb_phy_events */
        struct atomic_notifier_head     notifier;