diff mbox

[1/2] gpio-vbus: support disabling D+ pullup on suspend

Message ID 1308745217-10883-1-git-send-email-dbaryshkov@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dmitry Baryshkov June 22, 2011, 12:20 p.m. UTC
Some platforms would like to disable D+ pullup on suspend, to drain as
low power, as possible. E.g. this was requested by mioa701 board
maintainers.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/usb/otg/gpio_vbus.c   |   32 ++++++++++++++++++++++++++++++++
 include/linux/usb/gpio_vbus.h |    1 +
 2 files changed, 33 insertions(+), 0 deletions(-)

Comments

Felipe Balbi June 22, 2011, 1:23 p.m. UTC | #1
Hi,

On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
> Some platforms would like to disable D+ pullup on suspend, to drain as
> low power, as possible. E.g. this was requested by mioa701 board
> maintainers.

I think this makes sense to many platforms, but by doing so, you would
loose connection to the Host PC, so you need to make sure your device
isn't been used before you go down this road.

> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> ---
>  drivers/usb/otg/gpio_vbus.c   |   32 ++++++++++++++++++++++++++++++++
>  include/linux/usb/gpio_vbus.h |    1 +
>  2 files changed, 33 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
> index 52733d9..44527bd 100644
> --- a/drivers/usb/otg/gpio_vbus.c
> +++ b/drivers/usb/otg/gpio_vbus.c
> @@ -327,6 +327,34 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_PM
> +static int gpio_vbus_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
> +	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
> +
> +	if (gpio_vbus->otg.gadget && pdata->disconnect_on_suspend) {
> +		/* optionally disable D+ pullup */
> +		if (gpio_is_valid(pdata->gpio_pullup))
> +			gpio_set_value(pdata->gpio_pullup,
> +					pdata->gpio_pullup_inverted);
> +
> +		set_vbus_draw(gpio_vbus, 0);
> +	}
> +	return 0;
> +}
> +
> +static int gpio_vbus_resume(struct platform_device *pdev)
> +{
> +	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
> +
> +	if (gpio_vbus->otg.gadget)
> +		schedule_work(&gpio_vbus->work);
> +
> +	return 0;
> +}

actually, the correct way would be to use dev_pm_ops.

> +#endif
> +
>  /* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
>  
>  MODULE_ALIAS("platform:gpio-vbus");
> @@ -337,6 +365,10 @@ static struct platform_driver gpio_vbus_driver = {
>  		.owner = THIS_MODULE,
>  	},
>  	.remove  = __exit_p(gpio_vbus_remove),
> +#ifdef CONFIG_PM
> +	.suspend	= gpio_vbus_suspend,
> +	.resume		= gpio_vbus_resume
> +#endif

also, avoid the ifdef on the driver structure.
Dmitry Baryshkov June 22, 2011, 1:52 p.m. UTC | #2
On 6/22/11, Felipe Balbi <balbi@ti.com> wrote:
> Hi,
>
> On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
>> Some platforms would like to disable D+ pullup on suspend, to drain as
>> low power, as possible. E.g. this was requested by mioa701 board
>> maintainers.
>
> I think this makes sense to many platforms, but by doing so, you would
> loose connection to the Host PC, so you need to make sure your device
> isn't been used before you go down this road.

I've thought about this. Should UDC driver should somehow call into OTG
layer on suspend? My understanding is that otg_set_suspend isn't the call
that should be done here, is it true?

My idea was that board can ask for D+ disabling, knowing itself the behaviour
of the platform driver on suspend (e.g. PXA27x does disable UDC on suspend,
but I dunno what effect this will cause on Host PC).

>> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
>> ---
>>  drivers/usb/otg/gpio_vbus.c   |   32 ++++++++++++++++++++++++++++++++
>>  include/linux/usb/gpio_vbus.h |    1 +
>>  2 files changed, 33 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
>> index 52733d9..44527bd 100644
>> --- a/drivers/usb/otg/gpio_vbus.c
>> +++ b/drivers/usb/otg/gpio_vbus.c
>> @@ -327,6 +327,34 @@ static int __exit gpio_vbus_remove(struct
>> platform_device *pdev)
>>  	return 0;
>>  }
>>
>> +#ifdef CONFIG_PM
>> +static int gpio_vbus_suspend(struct platform_device *pdev, pm_message_t
>> state)
>> +{
>> +	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
>> +	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
>> +
>> +	if (gpio_vbus->otg.gadget && pdata->disconnect_on_suspend) {
>> +		/* optionally disable D+ pullup */
>> +		if (gpio_is_valid(pdata->gpio_pullup))
>> +			gpio_set_value(pdata->gpio_pullup,
>> +					pdata->gpio_pullup_inverted);
>> +
>> +		set_vbus_draw(gpio_vbus, 0);
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int gpio_vbus_resume(struct platform_device *pdev)
>> +{
>> +	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
>> +
>> +	if (gpio_vbus->otg.gadget)
>> +		schedule_work(&gpio_vbus->work);
>> +
>> +	return 0;
>> +}
>
> actually, the correct way would be to use dev_pm_ops.

