2015-07-02 07:38:58

by Phil Edworthy

[permalink] [raw]
Subject: [PATCH v2] 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: Phil Edworthy <[email protected]>

---
v2:
- vbus variables changed from int to bool.
- dev_info() changed to dev_err()
---
drivers/usb/renesas_usbhs/common.h | 2 ++
drivers/usb/renesas_usbhs/mod.c | 3 +++
drivers/usb/renesas_usbhs/mod_gadget.c | 38 ++++++++++++++++++++++++++++++++++
3 files changed, 43 insertions(+)

diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 8c5fc12..478700c 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -255,6 +255,8 @@ struct usbhs_priv {
struct renesas_usbhs_driver_param dparam;

struct delayed_work notify_hotplug_work;
+ bool vbus_is_indirect;
+ bool vbus_indirect_value;
struct platform_device *pdev;

struct extcon_dev *edev;
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 9a705b1..8a2d3dd 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -42,6 +42,9 @@ static int usbhsm_autonomy_get_vbus(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);

+ if (priv->vbus_is_indirect)
+ return priv->vbus_indirect_value;
+
return VBSTS & usbhs_read(priv, INTSTS0);
}

diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index dc2aa32..51b63f9 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -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,7 @@ struct usbhsg_gpriv {
int uep_size;

struct usb_gadget_driver *driver;
+ struct usb_phy *transceiver;

u32 status;
#define USBHSG_STATUS_STARTED (1 << 0)
@@ -882,6 +884,8 @@ 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 ||
@@ -891,6 +895,17 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
/* first hook up the driver ... */
gpriv->driver = driver;

+ /* 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;
+ }
+ }
+
return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
}

@@ -900,6 +915,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))
+ (void) otg_set_peripheral(gpriv->transceiver->otg, NULL);
+
gpriv->driver = NULL;

return 0;
@@ -947,12 +966,27 @@ 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);
+
+ priv->vbus_is_indirect = 1;
+ priv->vbus_indirect_value = !!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 +1028,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, "%s transceiver found\n",
+ gpriv->transceiver ? "" : "No");
+
/*
* CAUTION
*
--
1.9.1


2015-07-02 08:15:45

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Phil,

(CC'ing Morimoto-san)

Thank you for the patch.

On Thursday 02 July 2015 08:36:42 Phil Edworthy wrote:
> These changes allow a PHY driver to trigger a VBUS interrupt and
> to provide the value of VBUS.
>
> Signed-off-by: Phil Edworthy <[email protected]>
>
> ---
> v2:
> - vbus variables changed from int to bool.
> - dev_info() changed to dev_err()
> ---
> drivers/usb/renesas_usbhs/common.h | 2 ++
> drivers/usb/renesas_usbhs/mod.c | 3 +++
> drivers/usb/renesas_usbhs/mod_gadget.c | 38 +++++++++++++++++++++++++++++++
> 3 files changed, 43 insertions(+)
>
> diff --git a/drivers/usb/renesas_usbhs/common.h
> b/drivers/usb/renesas_usbhs/common.h index 8c5fc12..478700c 100644
> --- a/drivers/usb/renesas_usbhs/common.h
> +++ b/drivers/usb/renesas_usbhs/common.h
> @@ -255,6 +255,8 @@ struct usbhs_priv {
> struct renesas_usbhs_driver_param dparam;
>
> struct delayed_work notify_hotplug_work;
> + bool vbus_is_indirect;
> + bool vbus_indirect_value;
> struct platform_device *pdev;
>
> struct extcon_dev *edev;
> diff --git a/drivers/usb/renesas_usbhs/mod.c
> b/drivers/usb/renesas_usbhs/mod.c index 9a705b1..8a2d3dd 100644
> --- a/drivers/usb/renesas_usbhs/mod.c
> +++ b/drivers/usb/renesas_usbhs/mod.c
> @@ -42,6 +42,9 @@ static int usbhsm_autonomy_get_vbus(struct platform_device
> *pdev) {
> struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
>
> + if (priv->vbus_is_indirect)
> + return priv->vbus_indirect_value;
> +

Something is bothering me. The comment block right before this function states
that "these functions are used if platform doesn't have external phy".
However, the mechanism you implement here is aimed at letting a PHY control
vbus. I have a feeling this isn't the right mechanism.

> return VBSTS & usbhs_read(priv, INTSTS0);
> }
>
> diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..51b63f9 100644
> --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> @@ -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,7 @@ struct usbhsg_gpriv {
> int uep_size;
>
> struct usb_gadget_driver *driver;
> + struct usb_phy *transceiver;
>
> u32 status;
> #define USBHSG_STATUS_STARTED (1 << 0)
> @@ -882,6 +884,8 @@ 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 ||
> @@ -891,6 +895,17 @@ static int usbhsg_gadget_start(struct usb_gadget
> *gadget, /* first hook up the driver ... */
> gpriv->driver = driver;
>
> + /* 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);

Shouldn't gpriv->driver be set to NULL here ? Or possibly better, this code
block moved before setting gpriv->driver ?

> + return ret;
> + }
> + }
> +
> return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
> }
>
> @@ -900,6 +915,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))
> + (void) otg_set_peripheral(gpriv->transceiver->otg, NULL);

Is there really a need for (void) ?

> +
> gpriv->driver = NULL;
>
> return 0;
> @@ -947,12 +966,27 @@ 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);
> +
> + priv->vbus_is_indirect = 1;
> + priv->vbus_indirect_value = !!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 +1028,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, "%s transceiver found\n",
> + gpriv->transceiver ? "" : "No");
> +
> /*
> * CAUTION
> *

--
Regards,

Laurent Pinchart

2015-07-02 08:36:22

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v2] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Laurent,

On 02 July 2015 09:15, Laurent wrote:
> Hi Phil,
>
> (CC'ing Morimoto-san)
>
> Thank you for the patch.
>
> On Thursday 02 July 2015 08:36:42 Phil Edworthy wrote:
> > These changes allow a PHY driver to trigger a VBUS interrupt and
> > to provide the value of VBUS.
> >
> > Signed-off-by: Phil Edworthy <[email protected]>
> >
> > ---
> > v2:
> > - vbus variables changed from int to bool.
> > - dev_info() changed to dev_err()
> > ---
> > drivers/usb/renesas_usbhs/common.h | 2 ++
> > drivers/usb/renesas_usbhs/mod.c | 3 +++
> > drivers/usb/renesas_usbhs/mod_gadget.c | 38
> +++++++++++++++++++++++++++++++
> > 3 files changed, 43 insertions(+)
> >
> > diff --git a/drivers/usb/renesas_usbhs/common.h
> > b/drivers/usb/renesas_usbhs/common.h index 8c5fc12..478700c 100644
> > --- a/drivers/usb/renesas_usbhs/common.h
> > +++ b/drivers/usb/renesas_usbhs/common.h
> > @@ -255,6 +255,8 @@ struct usbhs_priv {
> > struct renesas_usbhs_driver_param dparam;
> >
> > struct delayed_work notify_hotplug_work;
> > + bool vbus_is_indirect;
> > + bool vbus_indirect_value;
> > struct platform_device *pdev;
> >
> > struct extcon_dev *edev;
> > diff --git a/drivers/usb/renesas_usbhs/mod.c
> > b/drivers/usb/renesas_usbhs/mod.c index 9a705b1..8a2d3dd 100644
> > --- a/drivers/usb/renesas_usbhs/mod.c
> > +++ b/drivers/usb/renesas_usbhs/mod.c
> > @@ -42,6 +42,9 @@ static int usbhsm_autonomy_get_vbus(struct
> platform_device
> > *pdev) {
> > struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
> >
> > + if (priv->vbus_is_indirect)
> > + return priv->vbus_indirect_value;
> > +
>
> Something is bothering me. The comment block right before this function states
> that "these functions are used if platform doesn't have external phy".
> However, the mechanism you implement here is aimed at letting a PHY control
> vbus. I have a feeling this isn't the right mechanism.

I took the comment as though it was talking about an physically external PHY, but
I suppose it makes no difference from the point of view of this driver. I'll have a
look to see if there is a better way to hook this in.


> > return VBSTS & usbhs_read(priv, INTSTS0);
> > }
> >
> > diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> > b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..51b63f9 100644
> > --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> > +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> > @@ -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,7 @@ struct usbhsg_gpriv {
> > int uep_size;
> >
> > struct usb_gadget_driver *driver;
> > + struct usb_phy *transceiver;
> >
> > u32 status;
> > #define USBHSG_STATUS_STARTED (1 << 0)
> > @@ -882,6 +884,8 @@ 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 ||
> > @@ -891,6 +895,17 @@ static int usbhsg_gadget_start(struct usb_gadget
> > *gadget, /* first hook up the driver ... */
> > gpriv->driver = driver;
> >
> > + /* 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);
>
> Shouldn't gpriv->driver be set to NULL here ? Or possibly better, this code
> block moved before setting gpriv->driver ?
Makes sense.

> > + return ret;
> > + }
> > + }
> > +
> > return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
> > }
> >
> > @@ -900,6 +915,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))
> > + (void) otg_set_peripheral(gpriv->transceiver->otg, NULL);
>
> Is there really a need for (void) ?
Oops, none at all.

> > +
> > gpriv->driver = NULL;
> >
> > return 0;
> > @@ -947,12 +966,27 @@ 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);
> > +
> > + priv->vbus_is_indirect = 1;
> > + priv->vbus_indirect_value = !!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 +1028,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, "%s transceiver found\n",
> > + gpriv->transceiver ? "" : "No");
> > +
> > /*
> > * CAUTION
> > *
>
> --
> Regards,
>
> Laurent Pinchart

Thanks
Phil

2015-07-02 10:28:55

by Phil Edworthy

[permalink] [raw]
Subject: [PATCH v3] 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: Phil Edworthy <[email protected]>

---
v3:
- Changed how indirect vbus is plumbed in.
- Removed unnecessary (void) on call to otg_set_peripheral.
- Moved code that connects to bus through transceiver so it
is before setting gpriv->driver.

v2:
- vbus variables changed from int to bool.
- dev_info() changed to dev_err()
---
drivers/usb/renesas_usbhs/common.c | 8 +++++--
drivers/usb/renesas_usbhs/common.h | 2 ++
drivers/usb/renesas_usbhs/mod_gadget.c | 38 ++++++++++++++++++++++++++++++++++
3 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 0f7e850..15e67d8 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -379,7 +379,10 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
/*
* get vbus status from platform
*/
- enable = usbhs_platform_call(priv, get_vbus, pdev);
+ if (priv->vbus_is_indirect)
+ enable = priv->vbus_indirect_value;
+ else
+ enable = usbhs_platform_call(priv, get_vbus, pdev);

/*
* get id from platform
@@ -662,7 +665,8 @@ static int usbhs_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
usbhsc_power_ctrl(priv, 1);
- usbhs_mod_autonomy_mode(priv);
+ if (!priv->vbus_is_indirect)
+ usbhs_mod_autonomy_mode(priv);
}

/*
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 8c5fc12..478700c 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -255,6 +255,8 @@ struct usbhs_priv {
struct renesas_usbhs_driver_param dparam;

struct delayed_work notify_hotplug_work;
+ bool vbus_is_indirect;
+ bool vbus_indirect_value;
struct platform_device *pdev;

struct extcon_dev *edev;
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index dc2aa32..93ad4ea 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -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,7 @@ struct usbhsg_gpriv {
int uep_size;

struct usb_gadget_driver *driver;
+ struct usb_phy *transceiver;

u32 status;
#define USBHSG_STATUS_STARTED (1 << 0)
@@ -882,12 +884,25 @@ 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;
+ }
+ }
+
/* first hook up the driver ... */
gpriv->driver = driver;

@@ -900,6 +915,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 +966,27 @@ 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);
+
+ priv->vbus_is_indirect = 1;
+ priv->vbus_indirect_value = !!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 +1028,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, "%s transceiver found\n",
+ gpriv->transceiver ? "" : "No");
+
/*
* CAUTION
*
--
1.9.1

2015-07-02 11:16:52

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH v2] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hello.

On 7/2/2015 10:36 AM, Phil Edworthy wrote:

> These changes allow a PHY driver to trigger a VBUS interrupt and
> to provide the value of VBUS.

> Signed-off-by: Phil Edworthy <[email protected]>

[...]

> diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
> index dc2aa32..51b63f9 100644
> --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
[...]
> @@ -947,12 +966,27 @@ 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);
> +
> + priv->vbus_is_indirect = 1;

s/1/true/.

> + priv->vbus_indirect_value = !!is_active;
> +
> + renesas_usbhs_call_notify_hotplug(pdev);
> +
> + return 0;
> +}
> +
[...]
> @@ -994,6 +1028,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, "%s transceiver found\n",
> + gpriv->transceiver ? "" : "No");

Hm, I told you to make this message cleaner, and you haven't. :-(

[...]

WBR, Sergei

2015-07-02 12:01:25

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v2] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Sergei,

On 02 July 2015 12:17, Sergei wrote:
> To: Phil Edworthy; Yoshihiro Shimoda
> Hello.
>
> On 7/2/2015 10:36 AM, Phil Edworthy wrote:
>
> > These changes allow a PHY driver to trigger a VBUS interrupt and
> > to provide the value of VBUS.
>
> > Signed-off-by: Phil Edworthy <[email protected]>
>
> [...]
>
> > diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> b/drivers/usb/renesas_usbhs/mod_gadget.c
> > index dc2aa32..51b63f9 100644
> > --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> > +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> [...]
> > @@ -947,12 +966,27 @@ 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);
> > +
> > + priv->vbus_is_indirect = 1;
>
> s/1/true/.
Ok.

> > + priv->vbus_indirect_value = !!is_active;
> > +
> > + renesas_usbhs_call_notify_hotplug(pdev);
> > +
> > + return 0;
> > +}
> > +
> [...]
> > @@ -994,6 +1028,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, "%s transceiver found\n",
> > + gpriv->transceiver ? "" : "No");
>
> Hm, I told you to make this message cleaner, and you haven't. :-(
Ah, sorry, I missed that comment.

> [...]
>
> WBR, Sergei

Thanks
Phil

2015-07-06 07:27:46

by Yoshihiro Shimoda

[permalink] [raw]
Subject: RE: [PATCH v3] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Phil-san,

> Sent: Thursday, July 02, 2015 7:27 PM
>
> These changes allow a PHY driver to trigger a VBUS interrupt and
> to provide the value of VBUS.
>
> Signed-off-by: Phil Edworthy <[email protected]>

Thank you for the patch!

However, if I tested this patch, a kernel panic happened when
I did "rmmod g_mass_storage" on koelsch:

root@192:~/usb# rmmod g_mass_storage
Unable to handle kernel NULL pointer dereference at virtual address 00000004
pgd = eebd4bc0
[00000004] *pgd=00000000
Internal error: Oops: 205 [#1] SMP ARM
Modules linked in: g_mass_storage(-) usb_f_mass_storage libcomposite
CPU: 0 PID: 2496 Comm: rmmod Not tainted 4.1.0-dirty #32
Hardware name: Generic R8A7791 (Flattened Device Tree)
task: eeb64ac0 ti: ee022000 task.ti: ee022000
PC is at usbhs_pkt_pop+0x1c/0x100
LR is at usbhsg_ep_dequeue+0x28/0x40
pc : [<c036d934>] lr : [<c036e364>] psr: 20000013
sp : ee023e70 ip : ee023e98 fp : ee023e94
r10: 00000000 r9 : ee022000 r8 : c00101e4
r7 : 00200200 r6 : 00100100 r5 : 00000000 r4 : eeb917f8
r3 : c036e33c r2 : 00000041 r1 : eeb917f8 r0 : 00000000
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 30c5307d Table: 6ebd4bc0 DAC: fffffffd
Process rmmod (pid: 2496, stack limit = 0xee022210)
Stack: (0xee023e70 to 0xee024000)
3e60: ee1b1400 eeb917c0 00100100 00200200
3e80: c00101e4 ee022000 ee023eac ee023e98 c036e364 c036d924 eeb34180 eeb341c0
3ea0: ee023ecc ee023eb0 bf002f20 c036e348 eeb34180 00000001 ee1b1800 eeb341b8
3ec0: ee023eec ee023ed0 bf002fec bf002e5c ee181600 bf01d624 bed3ff0d 00000081
3ee0: ee023efc ee023ef0 bf003028 bf002f78 ee023f14 ee023f00 c036fb88 bf003018
3f00: ee181600 bf01d624 ee023f2c ee023f18 c036fc10 c036fb34 bf01d694 7f64cd30
3f20: ee023f3c ee023f30 bf0013d0 c036fbbc ee023f4c ee023f40 bf01d26c bf0013c0
3f40: ee023fa4 ee023f50 c0090bd8 bf01d248 ee023f6c 616d5f67 735f7373 61726f74
3f60: 00006567 ee023f70 c00460f4 c052a8c0 c00101e4 ee022010 ee023fb0 ee022000
3f80: ee023fac ee023f90 c00136c4 00046038 00000001 7f64cd00 00000000 ee023fa8
3fa0: c0010040 c0090adc 00000001 7f64cd00 7f64cd30 00000800 ccd5c100 ccd5c100
3fc0: 00000001 7f64cd00 bed3ff0d 00000081 7f64c008 00000000 00000002 00000800
3fe0: bed3fe0c bed3fb98 b6eeb068 b6e4f05c 60000010 7f64cd30 00000000 00000000
Backtrace:
[<c036d918>] (usbhs_pkt_pop) from [<c036e364>] (usbhsg_ep_dequeue+0x28/0x40)
r9:ee022000 r8:c00101e4 r7:00200200 r6:00100100 r5:eeb917c0 r4:ee1b1400
[<c036e33c>] (usbhsg_ep_dequeue) from [<bf002f20>] (composite_dev_cleanup+0xd0/0x11c [libcomposite])
r5:eeb341c0 r4:eeb34180
[<bf002e50>] (composite_dev_cleanup [libcomposite]) from [<bf002fec>] (__composite_unbind+0x80/0xa0 [libcomposite])
r7:eeb341b8 r6:ee1b1800 r5:00000001 r4:eeb34180
[<bf002f6c>] (__composite_unbind [libcomposite]) from [<bf003028>] (composite_unbind+0x1c/0x20 [libcomposite])
r7:00000081 r6:bed3ff0d r5:bf01d624 r4:ee181600
[<bf00300c>] (composite_unbind [libcomposite]) from [<c036fb88>] (usb_gadget_remove_driver+0x60/0x88)
[<c036fb28>] (usb_gadget_remove_driver) from [<c036fc10>] (usb_gadget_unregister_driver+0x60/0xa0)
r5:bf01d624 r4:ee181600
[<c036fbb0>] (usb_gadget_unregister_driver) from [<bf0013d0>] (usb_composite_unregister+0x1c/0x20 [libcomposite])
r5:7f64cd30 r4:bf01d694
[<bf0013b4>] (usb_composite_unregister [libcomposite]) from [<bf01d26c>] (msg_cleanup+0x30/0x3c [g_mass_storage])
[<bf01d23c>] (msg_cleanup [g_mass_storage]) from [<c0090bd8>] (SyS_delete_module+0x108/0x1c4)
[<c0090ad0>] (SyS_delete_module) from [<c0010040>] (ret_fast_syscall+0x0/0x3c)
r5:7f64cd00 r4:00000001
Code: e52de004 e8bd4000 e1a05000 e1a04001 (e5907004)
---[ end trace 8152e492b3f02f66 ]---


I don't know why this kernel panic happened after I applied this patch.
But, if I added the following code in the mod_gadget.c, this issue disappeared:

@@ -682,7 +684,8 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_r
struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);

- usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
+ if (pipe)
+ usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
usbhsg_queue_pop(uep, ureq, -ECONNRESET);

return 0;

Best regards,
Yoshihiro Shimoda

2015-07-06 08:20:22

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v3] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Phil,

Thank you for the patch.

On Thursday 02 July 2015 11:26:33 Phil Edworthy wrote:
> These changes allow a PHY driver to trigger a VBUS interrupt and
> to provide the value of VBUS.
>
> Signed-off-by: Phil Edworthy <[email protected]>
>
> ---
> v3:
> - Changed how indirect vbus is plumbed in.
> - Removed unnecessary (void) on call to otg_set_peripheral.
> - Moved code that connects to bus through transceiver so it
> is before setting gpriv->driver.
>
> v2:
> - vbus variables changed from int to bool.
> - dev_info() changed to dev_err()
> ---
> drivers/usb/renesas_usbhs/common.c | 8 +++++--
> drivers/usb/renesas_usbhs/common.h | 2 ++
> drivers/usb/renesas_usbhs/mod_gadget.c | 38 +++++++++++++++++++++++++++++++
> 3 files changed, 46 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/renesas_usbhs/common.c
> b/drivers/usb/renesas_usbhs/common.c index 0f7e850..15e67d8 100644
> --- a/drivers/usb/renesas_usbhs/common.c
> +++ b/drivers/usb/renesas_usbhs/common.c
> @@ -379,7 +379,10 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
> /*
> * get vbus status from platform
> */
> - enable = usbhs_platform_call(priv, get_vbus, pdev);
> + if (priv->vbus_is_indirect)
> + enable = priv->vbus_indirect_value;
> + else
> + enable = usbhs_platform_call(priv, get_vbus, pdev);
>
> /*
> * get id from platform
> @@ -662,7 +665,8 @@ static int usbhs_probe(struct platform_device *pdev)
> pm_runtime_enable(&pdev->dev);
> if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
> usbhsc_power_ctrl(priv, 1);
> - usbhs_mod_autonomy_mode(priv);
> + if (!priv->vbus_is_indirect)

Isn't this racy ? The vbus_session operation is called by transceivers from
interrupt handlers or work queues. Do we have a guarantee that it will be
called at least once before this code is reached ? Please see below for a
possible way to fix this.

> + usbhs_mod_autonomy_mode(priv);
> }
>
> /*
> diff --git a/drivers/usb/renesas_usbhs/common.h
> b/drivers/usb/renesas_usbhs/common.h index 8c5fc12..478700c 100644
> --- a/drivers/usb/renesas_usbhs/common.h
> +++ b/drivers/usb/renesas_usbhs/common.h
> @@ -255,6 +255,8 @@ struct usbhs_priv {
> struct renesas_usbhs_driver_param dparam;
>
> struct delayed_work notify_hotplug_work;
> + bool vbus_is_indirect;
> + bool vbus_indirect_value;
> struct platform_device *pdev;
>
> struct extcon_dev *edev;
> diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..93ad4ea 100644
> --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> @@ -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,7 @@ struct usbhsg_gpriv {
> int uep_size;
>
> struct usb_gadget_driver *driver;
> + struct usb_phy *transceiver;
>
> u32 status;
> #define USBHSG_STATUS_STARTED (1 << 0)
> @@ -882,12 +884,25 @@ 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;
> + }
> + }
> +

How is this change related to the topic ? I'm not too familiar with this
driver so I might just have missed something, but then others could as well,
and the commit message could do with a bit more information.

> /* first hook up the driver ... */
> gpriv->driver = driver;
>
> @@ -900,6 +915,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 +966,27 @@ 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);
> +
> + priv->vbus_is_indirect = 1;

