|
@@ -21,6 +21,7 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/usb/ch9.h>
|
|
|
#include <linux/usb/gadget.h>
|
|
|
+#include <linux/usb/otg.h>
|
|
|
#include "common.h"
|
|
|
|
|
|
/*
|
|
@@ -50,6 +51,8 @@ struct usbhsg_gpriv {
|
|
|
int uep_size;
|
|
|
|
|
|
struct usb_gadget_driver *driver;
|
|
|
+ struct usb_phy *transceiver;
|
|
|
+ bool vbus_active;
|
|
|
|
|
|
u32 status;
|
|
|
#define USBHSG_STATUS_STARTED (1 << 0)
|
|
@@ -872,6 +875,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * VBUS provided by the PHY
|
|
|
+ */
|
|
|
+static int usbhsm_phy_get_vbus(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
|
|
|
+ struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
|
|
|
+
|
|
|
+ return gpriv->vbus_active;
|
|
|
+}
|
|
|
+
|
|
|
+static void usbhs_mod_phy_mode(struct usbhs_priv *priv)
|
|
|
+{
|
|
|
+ struct usbhs_mod_info *info = &priv->mod_info;
|
|
|
+
|
|
|
+ info->irq_vbus = NULL;
|
|
|
+ priv->pfunc.get_vbus = usbhsm_phy_get_vbus;
|
|
|
+
|
|
|
+ usbhs_irq_callback_update(priv, NULL);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
*
|
|
|
* linux usb function
|
|
@@ -882,12 +906,28 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
|
|
|
{
|
|
|
struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
|
|
|
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
|
|
|
+ struct device *dev = usbhs_priv_to_dev(priv);
|
|
|
+ int ret;
|
|
|
|
|
|
if (!driver ||
|
|
|
!driver->setup ||
|
|
|
driver->max_speed < USB_SPEED_FULL)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ /* connect to bus through transceiver */
|
|
|
+ if (!IS_ERR_OR_NULL(gpriv->transceiver)) {
|
|
|
+ ret = otg_set_peripheral(gpriv->transceiver->otg,
|
|
|
+ &gpriv->gadget);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "%s: can't bind to transceiver\n",
|
|
|
+ gpriv->gadget.name);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* get vbus using phy versions */
|
|
|
+ usbhs_mod_phy_mode(priv);
|
|
|
+ }
|
|
|
+
|
|
|
/* first hook up the driver ... */
|
|
|
gpriv->driver = driver;
|
|
|
|
|
@@ -900,6 +940,10 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget)
|
|
|
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
|
|
|
|
|
|
usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
|
|
|
+
|
|
|
+ if (!IS_ERR_OR_NULL(gpriv->transceiver))
|
|
|
+ otg_set_peripheral(gpriv->transceiver->otg, NULL);
|
|
|
+
|
|
|
gpriv->driver = NULL;
|
|
|
|
|
|
return 0;
|
|
@@ -947,12 +991,26 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active)
|
|
|
+{
|
|
|
+ struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
|
|
|
+ struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
|
|
|
+ struct platform_device *pdev = usbhs_priv_to_pdev(priv);
|
|
|
+
|
|
|
+ gpriv->vbus_active = !!is_active;
|
|
|
+
|
|
|
+ renesas_usbhs_call_notify_hotplug(pdev);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static const struct usb_gadget_ops usbhsg_gadget_ops = {
|
|
|
.get_frame = usbhsg_get_frame,
|
|
|
.set_selfpowered = usbhsg_set_selfpowered,
|
|
|
.udc_start = usbhsg_gadget_start,
|
|
|
.udc_stop = usbhsg_gadget_stop,
|
|
|
.pullup = usbhsg_pullup,
|
|
|
+ .vbus_session = usbhsg_vbus_session,
|
|
|
};
|
|
|
|
|
|
static int usbhsg_start(struct usbhs_priv *priv)
|
|
@@ -994,6 +1052,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
|
|
|
goto usbhs_mod_gadget_probe_err_gpriv;
|
|
|
}
|
|
|
|
|
|
+ gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
|
|
|
+ dev_info(dev, "%stransceiver found\n",
|
|
|
+ gpriv->transceiver ? "" : "no ");
|
|
|
+
|
|
|
/*
|
|
|
* CAUTION
|
|
|
*
|