Could I use SIMPLE_DEV_PM_OPS here?

>
>> +#endif
>> +
>>  /* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
>>
>>  MODULE_ALIAS("platform:gpio-vbus");
>> @@ -337,6 +365,10 @@ static struct platform_driver gpio_vbus_driver = {
>>  		.owner = THIS_MODULE,
>>  	},
>>  	.remove  = __exit_p(gpio_vbus_remove),
>> +#ifdef CONFIG_PM
>> +	.suspend	= gpio_vbus_suspend,
>> +	.resume		= gpio_vbus_resume
>> +#endif
>
> also, avoid the ifdef on the driver structure.

Ack. Was just C&P from gpio-vbus, but it's not an excuse
to follow bad style.
Felipe Balbi June 22, 2011, 2:01 p.m. UTC | #3
Hi,

On Wed, Jun 22, 2011 at 05:52:18PM +0400, Dmitry Eremin-Solenikov wrote:
> On 6/22/11, Felipe Balbi <balbi@ti.com> wrote:
> > Hi,
> >
> > On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
> >> Some platforms would like to disable D+ pullup on suspend, to drain as
> >> low power, as possible. E.g. this was requested by mioa701 board
> >> maintainers.
> >
> > I think this makes sense to many platforms, but by doing so, you would
> > loose connection to the Host PC, so you need to make sure your device
> > isn't been used before you go down this road.
> 
> I've thought about this. Should UDC driver should somehow call into OTG
> layer on suspend? My understanding is that otg_set_suspend isn't the call
> that should be done here, is it true?
> 
> My idea was that board can ask for D+ disabling, knowing itself the behaviour
> of the platform driver on suspend (e.g. PXA27x does disable UDC on suspend,
> but I dunno what effect this will cause on Host PC).

Host PC will only see the device disconnecting. So, what happens if the
user has mounted file systems when you decide to go into suspend ?

> 
> >> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> >> ---
> >>  drivers/usb/otg/gpio_vbus.c   |   32 ++++++++++++++++++++++++++++++++
> >>  include/linux/usb/gpio_vbus.h |    1 +
> >>  2 files changed, 33 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
> >> index 52733d9..44527bd 100644
> >> --- a/drivers/usb/otg/gpio_vbus.c
> >> +++ b/drivers/usb/otg/gpio_vbus.c
> >> @@ -327,6 +327,34 @@ static int __exit gpio_vbus_remove(struct
> >> platform_device *pdev)
> >>  	return 0;
> >>  }
> >>
> >> +#ifdef CONFIG_PM
> >> +static int gpio_vbus_suspend(struct platform_device *pdev, pm_message_t
> >> state)
> >> +{
> >> +	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
> >> +	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
> >> +
> >> +	if (gpio_vbus->otg.gadget && pdata->disconnect_on_suspend) {
> >> +		/* optionally disable D+ pullup */
> >> +		if (gpio_is_valid(pdata->gpio_pullup))
> >> +			gpio_set_value(pdata->gpio_pullup,
> >> +					pdata->gpio_pullup_inverted);
> >> +
> >> +		set_vbus_draw(gpio_vbus, 0);
> >> +	}
> >> +	return 0;
> >> +}
> >> +
> >> +static int gpio_vbus_resume(struct platform_device *pdev)
> >> +{
> >> +	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
> >> +
> >> +	if (gpio_vbus->otg.gadget)
> >> +		schedule_work(&gpio_vbus->work);
> >> +
> >> +	return 0;
> >> +}
> >
> > actually, the correct way would be to use dev_pm_ops.
> 
> Could I use SIMPLE_DEV_PM_OPS here?

for sure ;-)

> >> +#endif
> >> +
> >>  /* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
> >>
> >>  MODULE_ALIAS("platform:gpio-vbus");
> >> @@ -337,6 +365,10 @@ static struct platform_driver gpio_vbus_driver = {
> >>  		.owner = THIS_MODULE,
> >>  	},
> >>  	.remove  = __exit_p(gpio_vbus_remove),
> >> +#ifdef CONFIG_PM
> >> +	.suspend	= gpio_vbus_suspend,
> >> +	.resume		= gpio_vbus_resume
> >> +#endif
> >
> > also, avoid the ifdef on the driver structure.
> 
> Ack. Was just C&P from gpio-vbus, but it's not an excuse
> to follow bad style.

see what e.g the musb driver does to avoid the ifdef
(drivers/usb/musb/musb_core.c)
Dmitry Baryshkov June 22, 2011, 2:15 p.m. UTC | #4
On 6/22/11, Felipe Balbi <balbi@ti.com> wrote:
> Hi,
>
> On Wed, Jun 22, 2011 at 05:52:18PM +0400, Dmitry Eremin-Solenikov wrote:
>> On 6/22/11, Felipe Balbi <balbi@ti.com> wrote:
>> > Hi,
>> >
>> > On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
>> >> Some platforms would like to disable D+ pullup on suspend, to drain as
>> >> low power, as possible. E.g. this was requested by mioa701 board
>> >> maintainers.
>> >
>> > I think this makes sense to many platforms, but by doing so, you would
>> > loose connection to the Host PC, so you need to make sure your device
>> > isn't been used before you go down this road.
>>
>> I've thought about this. Should UDC driver should somehow call into OTG
>> layer on suspend? My understanding is that otg_set_suspend isn't the call
>> that should be done here, is it true?
>>
>> My idea was that board can ask for D+ disabling, knowing itself the
>> behaviour
>> of the platform driver on suspend (e.g. PXA27x does disable UDC on
>> suspend,
>> but I dunno what effect this will cause on Host PC).
>
> Host PC will only see the device disconnecting. So, what happens if the
> user has mounted file systems when you decide to go into suspend ?

What happens if user has mounted filesystems when I decide to pull out
the cable?
I agree with you generally, but I'd like to hear any suggestions.
Felipe Balbi June 22, 2011, 2:20 p.m. UTC | #5
Hi,

On Wed, Jun 22, 2011 at 06:15:17PM +0400, Dmitry Eremin-Solenikov wrote:
> On 6/22/11, Felipe Balbi <balbi@ti.com> wrote:
> > Hi,
> >
> > On Wed, Jun 22, 2011 at 05:52:18PM +0400, Dmitry Eremin-Solenikov wrote:
> >> On 6/22/11, Felipe Balbi <balbi@ti.com> wrote:
> >> > Hi,
> >> >
> >> > On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
> >> >> Some platforms would like to disable D+ pullup on suspend, to drain as
> >> >> low power, as possible. E.g. this was requested by mioa701 board
> >> >> maintainers.
> >> >
> >> > I think this makes sense to many platforms, but by doing so, you would
> >> > loose connection to the Host PC, so you need to make sure your device
> >> > isn't been used before you go down this road.
> >>
> >> I've thought about this. Should UDC driver should somehow call into OTG
> >> layer on suspend? My understanding is that otg_set_suspend isn't the call
> >> that should be done here, is it true?
> >>
> >> My idea was that board can ask for D+ disabling, knowing itself the
> >> behaviour
> >> of the platform driver on suspend (e.g. PXA27x does disable UDC on
> >> suspend,
> >> but I dunno what effect this will cause on Host PC).
> >
> > Host PC will only see the device disconnecting. So, what happens if the
> > user has mounted file systems when you decide to go into suspend ?
> 
> What happens if user has mounted filesystems when I decide to pull out
> the cable?

for starters you could have filesystem corruption. In short, the best
way would be to return -EBUSY in your suspend if the cable is still
attached.

You could use osme VBUS IRQ to toggle a driver flag which, if true,
would return -EBUSY on suspend().

> I agree with you generally, but I'd like to hear any suggestions.

I'm not sure how to solve this, but OTOH the original code already did
this, just on a different way, right ?
Dmitry Baryshkov June 22, 2011, 2:26 p.m. UTC | #6
On 22.06.2011 18:20, Felipe Balbi wrote:
> Hi,
>
> On Wed, Jun 22, 2011 at 06:15:17PM +0400, Dmitry Eremin-Solenikov wrote:
>> On 6/22/11, Felipe Balbi<balbi@ti.com>  wrote:
>>> Hi,
>>>
>>> On Wed, Jun 22, 2011 at 05:52:18PM +0400, Dmitry Eremin-Solenikov wrote:
>>>> On 6/22/11, Felipe Balbi<balbi@ti.com>  wrote:
>>>>> Hi,
>>>>>
>>>>> On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
>>>>>> Some platforms would like to disable D+ pullup on suspend, to drain as
>>>>>> low power, as possible. E.g. this was requested by mioa701 board
>>>>>> maintainers.
>>>>>
>>>>> I think this makes sense to many platforms, but by doing so, you would
>>>>> loose connection to the Host PC, so you need to make sure your device
>>>>> isn't been used before you go down this road.
>>>>
>>>> I've thought about this. Should UDC driver should somehow call into OTG
>>>> layer on suspend? My understanding is that otg_set_suspend isn't the call
>>>> that should be done here, is it true?
>>>>
>>>> My idea was that board can ask for D+ disabling, knowing itself the
>>>> behaviour
>>>> of the platform driver on suspend (e.g. PXA27x does disable UDC on
>>>> suspend,
>>>> but I dunno what effect this will cause on Host PC).
>>>
>>> Host PC will only see the device disconnecting. So, what happens if the
>>> user has mounted file systems when you decide to go into suspend ?
>>
>> What happens if user has mounted filesystems when I decide to pull out
>> the cable?
>
> for starters you could have filesystem corruption. In short, the best
> way would be to return -EBUSY in your suspend if the cable is still
> attached.

That was a rhetorical question. Basically there are plenty of situations
and cases (cable is not attached; cable attached, but no gadget driver;
cable attached, block gadget driver, but filesystems aren't mounted; 
cable attached, block gadget driver , filesystem mounted, but host
is also suspended, etc.).

> You could use osme VBUS IRQ to toggle a driver flag which, if true,
> would return -EBUSY on suspend().

I'm more and more thinking that this handling this -EBUSY isn't a task 
of gpio-vbus, but rather of some higher level driver. I'd assume that
if I hit this point, all previous drivers (which depend on this 
transceiver, so registered later) permit suspending at this moment,
so everything is OK :)

>
>> I agree with you generally, but I'd like to hear any suggestions.
>
> I'm not sure how to solve this, but OTOH the original code already did
> this, just on a different way, right ?

Yes. pxa27x udc driver disables D+ pullup on suspend and that's the 
behaviour asked from me by Robert Jarzmik in comments to first cleanup 
patch serie for pxa27x UDC driver.
Alan Stern June 22, 2011, 2:30 p.m. UTC | #7
On Wed, 22 Jun 2011, Felipe Balbi wrote:

> Hi,
> 
> On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
> > Some platforms would like to disable D+ pullup on suspend, to drain as
> > low power, as possible. E.g. this was requested by mioa701 board
> > maintainers.
> 
> I think this makes sense to many platforms, but by doing so, you would
> loose connection to the Host PC, so you need to make sure your device
> isn't been used before you go down this road.

In fact, something like this is _necessary_ for all UDC/PHY drivers
unless the device can guarantee that it will automatically wake up from
suspend in time to service a USB packet (note that the window for
responding to a packet is only a few microseconds).  Otherwise the
device would appear to the host to be unresponsive and broken -- better
to do a clean disconnect.

If suspending the device while it is in use would cause problems ...  
then don't suspend it when it is in use!

Alan Stern
Felipe Balbi June 22, 2011, 2:30 p.m. UTC | #8
Hi,

On Wed, Jun 22, 2011 at 06:26:36PM +0400, Dmitry Eremin-Solenikov wrote:
> >You could use osme VBUS IRQ to toggle a driver flag which, if true,
> >would return -EBUSY on suspend().
> 
> I'm more and more thinking that this handling this -EBUSY isn't a
> task of gpio-vbus, but rather of some higher level driver. I'd assume
> that
> if I hit this point, all previous drivers (which depend on this
> transceiver, so registered later) permit suspending at this moment,
> so everything is OK :)

the thing is that today we don't have the "higher level driver" see that
the OTG/transceiver framework (if you can call it a framework) is just a
static global pointer which people set. So, you need to have
per-transceiver solutions, unfortunately :-(

> >>I agree with you generally, but I'd like to hear any suggestions.
> >
> >I'm not sure how to solve this, but OTOH the original code already did
> >this, just on a different way, right ?
> 
> Yes. pxa27x udc driver disables D+ pullup on suspend and that's the
> behaviour asked from me by Robert Jarzmik in comments to first
> cleanup patch serie for pxa27x UDC driver.

ok... so, go ahead but keep in mind you could end up in a bad situation
;-)
Felipe Balbi June 22, 2011, 2:32 p.m. UTC | #9
Hi,

On Wed, Jun 22, 2011 at 10:30:18AM -0400, Alan Stern wrote:
> On Wed, 22 Jun 2011, Felipe Balbi wrote:
> 
> > Hi,
> > 
> > On Wed, Jun 22, 2011 at 04:20:16PM +0400, Dmitry Eremin-Solenikov wrote:
> > > Some platforms would like to disable D+ pullup on suspend, to drain as
> > > low power, as possible. E.g. this was requested by mioa701 board
> > > maintainers.
> > 
> > I think this makes sense to many platforms, but by doing so, you would
> > loose connection to the Host PC, so you need to make sure your device
> > isn't been used before you go down this road.
> 
> In fact, something like this is _necessary_ for all UDC/PHY drivers
> unless the device can guarantee that it will automatically wake up from
> suspend in time to service a USB packet (note that the window for
> responding to a packet is only a few microseconds).  Otherwise the
> device would appear to the host to be unresponsive and broken -- better
> to do a clean disconnect.
> 
> If suspending the device while it is in use would cause problems ...  
> then don't suspend it when it is in use!

I second your thoughts, but today we don't have enough infrastructure to
communicate between PHY and Link, so a clean solution isn't possible,
right ?

Should we block this patch due to that ?
Alan Stern June 22, 2011, 3:02 p.m. UTC | #10
On Wed, 22 Jun 2011, Felipe Balbi wrote:

> > In fact, something like this is _necessary_ for all UDC/PHY drivers
> > unless the device can guarantee that it will automatically wake up from
> > suspend in time to service a USB packet (note that the window for
> > responding to a packet is only a few microseconds).  Otherwise the
> > device would appear to the host to be unresponsive and broken -- better
> > to do a clean disconnect.
> > 
> > If suspending the device while it is in use would cause problems ...  
> > then don't suspend it when it is in use!
> 
> I second your thoughts, but today we don't have enough infrastructure to
> communicate between PHY and Link, so a clean solution isn't possible,
> right ?
> 
> Should we block this patch due to that ?

No, the patch is appropriate.

We don't need better communication.  If g_mass_storage (for example)  
knows that the device is in use, it can block suspends by returning
-EBUSY from its own suspend callback.  The UDC driver doesn't need to
worry about these matters; it should assume that such things have
already been handled elsewhere.  That's what Dmitry meant when he was
talking about a "higher level driver" -- maybe "lower level" would have
been a better choice of words.  :-)

Until recently, ordering of the suspend callbacks didn't present any 
problem.  The gadget device was a child of the UDC device and therefore 
its suspend callback would always be invoked first.

With the new UDC framework, I don't know if this is true any more.  
It's something to consider.

Alan Stern
Felipe Balbi June 22, 2011, 3:19 p.m. UTC | #11
Hi,

On Wed, Jun 22, 2011 at 11:02:27AM -0400, Alan Stern wrote:
> On Wed, 22 Jun 2011, Felipe Balbi wrote:
> 
> > > In fact, something like this is _necessary_ for all UDC/PHY drivers
> > > unless the device can guarantee that it will automatically wake up from
> > > suspend in time to service a USB packet (note that the window for
> > > responding to a packet is only a few microseconds).  Otherwise the
> > > device would appear to the host to be unresponsive and broken -- better
> > > to do a clean disconnect.
> > > 
> > > If suspending the device while it is in use would cause problems ...  
> > > then don't suspend it when it is in use!
> > 
> > I second your thoughts, but today we don't have enough infrastructure to
> > communicate between PHY and Link, so a clean solution isn't possible,
> > right ?
> > 
> > Should we block this patch due to that ?
> 
> No, the patch is appropriate.
> 
> We don't need better communication.  If g_mass_storage (for example)  
> knows that the device is in use, it can block suspends by returning
> -EBUSY from its own suspend callback.  The UDC driver doesn't need to
> worry about these matters; it should assume that such things have
> already been handled elsewhere.  That's what Dmitry meant when he was
> talking about a "higher level driver" -- maybe "lower level" would have
> been a better choice of words.  :-)
> 
> Until recently, ordering of the suspend callbacks didn't present any 
> problem.  The gadget device was a child of the UDC device and therefore 
> its suspend callback would always be invoked first.
> 
> With the new UDC framework, I don't know if this is true any more.  
> It's something to consider.

it's still true, but with one extra device in the middle. e.g.:
musb is parent to udc-core which is parent to g_zero.
Robert Jarzmik June 25, 2011, 9:26 a.m. UTC | #12
On 06/22/2011 05:19 PM, Felipe Balbi wrote:
> Hi,
>
> On Wed, Jun 22, 2011 at 11:02:27AM -0400, Alan Stern wrote:
>> No, the patch is appropriate.
Indeed.
>>
>> We don't need better communication.  If g_mass_storage (for example)
>> knows that the device is in use, it can block suspends by returning
>> -EBUSY from its own suspend callback.  The UDC driver doesn't need to
>> worry about these matters; it should assume that such things have
>> already been handled elsewhere.  That's what Dmitry meant when he was
>> talking about a "higher level driver" -- maybe "lower level" would have
>> been a better choice of words.  :-)
The suspend at driver level should not care about filesystem in use, etc 
... A disconnected cable cannot be prevented by the kernel, and the 
effect in fine is the same as the suspend.

>> Until recently, ordering of the suspend callbacks didn't present any
>> problem.  The gadget device was a child of the UDC device and therefore
>> its suspend callback would always be invoked first.
>>
>> With the new UDC framework, I don't know if this is true any more.
>> It's something to consider.
That true also for the UDC driver, which should be suspended before the 
transciever, so that it can complete its shutdown properly.
That's what bothers me with the patch.

And we should not confuse the 2 suspends :
  (1) driver suspend, which happens at suspendToRam or suspendToDisk 
(the one we're discussing here)
  (2) USB suspend (which if I remember correctly is a special USB 
command while the USB bus remains powered).

The order of suspend in (1) requires :
  - gadget (gzero, gether, ...) suspended first
  - UDC suspended second
  - transceiver suspended last

The order of suspend in (2) doesn't require anything AFAIR.

For order in (1) :
  - gadget before UDC should be enforced by the framework, as the UDC 
usb_gadget_probe_driver() method calls device_add() on the gadget<
  - UDC before transceiver is enforced in some drivers by directly 
manipulating the gpio line.

So Dimitry, do you have an idea as how to guarantee order of suspend in 
(1), between UDC driver and gpio_vbus ? Maybe an otg_*() call would do 
the trick ?

Cheers.

--
Robert
Dmitry Baryshkov June 25, 2011, 10:33 a.m. UTC | #13
On 6/25/11, Robert Jarzmik <robert.jarzmik@free.fr> wrote:
> On 06/22/2011 05:19 PM, Felipe Balbi wrote:
>> On Wed, Jun 22, 2011 at 11:02:27AM -0400, Alan Stern wrote:
>>> Until recently, ordering of the suspend callbacks didn't present any
>>> problem.  The gadget device was a child of the UDC device and therefore
>>> its suspend callback would always be invoked first.
>>>
>>> With the new UDC framework, I don't know if this is true any more.
>>> It's something to consider.
> That true also for the UDC driver, which should be suspended before the
> transciever, so that it can complete its shutdown properly.
> That's what bothers me with the patch.
>
> And we should not confuse the 2 suspends :
>   (1) driver suspend, which happens at suspendToRam or suspendToDisk
> (the one we're discussing here)
>   (2) USB suspend (which if I remember correctly is a special USB
> command while the USB bus remains powered).
>
> The order of suspend in (1) requires :
>   - gadget (gzero, gether, ...) suspended first
>   - UDC suspended second
>   - transceiver suspended last
>
> The order of suspend in (2) doesn't require anything AFAIR.
>
> For order in (1) :
>   - gadget before UDC should be enforced by the framework, as the UDC
> usb_gadget_probe_driver() method calls device_add() on the gadget<
>   - UDC before transceiver is enforced in some drivers by directly
> manipulating the gpio line.
>
> So Dimitry, do you have an idea as how to guarantee order of suspend in
> (1), between UDC driver and gpio_vbus ? Maybe an otg_*() call would do
> the trick ?

That is simple: UDC driver acquires transceiver via otg_*() calls, so
transceiver
is already registered at the point of probing UDC. I'll check the order of calls
during suspend though.
Alan Stern June 25, 2011, 12:02 p.m. UTC | #14
On Sat, 25 Jun 2011, Robert Jarzmik wrote:

> On 06/22/2011 05:19 PM, Felipe Balbi wrote:
> > Hi,
> >
> > On Wed, Jun 22, 2011 at 11:02:27AM -0400, Alan Stern wrote:
> >> No, the patch is appropriate.
> Indeed.
> >>
> >> We don't need better communication.  If g_mass_storage (for example)
> >> knows that the device is in use, it can block suspends by returning
> >> -EBUSY from its own suspend callback.  The UDC driver doesn't need to
> >> worry about these matters; it should assume that such things have
> >> already been handled elsewhere.  That's what Dmitry meant when he was
> >> talking about a "higher level driver" -- maybe "lower level" would have
> >> been a better choice of words.  :-)
> The suspend at driver level should not care about filesystem in use, etc 
> ... A disconnected cable cannot be prevented by the kernel, and the 
> effect in fine is the same as the suspend.

This is a little ironic, because the mass-storage gadget driver has no
idea whether a filesystem is in use or not.  All it knows is whether it
is currently connected to a host.  Besides, it's questionable whether
the gadget driver should prevent the gadget from suspending.  This is a
policy matter which must be decided by the user, not by the kernel.

Nevertheless...  The fact that the kernel can do nothing about a
disconnected cable shouldn't stop us from handling system sleep
correctly.  After all, the kernel _can_ do something about that.

Alan Stern
Robert Jarzmik June 27, 2011, 8:39 p.m. UTC | #15
On 06/25/2011 02:02 PM, Alan Stern wrote:
> Nevertheless...  The fact that the kernel can do nothing about a
> disconnected cable shouldn't stop us from handling system sleep
> correctly.  After all, the kernel _can_ do something about that.

Well, it depends of which level of driver we speek about.
I was speeking about UDC driver, ie. a hardware driver. My point was 
that the hardware driver should only care about the hardware register 
manipulations, and check their success. If they succeed, then it should 
suspend itself without care of filesystem not in sync.

I didn't meant that the filesystem driver shouldn't care about the 
suspend, or even the mass-storage gadget. I don't have a strong opinion 
on these higher levels. The question if the kernel can do something 
about it is much more complicated :
  - should userspace sync/umount and check filesystem before suspending 
(as umount usb storage before suspending)
  - should the kernel block a suspend because a usb key was "forgotten" 
in an USB slot ?

For these questions, I'll let others battle. For the hardware related 
drivers, I'm pretty convinced all they should care about is the success 
or failure of hardware suspend manipulation, and the correct suspend order.

Cheers.

--
Robert
Peter Chen June 28, 2011, 2:41 a.m. UTC | #16
On Sat, Jun 25, 2011 at 11:26:09AM +0200, Robert Jarzmik wrote:
> On 06/22/2011 05:19 PM, Felipe Balbi wrote:
> >Hi,
> >
> >On Wed, Jun 22, 2011 at 11:02:27AM -0400, Alan Stern wrote:
> >>No, the patch is appropriate.
> Indeed.
> >>
> >>We don't need better communication.  If g_mass_storage (for example)
> >>knows that the device is in use, it can block suspends by returning
> >>-EBUSY from its own suspend callback.  The UDC driver doesn't need to
> >>worry about these matters; it should assume that such things have
> >>already been handled elsewhere.  That's what Dmitry meant when he was
> >>talking about a "higher level driver" -- maybe "lower level" would have
> >>been a better choice of words.  :-)
> The suspend at driver level should not care about filesystem in use,
> etc ... A disconnected cable cannot be prevented by the kernel, and
> the effect in fine is the same as the suspend.
> 
> >>Until recently, ordering of the suspend callbacks didn't present any
> >>problem.  The gadget device was a child of the UDC device and therefore
> >>its suspend callback would always be invoked first.
> >>
> >>With the new UDC framework, I don't know if this is true any more.
> >>It's something to consider.
> That true also for the UDC driver, which should be suspended before
> the transciever, so that it can complete its shutdown properly.
> That's what bothers me with the patch.
> 
> And we should not confuse the 2 suspends :
>  (1) driver suspend, which happens at suspendToRam or suspendToDisk
> (the one we're discussing here)
I think Dmitry's patch is for this system suspend, and less power consumption
is very important for system design, esp for embedded device.
>  (2) USB suspend (which if I remember correctly is a special USB
> command while the USB bus remains powered).
This suspend is USB suspend in USB 2.0 spec, it is usually triggered by
Usb controller after bus idle 3ms. It should not disable D+ pull-up, or
the bus will not be J, and the host will think the device has disconnected.
> 
> The order of suspend in (1) requires :
>  - gadget (gzero, gether, ...) suspended first
>  - UDC suspended second
>  - transceiver suspended last
> 
> The order of suspend in (2) doesn't require anything AFAIR.
> 
> For order in (1) :
>  - gadget before UDC should be enforced by the framework, as the UDC
> usb_gadget_probe_driver() method calls device_add() on the gadget<
>  - UDC before transceiver is enforced in some drivers by directly
> manipulating the gpio line.
> 
> So Dimitry, do you have an idea as how to guarantee order of suspend
> in (1), between UDC driver and gpio_vbus ? Maybe an otg_*() call
> would do the trick ?
> 
> Cheers.
> 
> --
> Robert
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
diff mbox

Patch

diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index 52733d9..44527bd 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -327,6 +327,34 @@  static int __exit gpio_vbus_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int gpio_vbus_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
+
+	if (gpio_vbus->otg.gadget && pdata->disconnect_on_suspend) {
+		/* optionally disable D+ pullup */
+		if (gpio_is_valid(pdata->gpio_pullup))
+			gpio_set_value(pdata->gpio_pullup,
+					pdata->gpio_pullup_inverted);
+
+		set_vbus_draw(gpio_vbus, 0);
+	}
+	return 0;
+}
+
+static int gpio_vbus_resume(struct platform_device *pdev)
+{
+	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+
+	if (gpio_vbus->otg.gadget)
+		schedule_work(&gpio_vbus->work);
+
+	return 0;
+}
+#endif
+
 /* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
 
 MODULE_ALIAS("platform:gpio-vbus");
@@ -337,6 +365,10 @@  static struct platform_driver gpio_vbus_driver = {
 		.owner = THIS_MODULE,
 	},
 	.remove  = __exit_p(gpio_vbus_remove),
+#ifdef CONFIG_PM
+	.suspend	= gpio_vbus_suspend,
+	.resume		= gpio_vbus_resume
+#endif
 };
 
 static int __init gpio_vbus_init(void)
diff --git a/include/linux/usb/gpio_vbus.h b/include/linux/usb/gpio_vbus.h
index d9f03cc..2faa38d 100644
--- a/include/linux/usb/gpio_vbus.h
+++ b/include/linux/usb/gpio_vbus.h
@@ -27,4 +27,5 @@  struct gpio_vbus_mach_info {
 	int gpio_pullup;
 	bool gpio_vbus_inverted;
 	bool gpio_pullup_inverted;
+	bool disconnect_on_suspend;
 };