summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/phy/Kconfig6
-rw-r--r--drivers/usb/phy/phy.c57
-rw-r--r--include/linux/usb/phy.h7
3 files changed, 67 insertions, 3 deletions
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 3006f569c068..aff702c0eb9f 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -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
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index 98f75d2842b7..032f5afaad4b 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -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);
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 31a8068c42a5..299245105610 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -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;