Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5fd3fc1c authored by Phil Edworthy's avatar Phil Edworthy Committed by Greg Kroah-Hartman
Browse files

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.

Signed-off-by: default avatarPhil Edworthy <phil.edworthy@renesas.com>
Reviewed-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e616b39a
Loading
Loading
Loading
Loading
+62 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include "common.h"
#include "common.h"


/*
/*
@@ -50,6 +51,8 @@ struct usbhsg_gpriv {
	int			 uep_size;
	int			 uep_size;


	struct usb_gadget_driver	*driver;
	struct usb_gadget_driver	*driver;
	struct usb_phy		*transceiver;
	bool 			 vbus_active;


	u32	status;
	u32	status;
#define USBHSG_STATUS_STARTED		(1 << 0)
#define USBHSG_STATUS_STARTED		(1 << 0)
@@ -872,6 +875,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
	return 0;
	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
 *		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 usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
	struct device *dev = usbhs_priv_to_dev(priv);
	int ret;


	if (!driver		||
	if (!driver		||
	    !driver->setup	||
	    !driver->setup	||
	    driver->max_speed < USB_SPEED_FULL)
	    driver->max_speed < USB_SPEED_FULL)
		return -EINVAL;
		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 ... */
	/* first hook up the driver ... */
	gpriv->driver = 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);
	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);


	usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
	usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);

	if (!IS_ERR_OR_NULL(gpriv->transceiver))
		otg_set_peripheral(gpriv->transceiver->otg, NULL);

	gpriv->driver = NULL;
	gpriv->driver = NULL;


	return 0;
	return 0;
@@ -947,12 +991,26 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
	return 0;
	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 = {
static const struct usb_gadget_ops usbhsg_gadget_ops = {
	.get_frame		= usbhsg_get_frame,
	.get_frame		= usbhsg_get_frame,
	.set_selfpowered	= usbhsg_set_selfpowered,
	.set_selfpowered	= usbhsg_set_selfpowered,
	.udc_start		= usbhsg_gadget_start,
	.udc_start		= usbhsg_gadget_start,
	.udc_stop		= usbhsg_gadget_stop,
	.udc_stop		= usbhsg_gadget_stop,
	.pullup			= usbhsg_pullup,
	.pullup			= usbhsg_pullup,
	.vbus_session		= usbhsg_vbus_session,
};
};


static int usbhsg_start(struct usbhs_priv *priv)
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;
		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
	 * CAUTION
	 *
	 *