vbus_is_indirect is never reset to 0. Shouldn't you set it to 1 (or rather to
true) in usbhs_mod_gadget_probe() if an external transceiver is found ?

What would you think of implementing and wiring up the get_vbus operation in
usbhs_mod_gadget_probe() in the same way that usbhs_mod_autonomy_mode() does,
and return the value of vbus_indirect_value there ? You could then get rid of
the vbus_is_indirect field and move the vbus_indirect_value field to struct
usbhsg_gpriv, removing the need to modify drivers/usb/renesas_usbhs/common.c.
It should also solve the race condition mentioned above.

> + priv->vbus_indirect_value = !!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 +1028,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, "%s transceiver found\n",
> + gpriv->transceiver ? "" : "No");
> +
> /*
> * CAUTION
> *

--
Regards,

Laurent Pinchart

2015-07-07 08:59:25

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v3] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Shimoda-san,

On 06 July 2015 08:28, Shimoda-san wrote:
> Hi Phil-san,
>
> > Sent: Thursday, July 02, 2015 7:27 PM
> >
> > These changes allow a PHY driver to trigger a VBUS interrupt and
> > to provide the value of VBUS.
> >
> > Signed-off-by: Phil Edworthy <[email protected]>
>
> Thank you for the patch!
>
> However, if I tested this patch, a kernel panic happened when
> I did "rmmod g_mass_storage" on koelsch:
>
> root@192:~/usb# rmmod g_mass_storage
> Unable to handle kernel NULL pointer dereference at virtual address 00000004
> pgd = eebd4bc0
> [00000004] *pgd=00000000
> Internal error: Oops: 205 [#1] SMP ARM
> Modules linked in: g_mass_storage(-) usb_f_mass_storage libcomposite
> CPU: 0 PID: 2496 Comm: rmmod Not tainted 4.1.0-dirty #32
> Hardware name: Generic R8A7791 (Flattened Device Tree)
> task: eeb64ac0 ti: ee022000 task.ti: ee022000
> PC is at usbhs_pkt_pop+0x1c/0x100
> LR is at usbhsg_ep_dequeue+0x28/0x40
> pc : [<c036d934>] lr : [<c036e364>] psr: 20000013
> sp : ee023e70 ip : ee023e98 fp : ee023e94
> r10: 00000000 r9 : ee022000 r8 : c00101e4
> r7 : 00200200 r6 : 00100100 r5 : 00000000 r4 : eeb917f8
> r3 : c036e33c r2 : 00000041 r1 : eeb917f8 r0 : 00000000
> Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 30c5307d Table: 6ebd4bc0 DAC: fffffffd
> Process rmmod (pid: 2496, stack limit = 0xee022210)
> Stack: (0xee023e70 to 0xee024000)
> 3e60: ee1b1400 eeb917c0 00100100 00200200
> 3e80: c00101e4 ee022000 ee023eac ee023e98 c036e364 c036d924 eeb34180
> eeb341c0
> 3ea0: ee023ecc ee023eb0 bf002f20 c036e348 eeb34180 00000001 ee1b1800
> eeb341b8
> 3ec0: ee023eec ee023ed0 bf002fec bf002e5c ee181600 bf01d624 bed3ff0d
> 00000081
> 3ee0: ee023efc ee023ef0 bf003028 bf002f78 ee023f14 ee023f00 c036fb88
> bf003018
> 3f00: ee181600 bf01d624 ee023f2c ee023f18 c036fc10 c036fb34 bf01d694 7f64cd30
> 3f20: ee023f3c ee023f30 bf0013d0 c036fbbc ee023f4c ee023f40 bf01d26c bf0013c0
> 3f40: ee023fa4 ee023f50 c0090bd8 bf01d248 ee023f6c 616d5f67 735f7373
> 61726f74
> 3f60: 00006567 ee023f70 c00460f4 c052a8c0 c00101e4 ee022010 ee023fb0
> ee022000
> 3f80: ee023fac ee023f90 c00136c4 00046038 00000001 7f64cd00 00000000
> ee023fa8
> 3fa0: c0010040 c0090adc 00000001 7f64cd00 7f64cd30 00000800 ccd5c100 ccd5c100
> 3fc0: 00000001 7f64cd00 bed3ff0d 00000081 7f64c008 00000000 00000002 00000800
> 3fe0: bed3fe0c bed3fb98 b6eeb068 b6e4f05c 60000010 7f64cd30 00000000
> 00000000
> Backtrace:
> [<c036d918>] (usbhs_pkt_pop) from [<c036e364>]
> (usbhsg_ep_dequeue+0x28/0x40)
> r9:ee022000 r8:c00101e4 r7:00200200 r6:00100100 r5:eeb917c0 r4:ee1b1400
> [<c036e33c>] (usbhsg_ep_dequeue) from [<bf002f20>]
> (composite_dev_cleanup+0xd0/0x11c [libcomposite])
> r5:eeb341c0 r4:eeb34180
> [<bf002e50>] (composite_dev_cleanup [libcomposite]) from [<bf002fec>]
> (__composite_unbind+0x80/0xa0 [libcomposite])
> r7:eeb341b8 r6:ee1b1800 r5:00000001 r4:eeb34180
> [<bf002f6c>] (__composite_unbind [libcomposite]) from [<bf003028>]
> (composite_unbind+0x1c/0x20 [libcomposite])
> r7:00000081 r6:bed3ff0d r5:bf01d624 r4:ee181600
> [<bf00300c>] (composite_unbind [libcomposite]) from [<c036fb88>]
> (usb_gadget_remove_driver+0x60/0x88)
> [<c036fb28>] (usb_gadget_remove_driver) from [<c036fc10>]
> (usb_gadget_unregister_driver+0x60/0xa0)
> r5:bf01d624 r4:ee181600
> [<c036fbb0>] (usb_gadget_unregister_driver) from [<bf0013d0>]
> (usb_composite_unregister+0x1c/0x20 [libcomposite])
> r5:7f64cd30 r4:bf01d694
> [<bf0013b4>] (usb_composite_unregister [libcomposite]) from [<bf01d26c>]
> (msg_cleanup+0x30/0x3c [g_mass_storage])
> [<bf01d23c>] (msg_cleanup [g_mass_storage]) from [<c0090bd8>]
> (SyS_delete_module+0x108/0x1c4)
> [<c0090ad0>] (SyS_delete_module) from [<c0010040>]
> (ret_fast_syscall+0x0/0x3c)
> r5:7f64cd00 r4:00000001
> Code: e52de004 e8bd4000 e1a05000 e1a04001 (e5907004)
> ---[ end trace 8152e492b3f02f66 ]---
>
>
> I don't know why this kernel panic happened after I applied this patch.
> But, if I added the following code in the mod_gadget.c, this issue disappeared:
>
> @@ -682,7 +684,8 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct
> usb_r
> struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
> struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
>
> - usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
> + if (pipe)
> + usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
> usbhsg_queue_pop(uep, ureq, -ECONNRESET);
>
> return 0;

That's odd, I can't see how my patch causes this problem. Do you think
that there has always been a race problem here and my changes make this
happen?

> Best regards,
> Yoshihiro Shimoda
>

Best regards
Phil

2015-07-07 09:12:33

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v3] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Laurent,

On 06 July 2015 09:20, Laurent wrote:
> Hi Phil,
>
> Thank you for the patch.
Thanks for your review!

> On Thursday 02 July 2015 11:26:33 Phil Edworthy wrote:
> > These changes allow a PHY driver to trigger a VBUS interrupt and
> > to provide the value of VBUS.
> >
> > Signed-off-by: Phil Edworthy <[email protected]>
> >
> > ---
> > v3:
> > - Changed how indirect vbus is plumbed in.
> > - Removed unnecessary (void) on call to otg_set_peripheral.
> > - Moved code that connects to bus through transceiver so it
> > is before setting gpriv->driver.
> >
> > v2:
> > - vbus variables changed from int to bool.
> > - dev_info() changed to dev_err()
> > ---
> > drivers/usb/renesas_usbhs/common.c | 8 +++++--
> > drivers/usb/renesas_usbhs/common.h | 2 ++
> > drivers/usb/renesas_usbhs/mod_gadget.c | 38
> +++++++++++++++++++++++++++++++
> > 3 files changed, 46 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/usb/renesas_usbhs/common.c
> > b/drivers/usb/renesas_usbhs/common.c index 0f7e850..15e67d8 100644
> > --- a/drivers/usb/renesas_usbhs/common.c
> > +++ b/drivers/usb/renesas_usbhs/common.c
> > @@ -379,7 +379,10 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
> > /*
> > * get vbus status from platform
> > */
> > - enable = usbhs_platform_call(priv, get_vbus, pdev);
> > + if (priv->vbus_is_indirect)
> > + enable = priv->vbus_indirect_value;
> > + else
> > + enable = usbhs_platform_call(priv, get_vbus, pdev);
> >
> > /*
> > * get id from platform
> > @@ -662,7 +665,8 @@ static int usbhs_probe(struct platform_device *pdev)
> > pm_runtime_enable(&pdev->dev);
> > if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
> > usbhsc_power_ctrl(priv, 1);
> > - usbhs_mod_autonomy_mode(priv);
> > + if (!priv->vbus_is_indirect)
>
> Isn't this racy ? The vbus_session operation is called by transceivers from
> interrupt handlers or work queues. Do we have a guarantee that it will be
> called at least once before this code is reached ? Please see below for a
> possible way to fix this.
You are right, it is racy... :(

> > + usbhs_mod_autonomy_mode(priv);
> > }
> >
> > /*
> > diff --git a/drivers/usb/renesas_usbhs/common.h
> > b/drivers/usb/renesas_usbhs/common.h index 8c5fc12..478700c 100644
> > --- a/drivers/usb/renesas_usbhs/common.h
> > +++ b/drivers/usb/renesas_usbhs/common.h
> > @@ -255,6 +255,8 @@ struct usbhs_priv {
> > struct renesas_usbhs_driver_param dparam;
> >
> > struct delayed_work notify_hotplug_work;
> > + bool vbus_is_indirect;
> > + bool vbus_indirect_value;
> > struct platform_device *pdev;
> >
> > struct extcon_dev *edev;
> > diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> > b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..93ad4ea 100644
> > --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> > +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> > @@ -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,7 @@ struct usbhsg_gpriv {
> > int uep_size;
> >
> > struct usb_gadget_driver *driver;
> > + struct usb_phy *transceiver;
> >
> > u32 status;
> > #define USBHSG_STATUS_STARTED (1 << 0)
> > @@ -882,12 +884,25 @@ 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;
> > + }
> > + }
> > +
>
> How is this change related to the topic ? I'm not too familiar with this
> driver so I might just have missed something, but then others could as well,
> and the commit message could do with a bit more information.
I'm not sure what you mean, this code is needed to tell the phy driver
if it is in host or gadget mode. I would have thought this is clear as it calls
otg_set_peripheral.

> > /* first hook up the driver ... */
> > gpriv->driver = driver;
> >
> > @@ -900,6 +915,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 +966,27 @@ 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);
> > +
> > + priv->vbus_is_indirect = 1;
>
> vbus_is_indirect is never reset to 0. Shouldn't you set it to 1 (or rather to
> true) in usbhs_mod_gadget_probe() if an external transceiver is found ?
Yes, I see what you say.

> What would you think of implementing and wiring up the get_vbus operation in
> usbhs_mod_gadget_probe() in the same way that
> usbhs_mod_autonomy_mode() does,
> and return the value of vbus_indirect_value there ? You could then get rid of
> the vbus_is_indirect field and move the vbus_indirect_value field to struct
> usbhsg_gpriv, removing the need to modify
> drivers/usb/renesas_usbhs/common.c.
> It should also solve the race condition mentioned above.
Ok, I'll have a look at that.

> > + priv->vbus_indirect_value = !!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 +1028,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, "%s transceiver found\n",
> > + gpriv->transceiver ? "" : "No");
> > +
> > /*
> > * CAUTION
> > *
>
> --
> Regards,
>
> Laurent Pinchart

Thanks
Phil

2015-07-07 11:54:59

by Phil Edworthy

[permalink] [raw]
Subject: [PATCH v5] 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: Phil Edworthy <[email protected]>

---
v5:
- Avoid race when vbus_is_indirect may or may not be read
before the phy has called vbus_session. In doing so, the
changes have also been isolated to mod_gadget.c

v4:
- Use true/false with bool vars.
- Clean up "transceiver found" message.

v3:
- Changed how indirect vbus is plumbed in.
- Removed unnecessary (void) on call to otg_set_peripheral.
- Moved code that connects to bus through transceiver so it
is before setting gpriv->driver.

v2:
- vbus variables changed from int to bool.
- dev_info() changed to dev_err()
---
drivers/usb/renesas_usbhs/mod_gadget.c | 62 ++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)

diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index dc2aa32..19a22a3 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -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_indirect_value;

u32 status;
#define USBHSG_STATUS_STARTED (1 << 0)
@@ -873,6 +876,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
}

/*
+ * 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_indirect_value;
+}
+
+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_indirect_value = !!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
*
--
1.9.1

2015-07-07 23:08:06

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v5] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Phil,

Thank you for the patch.

On Tuesday 07 July 2015 12:52:43 Phil Edworthy wrote:
> These changes allow a PHY driver to trigger a VBUS interrupt and
> to provide the value of VBUS.
>
> Signed-off-by: Phil Edworthy <[email protected]>

This looks much better to me. I just have two comments, please see below.

> ---
> v5:
> - Avoid race when vbus_is_indirect may or may not be read
> before the phy has called vbus_session. In doing so, the
> changes have also been isolated to mod_gadget.c
>
> v4:
> - Use true/false with bool vars.
> - Clean up "transceiver found" message.
>
> v3:
> - Changed how indirect vbus is plumbed in.
> - Removed unnecessary (void) on call to otg_set_peripheral.
> - Moved code that connects to bus through transceiver so it
> is before setting gpriv->driver.
>
> v2:
> - vbus variables changed from int to bool.
> - dev_info() changed to dev_err()
> ---
> drivers/usb/renesas_usbhs/mod_gadget.c | 62 +++++++++++++++++++++++++++++++
> 1 file changed, 62 insertions(+)
>
> diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..19a22a3 100644
> --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> @@ -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_indirect_value;

How about naming this vbus_connected ? A boolean "value" doesn't mean much.

>
> u32 status;
> #define USBHSG_STATUS_STARTED (1 << 0)
> @@ -873,6 +876,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32
> status) }
>
> /*
> + * 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_indirect_value;
> +}
> +
> +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);

Given that the presence of an external PHY is known at probe time, couldn't
this call be moved to the probe function ? It would then probably conflict
with the usbhs_mod_autonomy_mode() call from usbhs_probe(), which would need
to be fixed.

> + }
> +
> /* 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_indirect_value = !!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
> *

--
Regards,

Laurent Pinchart

2015-07-08 08:09:15

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v5] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Laurent,

On 08 July 2015 00:08, Laurent wrote:
> Hi Phil,
>
> Thank you for the patch.
>
> On Tuesday 07 July 2015 12:52:43 Phil Edworthy wrote:
> > These changes allow a PHY driver to trigger a VBUS interrupt and
> > to provide the value of VBUS.
> >
> > Signed-off-by: Phil Edworthy <[email protected]>
>
> This looks much better to me. I just have two comments, please see below.
>
> > ---
> > v5:
> > - Avoid race when vbus_is_indirect may or may not be read
> > before the phy has called vbus_session. In doing so, the
> > changes have also been isolated to mod_gadget.c
> >
> > v4:
> > - Use true/false with bool vars.
> > - Clean up "transceiver found" message.
> >
> > v3:
> > - Changed how indirect vbus is plumbed in.
> > - Removed unnecessary (void) on call to otg_set_peripheral.
> > - Moved code that connects to bus through transceiver so it
> > is before setting gpriv->driver.
> >
> > v2:
> > - vbus variables changed from int to bool.
> > - dev_info() changed to dev_err()
> > ---
> > drivers/usb/renesas_usbhs/mod_gadget.c | 62
> +++++++++++++++++++++++++++++++
> > 1 file changed, 62 insertions(+)
> >
> > diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> > b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..19a22a3 100644
> > --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> > +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> > @@ -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_indirect_value;
>
> How about naming this vbus_connected ? A boolean "value" doesn't mean much.
Hmm, vbus_connected isn't right either. This variable directly maps to the vbus
signal, i.e. this variable is true when the signal is high. I'll change it to
vbus_active.

> >
> > u32 status;
> > #define USBHSG_STATUS_STARTED (1 << 0)
> > @@ -873,6 +876,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32
> > status) }
> >
> > /*
> > + * 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_indirect_value;
> > +}
> > +
> > +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);
>
> Given that the presence of an external PHY is known at probe time, couldn't
> this call be moved to the probe function ? It would then probably conflict
> with the usbhs_mod_autonomy_mode() call from usbhs_probe(), which would
> need to be fixed.
You could do this, but as you say it would conflict with usbhs_probe(). I can't
see a simple way to check for the external phy connection, so I would prefer to
keep it here.
Is that ok?

> > + }
> > +
> > /* 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_indirect_value = !!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
> > *
>
> --
> Regards,
>
> Laurent Pinchart

Thanks
Phil

2015-07-09 01:03:24

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v5] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Phil,

On Wednesday 08 July 2015 08:08:27 Phil Edworthy wrote:
> On 08 July 2015 00:08, Laurent wrote:
> > On Tuesday 07 July 2015 12:52:43 Phil Edworthy wrote:
> > > These changes allow a PHY driver to trigger a VBUS interrupt and
> > > to provide the value of VBUS.
> > >
> > > Signed-off-by: Phil Edworthy <[email protected]>
> >
> > This looks much better to me. I just have two comments, please see below.
> >
> > > ---
> > >
> > > v5:
> > > - Avoid race when vbus_is_indirect may or may not be read
> > >
> > > before the phy has called vbus_session. In doing so, the
> > > changes have also been isolated to mod_gadget.c
> > >
> > > v4:
> > > - Use true/false with bool vars.
> > > - Clean up "transceiver found" message.
> > >
> > > v3:
> > > - Changed how indirect vbus is plumbed in.
> > > - Removed unnecessary (void) on call to otg_set_peripheral.
> > > - Moved code that connects to bus through transceiver so it
> > >
> > > is before setting gpriv->driver.
> > >
> > > v2:
> > > - vbus variables changed from int to bool.
> > > - dev_info() changed to dev_err()
> > >
> > > ---
> > >
> > > drivers/usb/renesas_usbhs/mod_gadget.c | 62 +++++++++++++++++++++++++++
> > > 1 file changed, 62 insertions(+)
> > >
> > > diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> > > b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..19a22a3 100644
> > > --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> > > +++ b/drivers/usb/renesas_usbhs/mod_gadget.c

[snip]

> > > @@ -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);
> >
> > Given that the presence of an external PHY is known at probe time,
> > couldn't this call be moved to the probe function ? It would then probably
> > conflict with the usbhs_mod_autonomy_mode() call from usbhs_probe(), which
> > would need to be fixed.
>
> You could do this, but as you say it would conflict with usbhs_probe(). I
> can't see a simple way to check for the external phy connection, so I would
> prefer to keep it here.
> Is that ok?

I can live with that, but I can't help feeling that it's not the best
architecture. Coming to think about it, why do we get the transceiver (by
calling usb_get_phy) in the gadget code ? Isn't the transceiver shared between
host and peripheral modes ? Shouldn't it be handled by core code then ? I
might miss something as my knowledge of the USB subsystem isn't perfect.

If we decide to refactor the code it can be done in a follow-up patch, this
patch has been delayed for long enough.

> > > + }
> > > +
> > >
> > > /* first hook up the driver ... */
> > > gpriv->driver = driver;

--
Regards,

Laurent Pinchart

2015-07-13 15:23:13

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v5] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Laurent,

On 09 July 2015 02:03, Laurent wrote:
> Hi Phil,
>
> On Wednesday 08 July 2015 08:08:27 Phil Edworthy wrote:
> > On 08 July 2015 00:08, Laurent wrote:
> > > On Tuesday 07 July 2015 12:52:43 Phil Edworthy wrote:
> > > > These changes allow a PHY driver to trigger a VBUS interrupt and
> > > > to provide the value of VBUS.
> > > >
> > > > Signed-off-by: Phil Edworthy <[email protected]>
> > >
> > > This looks much better to me. I just have two comments, please see below.
> > >
> > > > ---
> > > >
> > > > v5:
> > > > - Avoid race when vbus_is_indirect may or may not be read
> > > >
> > > > before the phy has called vbus_session. In doing so, the
> > > > changes have also been isolated to mod_gadget.c
> > > >
> > > > v4:
> > > > - Use true/false with bool vars.
> > > > - Clean up "transceiver found" message.
> > > >
> > > > v3:
> > > > - Changed how indirect vbus is plumbed in.
> > > > - Removed unnecessary (void) on call to otg_set_peripheral.
> > > > - Moved code that connects to bus through transceiver so it
> > > >
> > > > is before setting gpriv->driver.
> > > >
> > > > v2:
> > > > - vbus variables changed from int to bool.
> > > > - dev_info() changed to dev_err()
> > > >
> > > > ---
> > > >
> > > > drivers/usb/renesas_usbhs/mod_gadget.c | 62
> +++++++++++++++++++++++++++
> > > > 1 file changed, 62 insertions(+)
> > > >
> > > > diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> > > > b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..19a22a3
> 100644
> > > > --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> > > > +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
>
> [snip]
>
> > > > @@ -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);
> > >
> > > Given that the presence of an external PHY is known at probe time,
> > > couldn't this call be moved to the probe function ? It would then probably
> > > conflict with the usbhs_mod_autonomy_mode() call from usbhs_probe(),
> which
> > > would need to be fixed.
> >
> > You could do this, but as you say it would conflict with usbhs_probe(). I
> > can't see a simple way to check for the external phy connection, so I would
> > prefer to keep it here.
> > Is that ok?
>
> I can live with that, but I can't help feeling that it's not the best
> architecture. Coming to think about it, why do we get the transceiver (by
> calling usb_get_phy) in the gadget code ? Isn't the transceiver shared between
> host and peripheral modes ? Shouldn't it be handled by core code then ? I
> might miss something as my knowledge of the USB subsystem isn't perfect.
I suspect your knowledge of it is much better than mine!


> If we decide to refactor the code it can be done in a follow-up patch, this
> patch has been delayed for long enough.
Ok, thanks. I'll fix the variable name and re-post.

> > > > + }
> > > > +
> > > >
> > > > /* first hook up the driver ... */
> > > > gpriv->driver = driver;
>
> --
> Regards,
>
> Laurent Pinchart

Thanks
Phil

2015-07-13 15:32:31

by Phil Edworthy

[permalink] [raw]
Subject: [PATCH v6] 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: Phil Edworthy <[email protected]>

---
v6:
- Rename vbus_indirect_value to vbus_active

v5:
- Avoid race when vbus_is_indirect may or may not be read
before the phy has called vbus_session. In doing so, the
changes have also been isolated to mod_gadget.c

v4:
- Use true/false with bool vars.
- Clean up "transceiver found" message.

v3:
- Changed how indirect vbus is plumbed in.
- Removed unnecessary (void) on call to otg_set_peripheral.
- Moved code that connects to bus through transceiver so it
is before setting gpriv->driver.

v2:
- vbus variables changed from int to bool.
- dev_info() changed to dev_err()

usb: renesas_usbhs: fixes
---
drivers/usb/renesas_usbhs/mod_gadget.c | 62 ++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)

diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index dc2aa32..54f916f 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -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)
@@ -873,6 +876,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
}

/*
+ * 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
*
--
1.9.1

2015-07-13 15:50:37

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v6] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Phil,

Thank you for the patch.

On Monday 13 July 2015 16:30:18 Phil Edworthy wrote:
> These changes allow a PHY driver to trigger a VBUS interrupt and
> to provide the value of VBUS.
>
> Signed-off-by: Phil Edworthy <[email protected]>

I don't see any further show stopper for this patch, so

Reviewed-by: Laurent Pinchart <[email protected]>

Do you plan to submit a patch to move PHY handling from gadget code to core
code ?

> ---
> v6:
> - Rename vbus_indirect_value to vbus_active
>
> v5:
> - Avoid race when vbus_is_indirect may or may not be read
> before the phy has called vbus_session. In doing so, the
> changes have also been isolated to mod_gadget.c
>
> v4:
> - Use true/false with bool vars.
> - Clean up "transceiver found" message.
>
> v3:
> - Changed how indirect vbus is plumbed in.
> - Removed unnecessary (void) on call to otg_set_peripheral.
> - Moved code that connects to bus through transceiver so it
> is before setting gpriv->driver.
>
> v2:
> - vbus variables changed from int to bool.
> - dev_info() changed to dev_err()
>
> usb: renesas_usbhs: fixes
> ---
> drivers/usb/renesas_usbhs/mod_gadget.c | 62 +++++++++++++++++++++++++++++++
> 1 file changed, 62 insertions(+)
>
> diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c
> b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..54f916f 100644
> --- a/drivers/usb/renesas_usbhs/mod_gadget.c
> +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
> @@ -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)
> @@ -873,6 +876,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32
> status) }
>
> /*
> + * 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
> *

--
Regards,

Laurent Pinchart

2015-07-13 16:15:57

by Phil Edworthy

[permalink] [raw]
Subject: RE: [PATCH v6] usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS

Hi Laurent,

On 13 July 2015 16:51, Laurent wrote:
> Hi Phil,
>
> Thank you for the patch.
>
> On Monday 13 July 2015 16:30:18 Phil Edworthy wrote:
> > These changes allow a PHY driver to trigger a VBUS interrupt and
> > to provide the value of VBUS.
> >
> > Signed-off-by: Phil Edworthy <[email protected]>
>
> I don't see any further show stopper for this patch, so
>
> Reviewed-by: Laurent Pinchart <[email protected]>
>
> Do you plan to submit a patch to move PHY handling from gadget code to core
> code ?
Not at the moment... I am concentrating on the usb PHY driver and max3355
extcon driver.

<snip>

Thanks
Phil