usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS
These changes allow a PHY driver to trigger a VBUS interrupt and to provide the value of VBUS. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Родитель
9e832bf7c0
Коммит
b5a2875605
|
@ -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
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче