Re: [PATCHv7 2/4] USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ instead of an auto enabled IRQ request followed by IRQ disable

2015-03-12 Thread Sylvain Rochet
Hello Felipe,

On Tue, Mar 10, 2015 at 04:12:14PM -0500, Felipe Balbi wrote:
 Hi,
 
 (dropping patch, my only context is subject line)
 
 USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ
 instead of an auto enabled IRQ request followed by IRQ disable
 
 Holy crap, that's a pretty long patch *short* description. I'm trimming
 it to:
 
 usb: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ

I agree, lesson learned!, thanks for the heads up :)

Cheers,
Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 0/4] USB: gadget: atmel_usba_udc: PM driver improvements

2015-02-12 Thread Sylvain Rochet
Start clocks on rising edge of the Vbus signal, stop clocks on falling
edge of the Vbus signal.

Add suspend/resume with wakeup support.

Changes since v6:
  * Removed single IRQ edge support, which was used to wake up only on 
device connection. We don't have yet a clean solution to handle IRQ
controller with (at91sam9x5) and without (at91rm9200) single edge 
support. Rework PATCH v6 4/5 removed, we don't need this one anymore.

Changes since v5:
  * Some boards does not support configuring a GPIO interrupt on a specific
edge (rising only or falling only). As suggested added a config boolean
to distinguish between boards with and without support
  * Added a missing mutex_lock()/unlock() in usba_udc_suspend(), we need to
protect usba_stop() because usba_start() and usba_stop() can still
be called by Vbus IRQ handler.
  * Rebased the full series on linux-next
  * Patch cleaning with the help of checkpatch.pl

Changes since v4:
  * Now using IRQ_NOAUTOEN flag to remove the unused check for
udc-driver is not NULL in the Vbus IRQ.
  * Reworked the start/stop of clocks on Vbus edges to prepare for
suspend/resume support, factorised start and stop procedures
  * New patch, suspend/resume for USBA with wakeup support

Changes since v3:
  * Added stable tag for the first patch
  * As suggested, removed the unused check for udc-driver is NULL in
Vbus IRQ by requesting IRQ after udc-driver is set and by releasing
IRQ before udc-driver is cleared
  * Rebased the core patch of this series against the just explained changes

Changes since v2:
  * Use spin_lock_irqsave/unlock_irqrestore instead of spin_lock/unlock in
threaded interrupt because we are not in irq context anymore
  * Removed useless and probably harmful IRQF_NO_SUSPEND from
devm_request_threaded_irq() flags

Changes since v1:
  * Using a threaded irq and mutex instead of spinclock as suggested
  * Moved a silently fixed bug in a separate patch (1/2)

Sylvain Rochet (4):
  USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state
  USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ
instead of an auto enabled IRQ request followed by IRQ disable
  USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus
signal, stop clocks on falling edge of the Vbus signal
  USB: gadget: atmel_usba_udc: Add suspend/resume with wakeup support

 drivers/usb/gadget/udc/atmel_usba_udc.c | 208 
 drivers/usb/gadget/udc/atmel_usba_udc.h |   4 +
 2 files changed, 159 insertions(+), 53 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv6 4/5] USB: gadget: atmel_usba_udc: Prepare for IRQ single edge support

2015-02-12 Thread Sylvain Rochet
Hello Boris,

On Sun, Feb 08, 2015 at 10:24:39AM +0100, Boris Brezillon wrote:
 On Sat, 7 Feb 2015 20:37:23 +0100
 Sylvain Rochet sylvain.roc...@finsecur.com wrote:
 
  If not, is udc-caps-irq_single_edge_support boolean acceptable ?
 
 Do you mean keeping the current approach ?

Yes!


 If you do, then maybe you can rework a bit the way you detect the GPIO
 controller you depends on: instead of linking this information to the
 usba compatible string you could link it to the gpio controller
 compatible string.
 
 You can find the gpio controller node thanks to your vbus-gpio
 property: use the phandle defined in this property to find the gpio
 controller node, and once you have the device_node referencing the gpio
 controller you can match it with your internal device_id table
 (containing 2 entries: one for the at91rm9200 IP and the other for the
 at91sam9x5 IP).

I have a working PoC for that if this is the chosen solution.


 Another solution would be to add an irq_try_set_irq_type function that
 would not complain when it fails to set the requested trigger.
 
 Thomas, I know you did not follow the whole thread, but would you mind
 adding this irq_try_set_irq_type function (here is a reference
 implementation [1]), to prevent this error trace from happening when
 we're just trying a configuration ?

This would be great :-)


  If not, I am ok to drop the feature, this is only a bonus.
 
 That could be a short term solution, to get this series accepted. We
 could then find a proper way to support that optimization.

I agree, I have the feeling your proposed core change may takes a long 
time, I just sent a v7 without IRQ single edge support.


Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 2/4] USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ instead of an auto enabled IRQ request followed by IRQ disable

2015-02-12 Thread Sylvain Rochet
Vbus IRQ handler needs a started UDC driver to work because it uses
udc-driver, which is set by the UDC start handler. The previous way
chosen was to return from interrupt if udc-driver is NULL using a
spinlock around the check.

We now request an auto disabled (IRQ_NOAUTOEN) Vbus signal IRQ instead
of an auto enabled IRQ followed by disable_irq(). This way we remove the
very small timeslot of enabled IRQ which existed previously between
request() and disable(). We don't need anymore to check if udc-driver
is NULL in IRQ handler.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Suggested-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 9 ++---
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index e63c6fc..bbbd5f1 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1749,10 +1749,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 
spin_lock(udc-lock);
 
-   /* May happen if Vbus pin toggles during probe() */
-   if (!udc-driver)
-   goto out;
-
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
@@ -1773,7 +1769,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
udc-vbus_prev = vbus;
}
 
-out:
spin_unlock(udc-lock);
 
return IRQ_HANDLED;
@@ -2113,6 +2108,8 @@ static int usba_udc_probe(struct platform_device *pdev)
 
if (gpio_is_valid(udc-vbus_pin)) {
if (!devm_gpio_request(pdev-dev, udc-vbus_pin, 
atmel_usba_udc)) {
+   irq_set_status_flags(gpio_to_irq(udc-vbus_pin),
+   IRQ_NOAUTOEN);
ret = devm_request_irq(pdev-dev,
gpio_to_irq(udc-vbus_pin),
usba_vbus_irq, 0,
@@ -2122,8 +2119,6 @@ static int usba_udc_probe(struct platform_device *pdev)
dev_warn(udc-pdev-dev,
 failed to request vbus irq; 
 assuming always on\n);
-   } else {
-   disable_irq(gpio_to_irq(udc-vbus_pin));
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 4/4] USB: gadget: atmel_usba_udc: Add suspend/resume with wakeup support

2015-02-12 Thread Sylvain Rochet
This patch add suspend/resume with wakeup support for Atmel USBA.

On suspend: We stay continuously clocked if Vbus signal is not
available. If Vbus signal is available we set the Vbus signal as a wake
up source then we stop the USBA itself and all clocks used by USBA.

On resume: We recover clocks and USBA if we stopped them. If a device is
currently connected at resume time we enable the controller.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 57 +
 1 file changed, 57 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 999e2f2..d019b6c 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -2177,6 +2177,7 @@ static int usba_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(pdev-dev, udc-gadget);
if (ret)
return ret;
+   device_init_wakeup(pdev-dev, 1);
 
usba_init_debugfs(udc);
for (i = 1; i  udc-num_ep; i++)
@@ -2192,6 +2193,7 @@ static int __exit usba_udc_remove(struct platform_device 
*pdev)
 
udc = platform_get_drvdata(pdev);
 
+   device_init_wakeup(pdev-dev, 0);
usb_del_gadget_udc(udc-gadget);
 
for (i = 1; i  udc-num_ep; i++)
@@ -2201,10 +2203,65 @@ static int __exit usba_udc_remove(struct 
platform_device *pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int usba_udc_suspend(struct device *dev)
+{
+   struct usba_udc *udc = dev_get_drvdata(dev);
+
+   /* Not started */
+   if (!udc-driver)
+   return 0;
+
+   mutex_lock(udc-vbus_mutex);
+
+   if (!device_may_wakeup(dev)) {
+   usba_stop(udc);
+   goto out;
+   }
+
+   /*
+* Device may wake up. We stay clocked if we failed
+* to request vbus irq, assuming always on.
+*/
+   if (gpio_is_valid(udc-vbus_pin)) {
+   usba_stop(udc);
+   enable_irq_wake(gpio_to_irq(udc-vbus_pin));
+   }
+
+out:
+   mutex_unlock(udc-vbus_mutex);
+   return 0;
+}
+
+static int usba_udc_resume(struct device *dev)
+{
+   struct usba_udc *udc = dev_get_drvdata(dev);
+
+   /* Not started */
+   if (!udc-driver)
+   return 0;
+
+   if (device_may_wakeup(dev)  gpio_is_valid(udc-vbus_pin))
+   disable_irq_wake(gpio_to_irq(udc-vbus_pin));
+
+   /* If Vbus is present, enable the controller and wait for reset */
+   mutex_lock(udc-vbus_mutex);
+   udc-vbus_prev = vbus_is_present(udc);
+   if (udc-vbus_prev)
+   usba_start(udc);
+   mutex_unlock(udc-vbus_mutex);
+
+   return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
+
 static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {
.name   = atmel_usba_udc,
+   .pm = usba_udc_pm_ops,
.of_match_table = of_match_ptr(atmel_udc_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 3/4] USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus signal, stop clocks on falling edge of the Vbus signal

2015-02-12 Thread Sylvain Rochet
If USB PLL is not necessary for other USB drivers (e.g. OHCI and EHCI)
we will reduce power consumption by switching off the USB PLL if no USB
Host is currently connected to this USB Device.

We are using Vbus GPIO signal to detect Host presence. If Vbus signal is
not available then the device stays continuously clocked.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 144 +---
 drivers/usb/gadget/udc/atmel_usba_udc.h |   4 +
 2 files changed, 100 insertions(+), 48 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index bbbd5f1..999e2f2 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1739,7 +1739,72 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
 }
 
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
+static int start_clock(struct usba_udc *udc)
+{
+   int ret;
+
+   if (udc-clocked)
+   return 0;
+
+   ret = clk_prepare_enable(udc-pclk);
+   if (ret)
+   return ret;
+   ret = clk_prepare_enable(udc-hclk);
+   if (ret) {
+   clk_disable_unprepare(udc-pclk);
+   return ret;
+   }
+
+   udc-clocked = true;
+   return 0;
+}
+
+static void stop_clock(struct usba_udc *udc)
+{
+   if (!udc-clocked)
+   return;
+
+   clk_disable_unprepare(udc-hclk);
+   clk_disable_unprepare(udc-pclk);
+
+   udc-clocked = false;
+}
+
+static int usba_start(struct usba_udc *udc)
+{
+   unsigned long flags;
+   int ret;
+
+   ret = start_clock(udc);
+   if (ret)
+   return ret;
+
+   spin_lock_irqsave(udc-lock, flags);
+   toggle_bias(udc, 1);
+   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+   usba_int_enb_set(udc, USBA_END_OF_RESET);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   return 0;
+}
+
+static void usba_stop(struct usba_udc *udc)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(udc-lock, flags);
+   udc-gadget.speed = USB_SPEED_UNKNOWN;
+   reset_all_endpoints(udc);
+
+   /* This will also disable the DP pullup */
+   toggle_bias(udc, 0);
+   usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   stop_clock(udc);
+}
+
+static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 {
struct usba_udc *udc = devid;
int vbus;
@@ -1747,30 +1812,22 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
/* debounce */
udelay(10);
 
-   spin_lock(udc-lock);
+   mutex_lock(udc-vbus_mutex);
 
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
-   toggle_bias(udc, 1);
-   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-   usba_int_enb_set(udc, USBA_END_OF_RESET);
+   usba_start(udc);
} else {
-   udc-gadget.speed = USB_SPEED_UNKNOWN;
-   reset_all_endpoints(udc);
-   toggle_bias(udc, 0);
-   usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-   if (udc-driver-disconnect) {
-   spin_unlock(udc-lock);
+   usba_stop(udc);
+
+   if (udc-driver-disconnect)
udc-driver-disconnect(udc-gadget);
-   spin_lock(udc-lock);
-   }
}
udc-vbus_prev = vbus;
}
 
-   spin_unlock(udc-lock);
-
+   mutex_unlock(udc-vbus_mutex);
return IRQ_HANDLED;
 }
 
@@ -1782,57 +1839,47 @@ static int atmel_usba_start(struct usb_gadget *gadget,
unsigned long flags;
 
spin_lock_irqsave(udc-lock, flags);
-
udc-devstatus = 1  USB_DEVICE_SELF_POWERED;
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
-   ret = clk_prepare_enable(udc-pclk);
-   if (ret)
-   return ret;
-   ret = clk_prepare_enable(udc-hclk);
-   if (ret) {
-   clk_disable_unprepare(udc-pclk);
-   return ret;
-   }
+   mutex_lock(udc-vbus_mutex);
 
-   udc-vbus_prev = 0;
if (gpio_is_valid(udc-vbus_pin))
enable_irq(gpio_to_irq(udc-vbus_pin));
 
/* If Vbus is present, enable the controller and wait for reset */
-   spin_lock_irqsave(udc-lock, flags);
-   if (vbus_is_present(udc)  udc-vbus_prev == 0) {
-   toggle_bias(udc, 1);
-   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-   usba_int_enb_set(udc, USBA_END_OF_RESET);
-
-   udc-vbus_prev = 1

[PATCHv7 1/4] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-02-12 Thread Sylvain Rochet
If vbus gpio is high at init, we should set vbus_prev to true
accordingly to the current vbus state. Without that, we skip the first
vbus interrupt because the saved vbus state is not consistent.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index d79cb35..e63c6fc 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1811,6 +1811,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_int_enb_set(udc, USBA_END_OF_RESET);
+
+   udc-vbus_prev = 1;
}
spin_unlock_irqrestore(udc-lock, flags);
 
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 3/3] ARM: at91: dt: at91sam9n12ek: enable udp

2015-02-09 Thread Sylvain Rochet
Hello Bo,

On Mon, Feb 09, 2015 at 05:02:52PM +0800, Bo Shen wrote:
 Enable usb device port on at91sam9n12ek board.
 
 Signed-off-by: Bo Shen voice.s...@atmel.com
 ---
 
  arch/arm/boot/dts/at91sam9n12ek.dts | 5 +
  1 file changed, 5 insertions(+)
 
 diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts 
 b/arch/arm/boot/dts/at91sam9n12ek.dts
 index 13bb24e..3e572e5 100644
 --- a/arch/arm/boot/dts/at91sam9n12ek.dts
 +++ b/arch/arm/boot/dts/at91sam9n12ek.dts
 @@ -120,6 +120,11 @@
   };
   };
  
 + usb1: gadget@f803c000 {
 + atmel,vbus-gpio = pioB 16 GPIO_ACTIVE_HIGH;
 + status = okay;
 + };
 +

There is an external resistor divider on PB16, acting like a pull-down 
(R22+R23). PB16 reset state is input, pull-up, schmitt trigger, you need 
to disable the pull-up in pinctrl this way:

usb1: gadget@f803c000 {
pinctrl-names = default;
pinctrl-0 = pinctrl_board_usb1;
…
}

pinctrl … {
usb1 {
pinctrl_board_usb1: usb1-board {
atmel,pins = AT91_PIOB 16 AT91_PERIPH_GPIO 
AT91_PINCTRL_DEGLITCH;/* PB16, no pull up and deglitch */
};
};
};


Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv6 4/5] USB: gadget: atmel_usba_udc: Prepare for IRQ single edge support

2015-02-07 Thread Sylvain Rochet
Hello Nicolas,


On Thu, Feb 05, 2015 at 06:19:55PM +0100, Nicolas Ferre wrote:
 Le 22/01/2015 18:14, Boris Brezillon a écrit :
  On Thu, 22 Jan 2015 17:56:44 +0100
  Sylvain Rochet sylvain.roc...@finsecur.com wrote:
  
   -static const struct usba_udc_errata at91sam9g45_errata = {
   +static const struct usba_udc_caps at91sam9g45_caps = {
 .pulse_bias = at91sam9g45_pulse_bias,
   + .irq_single_edge_support = true,
 
 Nope! at91sam9g45 doesn't have this property. You'll have to create
 another compatible string and capabilities structure
 (atmel,at91sam9x5-udc)

Oops.


 But still, I don't know if it's the proper approach. The possibility to
 trigger an IRQ on both edges or a single edge is a capacity of the gpio
 controller, not the USBA IP. So, it's a little bit strange to have this
 capability here.

I agree.


 I don't know if it's actually feasible but trying to configure the IRQ
 on a single edge, testing if it's accepted by the GPIO irq controller
 and if not, falling back to a both edge pattern. Doesn't it look like
 a way to workaround this issue nicely? Can you give it a try?

Tried, it works, but it displays the following message from 
__irq_set_trigger() [1] during devm_request_threaded_irq(…, 
IRQF_TRIGGER_RISING, …) on boards which does not support single-edge 
IRQ:

genirq: Setting trigger mode 1 for irq 176 failed (gpio_irq_type+0x0/0x34)

Is it acceptable ?
If not, is udc-caps-irq_single_edge_support boolean acceptable ?
If not, I am ok to drop the feature, this is only a bonus.


Sylvain


[1] http://lxr.free-electrons.com/source/kernel/irq/manage.c#L619
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv6 2/5] USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ instead of an auto enabled IRQ request followed by IRQ disable

2015-01-23 Thread Sylvain Rochet
Hello,

On Fri, Jan 23, 2015 at 09:59:58AM +0100, Nicolas Ferre wrote:
 Le 23/01/2015 08:43, Jean-Christophe PLAGNIOL-VILLARD a écrit :
   On Jan 23, 2015, at 12:56 AM, Sylvain Rochet 
   sylvain.roc...@finsecur.com wrote:
   + irq_set_status_flags(gpio_to_irq(udc-vbus_pin),
   + IRQ_NOAUTOEN);
  
  not happy about still using the broken gpio_to_irq API
  
  Linus can pass the IRQ via board file?
  
  and via DT we can use IRQ directly

Although I agree on the general principle, this driver is also used by 
non-DT boards.

I have concerns at least for at32ap700x-based boards which use this 
driver and are non-DT. The suggested change requires changing platform 
data of at32ap700x in such a way we may break it in my opinion.


 Absolutely not the topic of this patch series.
 Maybe the subject of another patch later?

Indeed. This series is only about PM support, harmless rework, or 
necessary rework for PM. Changing the way we acquire the IRQ is not 
harmless, this should be checked carefully for DT and particularly 
non-DT boards.


Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 5/5] USB: gadget: atmel_usba_udc: Add suspend/resume with wakeup support

2015-01-22 Thread Sylvain Rochet
This patch add suspend/resume with wakeup support for Atmel USBA.

On suspend: We stay continuously clocked if Vbus signal is not
available. If Vbus signal is available we set the Vbus signal as a wake
up source then we stop the USBA itself and all clocks used by USBA.

On resume: We recover clocks and USBA if we stopped them. If a device is
currently connected at resume time we enable the controller.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 68 +
 1 file changed, 68 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 361f740..7942c2f 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -2178,6 +2178,7 @@ static int usba_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(pdev-dev, udc-gadget);
if (ret)
return ret;
+   device_init_wakeup(pdev-dev, 1);
 
usba_init_debugfs(udc);
for (i = 1; i  udc-num_ep; i++)
@@ -2193,6 +2194,7 @@ static int __exit usba_udc_remove(struct platform_device 
*pdev)
 
udc = platform_get_drvdata(pdev);
 
+   device_init_wakeup(pdev-dev, 0);
usb_del_gadget_udc(udc-gadget);
 
for (i = 1; i  udc-num_ep; i++)
@@ -2202,10 +2204,76 @@ static int __exit usba_udc_remove(struct 
platform_device *pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int usba_udc_suspend(struct device *dev)
+{
+   struct usba_udc *udc = dev_get_drvdata(dev);
+
+   /* Not started */
+   if (!udc-driver)
+   return 0;
+
+   mutex_lock(udc-vbus_mutex);
+
+   if (!device_may_wakeup(dev)) {
+   usba_stop(udc);
+   goto out;
+   }
+
+   /*
+* Device may wake up. We stay clocked if we failed
+* to request vbus irq, assuming always on.
+*/
+   if (gpio_is_valid(udc-vbus_pin)) {
+   usba_stop(udc);
+   /* Only wake up on device connection */
+   if (udc-caps  udc-caps-irq_single_edge_support)
+   irq_set_irq_type(gpio_to_irq(udc-vbus_pin),
+   udc-vbus_pin_inverted ?
+   IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING);
+
+   enable_irq_wake(gpio_to_irq(udc-vbus_pin));
+   }
+
+out:
+   mutex_unlock(udc-vbus_mutex);
+   return 0;
+}
+
+static int usba_udc_resume(struct device *dev)
+{
+   struct usba_udc *udc = dev_get_drvdata(dev);
+
+   /* Not started */
+   if (!udc-driver)
+   return 0;
+
+   if (device_may_wakeup(dev)  gpio_is_valid(udc-vbus_pin)) {
+   disable_irq_wake(gpio_to_irq(udc-vbus_pin));
+
+   if (udc-caps  udc-caps-irq_single_edge_support)
+   irq_set_irq_type(gpio_to_irq(udc-vbus_pin),
+   IRQ_TYPE_EDGE_BOTH);
+   }
+
+   /* If Vbus is present, enable the controller and wait for reset */
+   mutex_lock(udc-vbus_mutex);
+   udc-vbus_prev = vbus_is_present(udc);
+   if (udc-vbus_prev)
+   usba_start(udc);
+   mutex_unlock(udc-vbus_mutex);
+
+   return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
+
 static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {
.name   = atmel_usba_udc,
+   .pm = usba_udc_pm_ops,
.of_match_table = of_match_ptr(atmel_udc_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 2/5] USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ instead of an auto enabled IRQ request followed by IRQ disable

2015-01-22 Thread Sylvain Rochet
Vbus IRQ handler needs a started UDC driver to work because it uses
udc-driver, which is set by the UDC start handler. The previous way
chosen was to return from interrupt if udc-driver is NULL using a
spinlock around the check.

We now request an auto disabled (IRQ_NOAUTOEN) Vbus signal IRQ instead
of an auto enabled IRQ followed by disable_irq(). This way we remove the
very small timeslot of enabled IRQ which existed previously between
request() and disable(). We don't need anymore to check if udc-driver
is NULL in IRQ handler.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Suggested-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 9 ++---
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 40e5fc7..f9f305f 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1745,10 +1745,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 
spin_lock(udc-lock);
 
-   /* May happen if Vbus pin toggles during probe() */
-   if (!udc-driver)
-   goto out;
-
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
@@ -1769,7 +1765,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
udc-vbus_prev = vbus;
}
 
-out:
spin_unlock(udc-lock);
 
return IRQ_HANDLED;
@@ -2109,6 +2104,8 @@ static int usba_udc_probe(struct platform_device *pdev)
 
if (gpio_is_valid(udc-vbus_pin)) {
if (!devm_gpio_request(pdev-dev, udc-vbus_pin, 
atmel_usba_udc)) {
+   irq_set_status_flags(gpio_to_irq(udc-vbus_pin),
+   IRQ_NOAUTOEN);
ret = devm_request_irq(pdev-dev,
gpio_to_irq(udc-vbus_pin),
usba_vbus_irq, 0,
@@ -2118,8 +2115,6 @@ static int usba_udc_probe(struct platform_device *pdev)
dev_warn(udc-pdev-dev,
 failed to request vbus irq; 
 assuming always on\n);
-   } else {
-   disable_irq(gpio_to_irq(udc-vbus_pin));
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 3/5] USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus signal, stop clocks on falling edge of the Vbus signal

2015-01-22 Thread Sylvain Rochet
If USB PLL is not necessary for other USB drivers (e.g. OHCI and EHCI)
we will reduce power consumption by switching off the USB PLL if no USB
Host is currently connected to this USB Device.

We are using Vbus GPIO signal to detect Host presence. If Vbus signal is
not available then the device stays continuously clocked.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 144 +---
 drivers/usb/gadget/udc/atmel_usba_udc.h |   4 +
 2 files changed, 100 insertions(+), 48 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index f9f305f..d554106 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1735,7 +1735,72 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
 }
 
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
+static int start_clock(struct usba_udc *udc)
+{
+   int ret;
+
+   if (udc-clocked)
+   return 0;
+
+   ret = clk_prepare_enable(udc-pclk);
+   if (ret)
+   return ret;
+   ret = clk_prepare_enable(udc-hclk);
+   if (ret) {
+   clk_disable_unprepare(udc-pclk);
+   return ret;
+   }
+
+   udc-clocked = true;
+   return 0;
+}
+
+static void stop_clock(struct usba_udc *udc)
+{
+   if (!udc-clocked)
+   return;
+
+   clk_disable_unprepare(udc-hclk);
+   clk_disable_unprepare(udc-pclk);
+
+   udc-clocked = false;
+}
+
+static int usba_start(struct usba_udc *udc)
+{
+   unsigned long flags;
+   int ret;
+
+   ret = start_clock(udc);
+   if (ret)
+   return ret;
+
+   spin_lock_irqsave(udc-lock, flags);
+   toggle_bias(udc, 1);
+   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+   usba_int_enb_set(udc, USBA_END_OF_RESET);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   return 0;
+}
+
+static void usba_stop(struct usba_udc *udc)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(udc-lock, flags);
+   udc-gadget.speed = USB_SPEED_UNKNOWN;
+   reset_all_endpoints(udc);
+
+   /* This will also disable the DP pullup */
+   toggle_bias(udc, 0);
+   usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   stop_clock(udc);
+}
+
+static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 {
struct usba_udc *udc = devid;
int vbus;
@@ -1743,30 +1808,22 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
/* debounce */
udelay(10);
 
-   spin_lock(udc-lock);
+   mutex_lock(udc-vbus_mutex);
 
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
-   toggle_bias(udc, 1);
-   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-   usba_int_enb_set(udc, USBA_END_OF_RESET);
+   usba_start(udc);
} else {
-   udc-gadget.speed = USB_SPEED_UNKNOWN;
-   reset_all_endpoints(udc);
-   toggle_bias(udc, 0);
-   usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-   if (udc-driver-disconnect) {
-   spin_unlock(udc-lock);
+   usba_stop(udc);
+
+   if (udc-driver-disconnect)
udc-driver-disconnect(udc-gadget);
-   spin_lock(udc-lock);
-   }
}
udc-vbus_prev = vbus;
}
 
-   spin_unlock(udc-lock);
-
+   mutex_unlock(udc-vbus_mutex);
return IRQ_HANDLED;
 }
 
@@ -1778,57 +1835,47 @@ static int atmel_usba_start(struct usb_gadget *gadget,
unsigned long flags;
 
spin_lock_irqsave(udc-lock, flags);
-
udc-devstatus = 1  USB_DEVICE_SELF_POWERED;
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
-   ret = clk_prepare_enable(udc-pclk);
-   if (ret)
-   return ret;
-   ret = clk_prepare_enable(udc-hclk);
-   if (ret) {
-   clk_disable_unprepare(udc-pclk);
-   return ret;
-   }
+   mutex_lock(udc-vbus_mutex);
 
-   udc-vbus_prev = 0;
if (gpio_is_valid(udc-vbus_pin))
enable_irq(gpio_to_irq(udc-vbus_pin));
 
/* If Vbus is present, enable the controller and wait for reset */
-   spin_lock_irqsave(udc-lock, flags);
-   if (vbus_is_present(udc)  udc-vbus_prev == 0) {
-   toggle_bias(udc, 1);
-   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-   usba_int_enb_set(udc, USBA_END_OF_RESET);
-
-   udc-vbus_prev = 1

[PATCHv6 4/5] USB: gadget: atmel_usba_udc: Prepare for IRQ single edge support

2015-01-22 Thread Sylvain Rochet
Renamed struct usba_udc_errata to struct usba_udc_caps, we are adding a
new property which is not about errata, this way the struct is not
misnamed.

New struct usba_udc_caps property: irq_single_edge_support, boolean,
set to true if the board supports IRQ_TYPE_EDGE_FALLING and
IRQ_TYPE_EDGE_RISING, otherwise set to false.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 25 +++--
 drivers/usb/gadget/udc/atmel_usba_udc.h |  5 +++--
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index d554106..361f740 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -338,8 +338,8 @@ static int vbus_is_present(struct usba_udc *udc)
 
 static void toggle_bias(struct usba_udc *udc, int is_on)
 {
-   if (udc-errata  udc-errata-toggle_bias)
-   udc-errata-toggle_bias(udc, is_on);
+   if (udc-caps  udc-caps-toggle_bias)
+   udc-caps-toggle_bias(udc, is_on);
 }
 
 static void generate_bias_pulse(struct usba_udc *udc)
@@ -347,8 +347,8 @@ static void generate_bias_pulse(struct usba_udc *udc)
if (!udc-bias_pulse_needed)
return;
 
-   if (udc-errata  udc-errata-pulse_bias)
-   udc-errata-pulse_bias(udc);
+   if (udc-caps  udc-caps-pulse_bias)
+   udc-caps-pulse_bias(udc);
 
udc-bias_pulse_needed = false;
 }
@@ -1901,18 +1901,23 @@ static void at91sam9g45_pulse_bias(struct usba_udc *udc)
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
 }
 
-static const struct usba_udc_errata at91sam9rl_errata = {
+static const struct usba_udc_caps at91sam9rl_caps = {
.toggle_bias = at91sam9rl_toggle_bias,
 };
 
-static const struct usba_udc_errata at91sam9g45_errata = {
+static const struct usba_udc_caps at91sam9g45_caps = {
.pulse_bias = at91sam9g45_pulse_bias,
+   .irq_single_edge_support = true,
+};
+
+static const struct usba_udc_caps sama5d3_caps = {
+   .irq_single_edge_support = true,
 };
 
 static const struct of_device_id atmel_udc_dt_ids[] = {
-   { .compatible = atmel,at91sam9rl-udc, .data = at91sam9rl_errata },
-   { .compatible = atmel,at91sam9g45-udc, .data = at91sam9g45_errata },
-   { .compatible = atmel,sama5d3-udc },
+   { .compatible = atmel,at91sam9rl-udc, .data = at91sam9rl_caps },
+   { .compatible = atmel,at91sam9g45-udc, .data = at91sam9g45_caps },
+   { .compatible = atmel,sama5d3-udc, .data = sama5d3_caps },
{ /* sentinel */ }
 };
 
@@ -1934,7 +1939,7 @@ static struct usba_ep * atmel_udc_of_init(struct 
platform_device *pdev,
if (!match)
return ERR_PTR(-EINVAL);
 
-   udc-errata = match-data;
+   udc-caps = match-data;
 
udc-num_ep = 0;
 
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h 
b/drivers/usb/gadget/udc/atmel_usba_udc.h
index 085749a..4fe4c87 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.h
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.h
@@ -304,9 +304,10 @@ struct usba_request {
unsigned intmapped:1;
 };
 
-struct usba_udc_errata {
+struct usba_udc_caps {
void (*toggle_bias)(struct usba_udc *udc, int is_on);
void (*pulse_bias)(struct usba_udc *udc);
+   bool irq_single_edge_support;
 };
 
 struct usba_udc {
@@ -322,7 +323,7 @@ struct usba_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct platform_device *pdev;
-   const struct usba_udc_errata *errata;
+   const struct usba_udc_caps *caps;
int irq;
int vbus_pin;
int vbus_pin_inverted;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 1/5] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-01-22 Thread Sylvain Rochet
If vbus gpio is high at init, we should set vbus_prev to true
accordingly to the current vbus state. Without that, we skip the first
vbus interrupt because the saved vbus state is not consistent.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 4b5b7fa..40e5fc7 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1807,6 +1807,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_int_enb_set(udc, USBA_END_OF_RESET);
+
+   udc-vbus_prev = 1;
}
spin_unlock_irqrestore(udc-lock, flags);
 
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 0/5] USB: gadget: atmel_usba_udc: Driver improvements

2015-01-22 Thread Sylvain Rochet
Start clocks on rising edge of the Vbus signal, stop clocks on falling
edge of the Vbus signal.

Add suspend/resume with wakeup support.

This series is based on linux-next and depends on this complete series:
  https://lkml.org/lkml/2015/1/12/209
which is currently only partially pushed to linux-next, the following 
patch should be pushed along with this series:
  https://lkml.org/lkml/2015/1/12/212

Changes since v5:
  * Some boards does not support configuring a GPIO interrupt on a specific
edge (rising only or falling only). As suggested added a config boolean
to distinguish between boards with and without support
  * Added a missing mutex_lock()/unlock() in usba_udc_suspend(), we need to
protect usba_stop() because usba_start() and usba_stop() can still 
be called by Vbus IRQ handler.
  * Rebased the full series on linux-next
  * Patch cleaning with the help of checkpatch.pl

Changes since v4:
  * Now using IRQ_NOAUTOEN flag to remove the unused check for
udc-driver is not NULL in the Vbus IRQ.
  * Reworked the start/stop of clocks on Vbus edges to prepare for
suspend/resume support, factorised start and stop procedures
  * New patch, suspend/resume for USBA with wakeup support

Changes since v3:
  * Added stable tag for the first patch
  * As suggested, removed the unused check for udc-driver is NULL in
Vbus IRQ by requesting IRQ after udc-driver is set and by releasing
IRQ before udc-driver is cleared
  * Rebased the core patch of this series against the just explained changes

Changes since v2:
  * Use spin_lock_irqsave/unlock_irqrestore instead of spin_lock/unlock in
threaded interrupt because we are not in irq context anymore
  * Removed useless and probably harmful IRQF_NO_SUSPEND from
devm_request_threaded_irq() flags

Changes since v1:
  * Using a threaded irq and mutex instead of spinclock as suggested
  * Moved a silently fixed bug in a separate patch (1/2)

Sylvain Rochet (5):
  USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state
  USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ
instead of an auto enabled IRQ request followed by IRQ disable
  USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus
signal, stop clocks on falling edge of the Vbus signal
  USB: gadget: atmel_usba_udc: Prepare for IRQ single edge support
  USB: gadget: atmel_usba_udc: Add suspend/resume with wakeup support

 drivers/usb/gadget/udc/atmel_usba_udc.c | 244 +++-
 drivers/usb/gadget/udc/atmel_usba_udc.h |   9 +-
 2 files changed, 188 insertions(+), 65 deletions(-)

-- 
2.1.4
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 1/4] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-01-21 Thread Sylvain Rochet
If vbus gpio is high at init, we should set vbus_prev to true
accordingly to the current vbus state. Without that, we skip the first
vbus interrupt because the saved vbus state is not consistent.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Fixes: 914a3f3b3754 (USB: add atmel_usba_udc driver)
Cc: sta...@vger.kernel.org #2.6.24+
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index ce88237..e207d75 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1791,6 +1791,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+
+   udc-vbus_prev = 1;
}
spin_unlock_irqrestore(udc-lock, flags);
 
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 2/4] USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ instead of an auto enabled IRQ request followed by IRQ disable

2015-01-21 Thread Sylvain Rochet
Vbus IRQ handler needs a started UDC driver to work because it uses
udc-driver, which is set by the UDC start handler. The previous way
chosen was to return from interrupt if udc-driver is NULL using a
spinlock around the check.

We now request an auto disabled (IRQ_NOAUTOEN) Vbus signal IRQ instead
of an auto enabled IRQ followed by disable_irq(). This way we remove the
very small timeslot of enabled IRQ which existed previously between
request() and disable(). We don't need anymore to check if udc-driver
is NULL in IRQ handler.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Suggested-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 8 +---
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index e207d75..d369ae0 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1729,10 +1729,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 
spin_lock(udc-lock);
 
-   /* May happen if Vbus pin toggles during probe() */
-   if (!udc-driver)
-   goto out;
-
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
@@ -1753,7 +1749,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
udc-vbus_prev = vbus;
}
 
-out:
spin_unlock(udc-lock);
 
return IRQ_HANDLED;
@@ -2049,6 +2044,7 @@ static int usba_udc_probe(struct platform_device *pdev)
 
if (gpio_is_valid(udc-vbus_pin)) {
if (!devm_gpio_request(pdev-dev, udc-vbus_pin, 
atmel_usba_udc)) {
+   irq_set_status_flags(gpio_to_irq(udc-vbus_pin), 
IRQ_NOAUTOEN);
ret = devm_request_irq(pdev-dev,
gpio_to_irq(udc-vbus_pin),
usba_vbus_irq, 0,
@@ -2058,8 +2054,6 @@ static int usba_udc_probe(struct platform_device *pdev)
dev_warn(udc-pdev-dev,
 failed to request vbus irq; 
 assuming always on\n);
-   } else {
-   disable_irq(gpio_to_irq(udc-vbus_pin));
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 4/4] USB: gadget: atmel_usba_udc: Add suspend/resume with wakeup support

2015-01-21 Thread Sylvain Rochet
This patch add suspend/resume with wakeup support for Atmel USBA.

On suspend: We stay continuously clocked if Vbus signal is not
available. If Vbus signal is available we set the Vbus signal as a wake
up source then we stop the USBA itself and all clocks used by USBA.

On resume: We recover clocks and USBA we stopped them. If a device is
connected, i.e. connected while we were suspended without wakeup
enabled, we enable the controller.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 61 +
 1 file changed, 61 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 963e398..326725e 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -2115,6 +2115,7 @@ static int usba_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(pdev-dev, udc-gadget);
if (ret)
return ret;
+   device_init_wakeup(pdev-dev, 1);
 
usba_init_debugfs(udc);
for (i = 1; i  udc-num_ep; i++)
@@ -2130,6 +2131,7 @@ static int __exit usba_udc_remove(struct platform_device 
*pdev)
 
udc = platform_get_drvdata(pdev);
 
+   device_init_wakeup(pdev-dev, 0);
usb_del_gadget_udc(udc-gadget);
 
for (i = 1; i  udc-num_ep; i++)
@@ -2139,6 +2141,62 @@ static int __exit usba_udc_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int usba_udc_suspend(struct device *dev)
+{
+   struct usba_udc *udc = dev_get_drvdata(dev);
+
+   /* Not started */
+   if (!udc-driver)
+   return 0;
+
+   if (!device_may_wakeup(dev)) {
+   usba_stop(udc);
+   return 0;
+   }
+
+   /*
+* Device may wake up. We stay clocked if we failed
+* to request vbus irq, assuming always on.
+*/
+   if (gpio_is_valid(udc-vbus_pin)) {
+   usba_stop(udc);
+   /* Only wake up on device connection */
+   irq_set_irq_type(gpio_to_irq(udc-vbus_pin),
+   udc-vbus_pin_inverted ?
+   IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING);
+   enable_irq_wake(gpio_to_irq(udc-vbus_pin));
+   }
+
+   return 0;
+}
+
+static int usba_udc_resume(struct device *dev)
+{
+   struct usba_udc *udc = dev_get_drvdata(dev);
+
+   /* Not started */
+   if (!udc-driver)
+   return 0;
+
+   if (device_may_wakeup(dev)  gpio_is_valid(udc-vbus_pin)) {
+   disable_irq_wake(gpio_to_irq(udc-vbus_pin));
+   irq_set_irq_type(gpio_to_irq(udc-vbus_pin), 
IRQ_TYPE_EDGE_BOTH);
+   }
+
+   /* If Vbus is present, enable the controller and wait for reset */
+   mutex_lock(udc-vbus_mutex);
+   udc-vbus_prev = vbus_is_present(udc);
+
+   if (udc-vbus_prev)
+   usba_start(udc);
+
+   mutex_unlock(udc-vbus_mutex);
+
+   return 0;
+}
+#endif
+
 #if defined(CONFIG_OF)
 static const struct of_device_id atmel_udc_dt_ids[] = {
{ .compatible = atmel,at91sam9rl-udc },
@@ -2148,10 +2206,13 @@ static const struct of_device_id atmel_udc_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
 #endif
 
+static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
+
 static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {
.name   = atmel_usba_udc,
+   .pm = usba_udc_pm_ops,
.of_match_table = of_match_ptr(atmel_udc_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 3/4] USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus signal, stop clocks on falling edge of the Vbus signal

2015-01-21 Thread Sylvain Rochet
If USB PLL is not necessary for other USB drivers (e.g. OHCI and EHCI)
we will reduce power consumption by switching off the USB PLL if no USB
Host is currently connected to this USB Device.

We are using Vbus GPIO signal to detect Host presence. If Vbus signal is
not available then the device stays continuously clocked.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 149 +---
 drivers/usb/gadget/udc/atmel_usba_udc.h |   4 +
 2 files changed, 104 insertions(+), 49 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index d369ae0..963e398 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1719,38 +1719,98 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
 }
 
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
+static int start_clock(struct usba_udc *udc)
+{
+   int ret;
+
+   if (udc-clocked)
+   return 0;
+
+   ret = clk_prepare_enable(udc-pclk);
+   if (ret)
+   return ret;
+   ret = clk_prepare_enable(udc-hclk);
+   if (ret) {
+   clk_disable_unprepare(udc-pclk);
+   return ret;
+   }
+
+   udc-clocked = true;
+   return 0;
+}
+
+static void stop_clock(struct usba_udc *udc)
+{
+   if (!udc-clocked)
+   return;
+
+   clk_disable_unprepare(udc-hclk);
+   clk_disable_unprepare(udc-pclk);
+
+   udc-clocked = false;
+}
+
+static int usba_start(struct usba_udc *udc)
+{
+   unsigned long flags;
+   int ret;
+
+   ret = start_clock(udc);
+   if (ret)
+   return ret;
+
+   spin_lock_irqsave(udc-lock, flags);
+   toggle_bias(1);
+   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+   usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+   spin_unlock_irqrestore(udc-lock, flags);
+   return 0;
+}
+
+static void usba_stop(struct usba_udc *udc)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(udc-lock, flags);
+   udc-gadget.speed = USB_SPEED_UNKNOWN;
+   reset_all_endpoints(udc);
+
+   /* This will also disable the DP pullup */
+   toggle_bias(0);
+   usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   stop_clock(udc);
+}
+
+static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 {
struct usba_udc *udc = devid;
int vbus;
+   int ret;
 
/* debounce */
udelay(10);
 
-   spin_lock(udc-lock);
+   mutex_lock(udc-vbus_mutex);
 
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
+   udc-vbus_prev = vbus;
if (vbus) {
-   toggle_bias(1);
-   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-   usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+   ret = usba_start(udc);
+   if (ret)
+   goto out;
} else {
-   udc-gadget.speed = USB_SPEED_UNKNOWN;
-   reset_all_endpoints(udc);
-   toggle_bias(0);
-   usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-   if (udc-driver-disconnect) {
-   spin_unlock(udc-lock);
+   usba_stop(udc);
+
+   if (udc-driver-disconnect)
udc-driver-disconnect(udc-gadget);
-   spin_lock(udc-lock);
-   }
}
-   udc-vbus_prev = vbus;
}
 
-   spin_unlock(udc-lock);
-
+out:
+   mutex_unlock(udc-vbus_mutex);
return IRQ_HANDLED;
 }
 
@@ -1762,57 +1822,47 @@ static int atmel_usba_start(struct usb_gadget *gadget,
unsigned long flags;
 
spin_lock_irqsave(udc-lock, flags);
-
udc-devstatus = 1  USB_DEVICE_SELF_POWERED;
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
-   ret = clk_prepare_enable(udc-pclk);
-   if (ret)
-   return ret;
-   ret = clk_prepare_enable(udc-hclk);
-   if (ret) {
-   clk_disable_unprepare(udc-pclk);
-   return ret;
-   }
+   mutex_lock(udc-vbus_mutex);
 
-   udc-vbus_prev = 0;
if (gpio_is_valid(udc-vbus_pin))
enable_irq(gpio_to_irq(udc-vbus_pin));
 
/* If Vbus is present, enable the controller and wait for reset */
-   spin_lock_irqsave(udc-lock, flags);
-   if (vbus_is_present(udc)  udc-vbus_prev == 0) {
-   toggle_bias(1);
-   usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-   usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
-
-   udc-vbus_prev = 1;
+   udc

[PATCHv5 0/4] USB: gadget: atmel_usba_udc: Driver improvements

2015-01-21 Thread Sylvain Rochet
Start clocks on rising edge of the Vbus signal, stop clocks on falling 
edge of the Vbus signal.

Add suspend/resume with wakeup support.

Changes since v4:
  * Now using IRQ_NOAUTOEN flag to remove the unused check for 
udc-driver is not NULL in the Vbus IRQ.
  * Reworked the start/stop of clocks on Vbus edges to prepare for 
suspend/resume support, factorised start and stop procedures
  * New patch, suspend/resume for USBA with wakeup support

Changes since v3:
  * Added stable tag for the first patch
  * As suggested, removed the unused check for udc-driver is not NULL in
Vbus IRQ by requesting IRQ after udc-driver is set and by releasing
IRQ before udc-driver is cleared
  * Rebased the core patch of this series against the just explained changes

Changes since v2:
  * Use spin_lock_irqsave/unlock_irqrestore instead of spin_lock/unlock in
threaded interrupt because we are not in irq context anymore
  * Removed useless and probably harmful IRQF_NO_SUSPEND from
devm_request_threaded_irq() flags

Changes since v1:
  * Using a threaded irq and mutex instead of spinclock as suggested
  * Moved a silently fixed bug in a separate patch (1/2)

Sylvain Rochet (4):
  USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state
  USB: gadget: atmel_usba_udc: Request an auto disabled Vbus signal IRQ
instead of an auto enabled IRQ request followed by IRQ disable
  USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus
signal, stop clocks on falling edge of the Vbus signal
  USB: gadget: atmel_usba_udc: Add suspend/resume with wakeup support

 drivers/usb/gadget/udc/atmel_usba_udc.c | 214 
 drivers/usb/gadget/udc/atmel_usba_udc.h |   4 +
 2 files changed, 165 insertions(+), 53 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv4 2/3] USB: gadget: atmel_usba_udc: Enable Vbus signal IRQ in UDC start instead of UDC probe

2015-01-21 Thread Sylvain Rochet
Hi Boris,

On Wed, Jan 21, 2015 at 10:20:16AM +0100, Boris Brezillon wrote:
   
  udc-vbus_prev = 0;
  -   if (gpio_is_valid(udc-vbus_pin))
  -   enable_irq(gpio_to_irq(udc-vbus_pin));
  +   if (gpio_is_valid(udc-vbus_pin)) {
  +   ret = request_irq(gpio_to_irq(udc-vbus_pin),
  +   usba_vbus_irq, 0,
  +   atmel_usba_udc, udc);
  +   if (ret) {
  +   udc-vbus_pin = -ENODEV;
 
 I guess you're trying to protect against free_irq by changing the
 vbus_pin value (making it an invalid gpio id), but I think you should
 leave it unchanged for two reasons:
 1) If the request_irq call temporary fails (an ENOMEM for example) then
 you should be able to retry later, and modifying the vbus_pin value
 will prevent that.
 2) atmel_usba_stop will never be called if the atmel_usba_start failed,
 so there's no need to protect against this free_irq.

Indeed.

By the way, I just discovered irq_set_status_flags(irq, IRQ_NOAUTOEN); … 
so I am going for a v5 and the previous part is not relevant anymore.

Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv3 1/2] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-01-20 Thread Sylvain Rochet
Hello,

On Mon, Jan 19, 2015 at 12:55:47PM -0600, Felipe Balbi wrote:
 On Mon, Jan 19, 2015 at 03:09:44PM +0100, Nicolas Ferre wrote:
  Le 18/01/2015 18:24, Sylvain Rochet a écrit :
   If vbus gpio is high at init, we should set vbus_prev to true
   accordingly to the current vbus state. Without that, we skip the first
   vbus interrupt because the saved vbus state is not consistent.
   
   Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
  
  Indeed:
  Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
  
  We can also add the following tags:
  Fixes: 914a3f3b3754 (USB: add atmel_usba_udc driver)
  Cc: sta...@vger.kernel.org # 2.6.x-ish
 
 Please resend with the proper stable format. Also, this 2.6.x-ish should
 be 2.6.24+, git describe helps a lot figuring these out.

Unfortunately I failed to understand what I should do. The Also 
keyword means for me that there are two differents things to fix:

1. proper stable format
2. 2.6.x-ish → 2.6.24+

  2. does not imply fixing 1., isn'it ?

I read SubmittingPatches thoroughly and I can't find a reference to 
stable format.

Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 6/6] USB: host: ohci-at91: Fix wake-up support

2015-01-20 Thread Sylvain Rochet
This device needs to be continuously clocked to provide wake up support,
previously, if STANDBY target were chosen the device were
enable_irq_wake()-prepared and clock still active and if MEM target were
chosen the device were also enable_irq_wake()-prepared but not clocked
anymore, which is wrong.

Now, if STANDBY target is chosen the device is still clocked with wake
up support enabled, which were the previous default and if MEM target is
chosen the device is declocked with wake up support disabled.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Alan Stern st...@rowland.harvard.edu
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/host/ohci-at91.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 970a776..1fc5610 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -42,6 +42,7 @@ struct ohci_at91_priv {
struct clk *uclk;
struct clk *hclk;
bool clocked;
+   bool wakeup;/* Saved wake-up state for resume */
 };
 /* interface and function clocks; sometimes also an AHB clock */
 
@@ -61,6 +62,8 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
+   if (ohci_at91-clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(ohci_at91-uclk, 4800);
clk_prepare_enable(ohci_at91-uclk);
@@ -73,6 +76,8 @@ static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 
 static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
+   if (!ohci_at91-clocked)
+   return;
clk_disable_unprepare(ohci_at91-fclk);
clk_disable_unprepare(ohci_at91-iclk);
clk_disable_unprepare(ohci_at91-hclk);
@@ -614,15 +619,22 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
-   booldo_wakeup = device_may_wakeup(dev);
int ret;
 
-   if (do_wakeup)
+   /*
+* Disable wakeup if we are going to sleep with slow clock mode
+* enabled.
+*/
+   ohci_at91-wakeup = device_may_wakeup(dev)
+!at91_suspend_entering_slow_clock();
+
+   if (ohci_at91-wakeup)
enable_irq_wake(hcd-irq);
 
-   ret = ohci_suspend(hcd, do_wakeup);
+   ret = ohci_suspend(hcd, ohci_at91-wakeup);
if (ret) {
-   disable_irq_wake(hcd-irq);
+   if (ohci_at91-wakeup)
+   disable_irq_wake(hcd-irq);
return ret;
}
/*
@@ -632,7 +644,7 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
 *
 * REVISIT: some boards will be able to turn VBUS off...
 */
-   if (at91_suspend_entering_slow_clock()) {
+   if (!ohci_at91-wakeup) {
ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
ohci-hc_control = OHCI_CTRL_RWC;
ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
@@ -651,11 +663,10 @@ static int ohci_hcd_at91_drv_resume(struct device *dev)
struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
-   if (device_may_wakeup(dev))
+   if (ohci_at91-wakeup)
disable_irq_wake(hcd-irq);
 
-   if (!ohci_at91-clocked)
-   at91_start_clock(ohci_at91);
+   at91_start_clock(ohci_at91);
 
ohci_resume(hcd, false);
return 0;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 4/6] USB: host: ohci-at91: Move global variables to private struct

2015-01-20 Thread Sylvain Rochet
This patch move AT91 OHCI global variables (clocks ptr and clocked
boolean) to private struct ohci_at91_priv, stored in ohci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Alan Stern st...@rowland.harvard.edu
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/host/ohci-at91.c | 84 +++-
 1 file changed, 51 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 65e7836..c810917 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,16 @@
for ((index) = 0; (index)  AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) \
+   ((struct ohci_at91_priv *)hcd_to_ohci(h)-priv)
+
+struct ohci_at91_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   struct clk *hclk;
+   bool clocked;
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC OHCI Atmel driver
@@ -41,45 +50,49 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
 static const char hcd_name[] = ohci-atmel;
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct ohci_at91_priv),
+};
 
 extern int usb_disabled(void);
 
 /*-*/
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(ohci_at91-uclk, 4800);
+   clk_prepare_enable(ohci_at91-uclk);
}
-   clk_prepare_enable(hclk);
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(ohci_at91-hclk);
+   clk_prepare_enable(ohci_at91-iclk);
+   clk_prepare_enable(ohci_at91-fclk);
+   ohci_at91-clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
-   clk_disable_unprepare(hclk);
+   clk_disable_unprepare(ohci_at91-fclk);
+   clk_disable_unprepare(ohci_at91-iclk);
+   clk_disable_unprepare(ohci_at91-hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(ohci_at91-uclk);
+   ohci_at91-clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, start\n);
 
/*
 * Start the USB clocks.
 */
-   at91_start_clock();
+   at91_start_clock(ohci_at91);
 
/*
 * The USB host controller must remain in reset.
@@ -91,6 +104,7 @@ static void at91_stop_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, stop\n);
 
@@ -102,7 +116,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
 * Stop the USB clocks.
 */
-   at91_stop_clock();
+   at91_stop_clock(ohci_at91);
 }
 
 
@@ -129,6 +143,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct ohci_hcd *ohci;
int retval;
struct usb_hcd *hcd = NULL;
+   struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
int irq;
@@ -142,6 +157,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd = usb_create_hcd(driver, dev, at91);
if (!hcd)
return -ENOMEM;
+   ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(dev, res);
@@ -152,29 +168,29 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(dev, ohci_clk);
-   if (IS_ERR(iclk)) {
+   ohci_at91-iclk = devm_clk_get(dev, ohci_clk);
+   if (IS_ERR(ohci_at91-iclk)) {
dev_err(dev, failed to get ohci_clk\n);
-   retval = PTR_ERR(iclk);
+   retval = PTR_ERR(ohci_at91-iclk);
goto err

[PATCHv7 0/6] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-20 Thread Sylvain Rochet
USB: host: Atmel OHCI and EHCI drivers improvements

Suspend/resume support for EHCI.
struct dev_pm_ops for OHCI.
Removed global variables from both.
Fixed OHCI wake up support for STANDBY(wake-up enabled) and MEM(wake-up
disabled) sleep targets.

Changes since v6:
  * Collected Acked-by tags

Changes since v5:
  * Don't overwrite device wakeup flag with device_init_wakeup(),
now using a private wakeup bool instead.

Changes since v4:
  * Re-add at91_suspend_entering_slow_clock() to OHCI, we can't naively
remove this one, this device needs to be continuously clocked to
provide wake up support.
The removal of at91_suspend_entering_slow_clock() actually lighted up
an issue on wake up support, which is now fixed.

Changes since v3:
  * Using struct dev_pm_ops instead of static struct platform_driver
resume and suspend bindings for both EHCI and OHCI
  * Fixed inconsistency in patch subjects, _ intead of - for file names
  * Patch cleaning with the help of checkpatch.pl, fixed lines over
80 characters

Changes since v2:
  * Added patchs from an other submission, because this series
depended on this one
* EHCI: Move global variables to private struct
* OHCI: Move global variables to private struct
  * Using ohci-priv and ehci-priv instead of hcd-hcd_priv,
which were not the right way to do that

Changes since v1:
  * Don't use at91_suspend_entering_slow_clock() on EHCI,
we are trying to get read of this of this function
  * Removed at91_suspend_entering_slow_clock() from OHCI

Sylvain Rochet (6):
  USB: host: ehci-atmel: Add suspend/resume support
  USB: host: ohci-at91: Use struct dev_pm_ops instead of struct
platform_driver
  USB: host: ehci-atmel: Move global variables to private struct
  USB: host: ohci-at91: Move global variables to private struct
  USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack
initialisation
  USB: host: ohci-at91: Fix wake-up support

 drivers/usb/host/ehci-atmel.c | 102 +-
 drivers/usb/host/ohci-at91.c  | 126 ++
 2 files changed, 154 insertions(+), 74 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 1/6] USB: host: ehci-atmel: Add suspend/resume support

2015-01-20 Thread Sylvain Rochet
This patch add suspend/resume support for Atmel EHCI, mostly
about disabling and unpreparing clocks so USB PLL is stopped
before entering sleep state.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Alan Stern st...@rowland.harvard.edu
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Acked-by: Alexandre Belloni alexandre.bell...@free-electrons.com
---
 drivers/usb/host/ehci-atmel.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..5a15e3d 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -37,6 +37,8 @@ static int clocked;
 
 static void atmel_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -48,6 +50,8 @@ static void atmel_start_clock(void)
 
 static void atmel_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
@@ -174,6 +178,29 @@ static int ehci_atmel_drv_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+   int ret;
+
+   ret = ehci_suspend(hcd, false);
+   if (ret)
+   return ret;
+
+   atmel_stop_clock();
+   return 0;
+}
+
+static int ehci_atmel_drv_resume(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+   atmel_start_clock();
+   return ehci_resume(hcd, false);
+}
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = atmel,at91sam9g45-ehci },
@@ -183,12 +210,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 #endif
 
+static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
+   ehci_atmel_drv_resume);
+
 static struct platform_driver ehci_atmel_driver = {
.probe  = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
.driver = {
.name   = atmel-ehci,
+   .pm = ehci_atmel_pm_ops,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 5/6] USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack initialisation

2015-01-20 Thread Sylvain Rochet
struct usb_hcd *hcd = NULL;
...
hcd = usb_create_hcd(driver, dev, at91);

This patch remove *hcd useless initialisation

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Alan Stern st...@rowland.harvard.edu
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/host/ohci-at91.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index c810917..970a776 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -142,7 +142,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
-   struct usb_hcd *hcd = NULL;
+   struct usb_hcd *hcd;
struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 2/6] USB: host: ohci-at91: Use struct dev_pm_ops instead of struct platform_driver

2015-01-20 Thread Sylvain Rochet
This patch replace struct platform_driver.{resume,suspend} PM bindings
to a new struct dev_pm_ops.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Alan Stern st...@rowland.harvard.edu
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/host/ohci-at91.c | 21 ++---
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..65e7836 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -593,11 +593,11 @@ static int ohci_hcd_at91_drv_remove(struct 
platform_device *pdev)
 #ifdef CONFIG_PM
 
 static int
-ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-   booldo_wakeup = device_may_wakeup(pdev-dev);
+   booldo_wakeup = device_may_wakeup(dev);
int ret;
 
if (do_wakeup)
@@ -629,11 +629,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, 
pm_message_t mesg)
return ret;
 }
 
-static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_at91_drv_resume(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
 
-   if (device_may_wakeup(pdev-dev))
+   if (device_may_wakeup(dev))
disable_irq_wake(hcd-irq);
 
if (!clocked)
@@ -642,19 +642,18 @@ static int ohci_hcd_at91_drv_resume(struct 
platform_device *pdev)
ohci_resume(hcd, false);
return 0;
 }
-#else
-#define ohci_hcd_at91_drv_suspend NULL
-#define ohci_hcd_at91_drv_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
+   ohci_hcd_at91_drv_resume);
+
 static struct platform_driver ohci_hcd_at91_driver = {
.probe  = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
-   .suspend= ohci_hcd_at91_drv_suspend,
-   .resume = ohci_hcd_at91_drv_resume,
.driver = {
.name   = at91_ohci,
+   .pm = ohci_hcd_at91_pm_ops,
.of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv7 3/6] USB: host: ehci-atmel: Move global variables to private struct

2015-01-20 Thread Sylvain Rochet
This patch move Atmel EHCI global variables (clocks ptr and clocked
boolean) to private struct atmel_ehci_priv, stored in ehci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Boris Brezillon boris.brezil...@free-electrons.com
Acked-by: Alan Stern st...@rowland.harvard.edu
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/host/ehci-atmel.c | 79 +++
 1 file changed, 50 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 5a15e3d..663f790 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,48 +27,66 @@
 #define DRIVER_DESC EHCI Atmel driver
 
 static const char hcd_name[] = ehci-atmel;
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) \
+   ((struct atmel_ehci_priv *)hcd_to_ehci(h)-priv)
+
+struct atmel_ehci_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
 
 /*-*/
 
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (clocked)
+   if (atmel_ehci-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(atmel_ehci-uclk, 4800);
+   clk_prepare_enable(atmel_ehci-uclk);
}
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(atmel_ehci-iclk);
+   clk_prepare_enable(atmel_ehci-fclk);
+   atmel_ehci-clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (!clocked)
+   if (!atmel_ehci-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
+   clk_disable_unprepare(atmel_ehci-fclk);
+   clk_disable_unprepare(atmel_ehci-iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(atmel_ehci-uclk);
+   atmel_ehci-clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, start\n);
-   atmel_start_clock();
+   atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, stop\n);
-   atmel_stop_clock();
+   atmel_stop_clock(atmel_ehci);
 }
 
 /*-*/
@@ -79,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+   struct atmel_ehci_priv *atmel_ehci;
int irq;
int retval;
 
@@ -109,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+   atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(pdev-dev, res);
@@ -120,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(pdev-dev, ehci_clk);
-   if (IS_ERR(iclk)) {
+   atmel_ehci-iclk = devm_clk_get(pdev-dev, ehci_clk);
+   if (IS_ERR(atmel_ehci-iclk)) {
dev_err(pdev-dev, Error getting interface clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
-   fclk = devm_clk_get(pdev-dev, uhpck);
-   if (IS_ERR(fclk)) {
+   atmel_ehci-fclk = devm_clk_get(pdev-dev, uhpck);
+   if (IS_ERR(atmel_ehci-fclk)) {
dev_err(pdev-dev, Error getting function clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   uclk = devm_clk_get(pdev-dev, usb_clk);
-   if (IS_ERR(uclk)) {
+   atmel_ehci-uclk = devm_clk_get(pdev-dev, usb_clk

[PATCHv4 0/3] USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus signal, stop clocks on falling edge of the Vbus signal

2015-01-20 Thread Sylvain Rochet
If USB PLL is not necessary for other USB drivers (e.g. OHCI and EHCI) 
reduce power consumption by switching off the USB PLL if no USB Host is 
currently connected to this USB Device.

Changes since v3:
  * Added stable tag for the first patch
  * As suggested, removed the unused check for udc-driver is not NULL in 
Vbus IRQ by requesting IRQ after udc-driver is set and by releasing 
IRQ before udc-driver is cleared
  * Rebased the core patch of this series against the just explained changes

Changes since v2:
  * Use spin_lock_irqsave/unlock_irqrestore instead of spin_lock/unlock in
threaded interrupt because we are not in irq context anymore
  * Removed useless and probably harmful IRQF_NO_SUSPEND from
devm_request_threaded_irq() flags

Changes since v1:
  * Using a threaded irq and mutex instead of spinclock as suggested
  * Moved a silently fixed bug in a separate patch (1/2)

Sylvain Rochet (3):
  USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state
  USB: gadget: atmel_usba_udc: Enable Vbus signal IRQ in UDC start
instead of UDC probe
  USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus
signal, stop clocks on falling edge of the Vbus signal

 drivers/usb/gadget/udc/atmel_usba_udc.c | 130 +---
 drivers/usb/gadget/udc/atmel_usba_udc.h |   4 +
 2 files changed, 89 insertions(+), 45 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv4 2/3] USB: gadget: atmel_usba_udc: Enable Vbus signal IRQ in UDC start instead of UDC probe

2015-01-20 Thread Sylvain Rochet
Vbus IRQ handler needs a started UDC driver to work because it uses
udc-driver, which is set by the UDC start handler. The previous way
chosen was to return from interrupt if udc-driver is NULL using a
spinlock.

This patch now request the Vbus signal IRQ in UDC start instead of UDC
probe and release the IRQ in UDC stop before udc-driver is set back to
NULL. This way we don't need the check about udc-driver in interruption
handler, therefore we don't need the spinlock as well anymore.

This was chosen against using set_irq_flags() to request a not auto
enabled IRQ (IRQF_NOAUTOEN flag) because set_irq_flags() can't change
just one flag, therefore it must be called with all flags, without
respecting what the AIC previously did. Naively copying IRQ flags
currently set by the AIC looked like error-prone if defaults flags
change at some point in the future.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Suggested-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 64 -
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index e207d75..546da63 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1729,10 +1729,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 
spin_lock(udc-lock);
 
-   /* May happen if Vbus pin toggles during probe() */
-   if (!udc-driver)
-   goto out;
-
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
@@ -1753,7 +1749,6 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
udc-vbus_prev = vbus;
}
 
-out:
spin_unlock(udc-lock);
 
return IRQ_HANDLED;
@@ -1767,23 +1762,27 @@ static int atmel_usba_start(struct usb_gadget *gadget,
unsigned long flags;
 
spin_lock_irqsave(udc-lock, flags);
-
udc-devstatus = 1  USB_DEVICE_SELF_POWERED;
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
ret = clk_prepare_enable(udc-pclk);
if (ret)
-   return ret;
+   goto err_pclk;
ret = clk_prepare_enable(udc-hclk);
-   if (ret) {
-   clk_disable_unprepare(udc-pclk);
-   return ret;
-   }
+   if (ret)
+   goto err_hclk;
 
udc-vbus_prev = 0;
-   if (gpio_is_valid(udc-vbus_pin))
-   enable_irq(gpio_to_irq(udc-vbus_pin));
+   if (gpio_is_valid(udc-vbus_pin)) {
+   ret = request_irq(gpio_to_irq(udc-vbus_pin),
+   usba_vbus_irq, 0,
+   atmel_usba_udc, udc);
+   if (ret) {
+   udc-vbus_pin = -ENODEV;
+   goto err;
+   }
+   }
 
/* If Vbus is present, enable the controller and wait for reset */
spin_lock_irqsave(udc-lock, flags);
@@ -1797,6 +1796,17 @@ static int atmel_usba_start(struct usb_gadget *gadget,
spin_unlock_irqrestore(udc-lock, flags);
 
return 0;
+
+err:
+   clk_disable_unprepare(udc-hclk);
+err_hclk:
+   clk_disable_unprepare(udc-pclk);
+err_pclk:
+   spin_lock_irqsave(udc-lock, flags);
+   udc-devstatus = ~(1  USB_DEVICE_SELF_POWERED);
+   udc-driver = NULL;
+   spin_unlock_irqrestore(udc-lock, flags);
+   return ret;
 }
 
 static int atmel_usba_stop(struct usb_gadget *gadget)
@@ -1805,7 +1815,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
unsigned long flags;
 
if (gpio_is_valid(udc-vbus_pin))
-   disable_irq(gpio_to_irq(udc-vbus_pin));
+   free_irq(gpio_to_irq(udc-vbus_pin), udc);
 
spin_lock_irqsave(udc-lock, flags);
udc-gadget.speed = USB_SPEED_UNKNOWN;
@@ -2047,24 +2057,14 @@ static int usba_udc_probe(struct platform_device *pdev)
}
udc-irq = irq;
 
-   if (gpio_is_valid(udc-vbus_pin)) {
-   if (!devm_gpio_request(pdev-dev, udc-vbus_pin, 
atmel_usba_udc)) {
-   ret = devm_request_irq(pdev-dev,
-   gpio_to_irq(udc-vbus_pin),
-   usba_vbus_irq, 0,
-   atmel_usba_udc, udc);
-   if (ret) {
-   udc-vbus_pin = -ENODEV;
-   dev_warn(udc-pdev-dev,
-failed to request vbus irq; 
-assuming always on\n);
-   } else {
-   disable_irq(gpio_to_irq(udc-vbus_pin));
-   }
-   } else {
-   /* gpio_request fail so use -EINVAL for gpio_is_valid */
-   udc-vbus_pin = -EINVAL

[PATCHv4 3/3] USB: gadget: atmel_usba_udc: Start clocks on rising edge of the Vbus signal, stop clocks on falling edge of the Vbus signal

2015-01-20 Thread Sylvain Rochet
If USB PLL is not necessary for other USB drivers (e.g. OHCI and EHCI)
it will reduce power consumption by switching off the USB PLL if no USB
Host is currently connected to this USB Device.

We are using Vbus GPIO signal to detect Host presence. If Vbus signal is
not available then the device stays continuously clocked.

Note this driver does not support suspend/resume yet, it may stay
clocked if USB Host is still connected when suspending. For what I need,
forbidding suspend from userland if we are still attached to an USB host
is fine, but we might as well add suspend/resume to this driver in the
future.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 86 -
 drivers/usb/gadget/udc/atmel_usba_udc.h |  4 ++
 2 files changed, 66 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 546da63..e05b16c 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -315,6 +315,37 @@ static inline void usba_cleanup_debugfs(struct usba_udc 
*udc)
 }
 #endif
 
+static int start_clock(struct usba_udc *udc)
+{
+   int ret;
+
+   if (udc-clocked)
+   return 0;
+
+   ret = clk_prepare_enable(udc-pclk);
+   if (ret)
+   return ret;
+   ret = clk_prepare_enable(udc-hclk);
+   if (ret) {
+   clk_disable_unprepare(udc-pclk);
+   return ret;
+   }
+
+   udc-clocked = true;
+   return 0;
+}
+
+static void stop_clock(struct usba_udc *udc)
+{
+   if (!udc-clocked)
+   return;
+
+   clk_disable_unprepare(udc-hclk);
+   clk_disable_unprepare(udc-pclk);
+
+   udc-clocked = false;
+}
+
 static int vbus_is_present(struct usba_udc *udc)
 {
if (gpio_is_valid(udc-vbus_pin))
@@ -1719,37 +1750,48 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
 }
 
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
+static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 {
struct usba_udc *udc = devid;
int vbus;
+   int ret;
+   unsigned long flags;
 
/* debounce */
udelay(10);
 
-   spin_lock(udc-lock);
+   mutex_lock(udc-vbus_mutex);
 
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
+   ret = start_clock(udc);
+   if (ret)
+   goto out;
+
+   spin_lock_irqsave(udc-lock, flags);
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+   spin_unlock_irqrestore(udc-lock, flags);
} else {
+   spin_lock_irqsave(udc-lock, flags);
udc-gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-   if (udc-driver-disconnect) {
-   spin_unlock(udc-lock);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   stop_clock(udc);
+
+   if (udc-driver-disconnect)
udc-driver-disconnect(udc-gadget);
-   spin_lock(udc-lock);
-   }
}
udc-vbus_prev = vbus;
}
 
-   spin_unlock(udc-lock);
+out:
+   mutex_unlock(udc-vbus_mutex);
 
return IRQ_HANDLED;
 }
@@ -1766,17 +1808,12 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
-   ret = clk_prepare_enable(udc-pclk);
-   if (ret)
-   goto err_pclk;
-   ret = clk_prepare_enable(udc-hclk);
-   if (ret)
-   goto err_hclk;
+   mutex_lock(udc-vbus_mutex);
 
udc-vbus_prev = 0;
if (gpio_is_valid(udc-vbus_pin)) {
-   ret = request_irq(gpio_to_irq(udc-vbus_pin),
-   usba_vbus_irq, 0,
+   ret = request_threaded_irq(gpio_to_irq(udc-vbus_pin), NULL,
+   usba_vbus_irq_thread, IRQF_ONESHOT,
atmel_usba_udc, udc);
if (ret) {
udc-vbus_pin = -ENODEV;
@@ -1785,23 +1822,24 @@ static int atmel_usba_start(struct usb_gadget *gadget,
}
 
/* If Vbus is present, enable the controller and wait for reset */
-   spin_lock_irqsave(udc-lock, flags);
if (vbus_is_present(udc)  udc-vbus_prev == 0) {
+   ret = start_clock(udc);
+   if (ret

[PATCHv4 1/3] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-01-20 Thread Sylvain Rochet
If vbus gpio is high at init, we should set vbus_prev to true
accordingly to the current vbus state. Without that, we skip the first
vbus interrupt because the saved vbus state is not consistent.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
Fixes: 914a3f3b3754 (USB: add atmel_usba_udc driver)
Cc: sta...@vger.kernel.org #2.6.24+
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index ce88237..e207d75 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1791,6 +1791,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+
+   udc-vbus_prev = 1;
}
spin_unlock_irqrestore(udc-lock, flags);
 
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 6/6] USB: host: ohci-at91: Fix wake-up support

2015-01-19 Thread Sylvain Rochet
This device needs to be continuously clocked to provide wake up support,
previously, if STANDBY target were chosen the device were
enable_irq_wake()-prepared and clock still active and if MEM target were
chosen the device were also enable_irq_wake()-prepared but not clocked
anymore, which is wrong.

Now, if STANDBY target is chosen the device is still clocked with wake
up support enabled, which were the previous default and if MEM target is
chosen the device is declocked with wake up support disabled.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 970a776..1fc5610 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -42,6 +42,7 @@ struct ohci_at91_priv {
struct clk *uclk;
struct clk *hclk;
bool clocked;
+   bool wakeup;/* Saved wake-up state for resume */
 };
 /* interface and function clocks; sometimes also an AHB clock */
 
@@ -61,6 +62,8 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
+   if (ohci_at91-clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(ohci_at91-uclk, 4800);
clk_prepare_enable(ohci_at91-uclk);
@@ -73,6 +76,8 @@ static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 
 static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
+   if (!ohci_at91-clocked)
+   return;
clk_disable_unprepare(ohci_at91-fclk);
clk_disable_unprepare(ohci_at91-iclk);
clk_disable_unprepare(ohci_at91-hclk);
@@ -614,15 +619,22 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
-   booldo_wakeup = device_may_wakeup(dev);
int ret;
 
-   if (do_wakeup)
+   /*
+* Disable wakeup if we are going to sleep with slow clock mode
+* enabled.
+*/
+   ohci_at91-wakeup = device_may_wakeup(dev)
+!at91_suspend_entering_slow_clock();
+
+   if (ohci_at91-wakeup)
enable_irq_wake(hcd-irq);
 
-   ret = ohci_suspend(hcd, do_wakeup);
+   ret = ohci_suspend(hcd, ohci_at91-wakeup);
if (ret) {
-   disable_irq_wake(hcd-irq);
+   if (ohci_at91-wakeup)
+   disable_irq_wake(hcd-irq);
return ret;
}
/*
@@ -632,7 +644,7 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
 *
 * REVISIT: some boards will be able to turn VBUS off...
 */
-   if (at91_suspend_entering_slow_clock()) {
+   if (!ohci_at91-wakeup) {
ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
ohci-hc_control = OHCI_CTRL_RWC;
ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
@@ -651,11 +663,10 @@ static int ohci_hcd_at91_drv_resume(struct device *dev)
struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
-   if (device_may_wakeup(dev))
+   if (ohci_at91-wakeup)
disable_irq_wake(hcd-irq);
 
-   if (!ohci_at91-clocked)
-   at91_start_clock(ohci_at91);
+   at91_start_clock(ohci_at91);
 
ohci_resume(hcd, false);
return 0;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 5/6] USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack initialisation

2015-01-19 Thread Sylvain Rochet
struct usb_hcd *hcd = NULL;
...
hcd = usb_create_hcd(driver, dev, at91);

This patch remove *hcd useless initialisation

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index c810917..970a776 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -142,7 +142,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
-   struct usb_hcd *hcd = NULL;
+   struct usb_hcd *hcd;
struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 4/6] USB: host: ohci-at91: Move global variables to private struct

2015-01-19 Thread Sylvain Rochet
This patch move AT91 OHCI global variables (clocks ptr and clocked
boolean) to private struct ohci_at91_priv, stored in ohci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 84 +++-
 1 file changed, 51 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 65e7836..c810917 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,16 @@
for ((index) = 0; (index)  AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) \
+   ((struct ohci_at91_priv *)hcd_to_ohci(h)-priv)
+
+struct ohci_at91_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   struct clk *hclk;
+   bool clocked;
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC OHCI Atmel driver
@@ -41,45 +50,49 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
 static const char hcd_name[] = ohci-atmel;
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct ohci_at91_priv),
+};
 
 extern int usb_disabled(void);
 
 /*-*/
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(ohci_at91-uclk, 4800);
+   clk_prepare_enable(ohci_at91-uclk);
}
-   clk_prepare_enable(hclk);
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(ohci_at91-hclk);
+   clk_prepare_enable(ohci_at91-iclk);
+   clk_prepare_enable(ohci_at91-fclk);
+   ohci_at91-clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
-   clk_disable_unprepare(hclk);
+   clk_disable_unprepare(ohci_at91-fclk);
+   clk_disable_unprepare(ohci_at91-iclk);
+   clk_disable_unprepare(ohci_at91-hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(ohci_at91-uclk);
+   ohci_at91-clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, start\n);
 
/*
 * Start the USB clocks.
 */
-   at91_start_clock();
+   at91_start_clock(ohci_at91);
 
/*
 * The USB host controller must remain in reset.
@@ -91,6 +104,7 @@ static void at91_stop_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, stop\n);
 
@@ -102,7 +116,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
 * Stop the USB clocks.
 */
-   at91_stop_clock();
+   at91_stop_clock(ohci_at91);
 }
 
 
@@ -129,6 +143,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct ohci_hcd *ohci;
int retval;
struct usb_hcd *hcd = NULL;
+   struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
int irq;
@@ -142,6 +157,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd = usb_create_hcd(driver, dev, at91);
if (!hcd)
return -ENOMEM;
+   ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(dev, res);
@@ -152,29 +168,29 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(dev, ohci_clk);
-   if (IS_ERR(iclk)) {
+   ohci_at91-iclk = devm_clk_get(dev, ohci_clk);
+   if (IS_ERR(ohci_at91-iclk)) {
dev_err(dev, failed to get ohci_clk\n);
-   retval = PTR_ERR(iclk);
+   retval = PTR_ERR(ohci_at91-iclk);
goto err;
}
-   fclk = devm_clk_get(dev, uhpck);
-   if (IS_ERR(fclk)) {
+   ohci_at91-fclk = devm_clk_get(dev, uhpck);
+   if (IS_ERR

[PATCHv6 0/6] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-19 Thread Sylvain Rochet
USB: host: Atmel OHCI and EHCI drivers improvements

Suspend/resume support for EHCI.
struct dev_pm_ops for OHCI.
Removed global variables from both.
Fixed OHCI wake up support for STANDBY(wake-up enabled) and MEM(wake-up
disabled) sleep targets.

Changes since v5:
  * Don't overwrite device wakeup flag with device_init_wakeup(),
now using a private wakeup bool instead.

Changes since v4:
  * Re-add at91_suspend_entering_slow_clock() to OHCI, we can't naively
remove this one, this device needs to be continuously clocked to
provide wake up support.
The removal of at91_suspend_entering_slow_clock() actually lighted up
an issue on wake up support, which is now fixed.

Changes since v3:
  * Using struct dev_pm_ops instead of static struct platform_driver
resume and suspend bindings for both EHCI and OHCI
  * Fixed inconsistency in patch subjects, _ intead of - for file names
  * Patch cleaning with the help of checkpatch.pl, fixed lines over
80 characters

Changes since v2:
  * Added patchs from an other submission, because this series
depended on this one
* EHCI: Move global variables to private struct
* OHCI: Move global variables to private struct
  * Using ohci-priv and ehci-priv instead of hcd-hcd_priv,
which were not the right way to do that

Changes since v1:
  * Don't use at91_suspend_entering_slow_clock() on EHCI,
we are trying to get read of this of this function
  * Removed at91_suspend_entering_slow_clock() from OHCI

Sylvain Rochet (6):
  USB: host: ehci-atmel: Add suspend/resume support
  USB: host: ohci-at91: Use struct dev_pm_ops instead of struct
platform_driver
  USB: host: ehci-atmel: Move global variables to private struct
  USB: host: ohci-at91: Move global variables to private struct
  USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack
initialisation
  USB: host: ohci-at91: Fix wake-up support

 drivers/usb/host/ehci-atmel.c | 102 +-
 drivers/usb/host/ohci-at91.c  | 126 ++
 2 files changed, 154 insertions(+), 74 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 3/6] USB: host: ehci-atmel: Move global variables to private struct

2015-01-19 Thread Sylvain Rochet
This patch move Atmel EHCI global variables (clocks ptr and clocked
boolean) to private struct atmel_ehci_priv, stored in ehci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 79 +++
 1 file changed, 50 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 5a15e3d..663f790 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,48 +27,66 @@
 #define DRIVER_DESC EHCI Atmel driver
 
 static const char hcd_name[] = ehci-atmel;
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) \
+   ((struct atmel_ehci_priv *)hcd_to_ehci(h)-priv)
+
+struct atmel_ehci_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
 
 /*-*/
 
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (clocked)
+   if (atmel_ehci-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(atmel_ehci-uclk, 4800);
+   clk_prepare_enable(atmel_ehci-uclk);
}
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(atmel_ehci-iclk);
+   clk_prepare_enable(atmel_ehci-fclk);
+   atmel_ehci-clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (!clocked)
+   if (!atmel_ehci-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
+   clk_disable_unprepare(atmel_ehci-fclk);
+   clk_disable_unprepare(atmel_ehci-iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(atmel_ehci-uclk);
+   atmel_ehci-clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, start\n);
-   atmel_start_clock();
+   atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, stop\n);
-   atmel_stop_clock();
+   atmel_stop_clock(atmel_ehci);
 }
 
 /*-*/
@@ -79,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+   struct atmel_ehci_priv *atmel_ehci;
int irq;
int retval;
 
@@ -109,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+   atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(pdev-dev, res);
@@ -120,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(pdev-dev, ehci_clk);
-   if (IS_ERR(iclk)) {
+   atmel_ehci-iclk = devm_clk_get(pdev-dev, ehci_clk);
+   if (IS_ERR(atmel_ehci-iclk)) {
dev_err(pdev-dev, Error getting interface clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
-   fclk = devm_clk_get(pdev-dev, uhpck);
-   if (IS_ERR(fclk)) {
+   atmel_ehci-fclk = devm_clk_get(pdev-dev, uhpck);
+   if (IS_ERR(atmel_ehci-fclk)) {
dev_err(pdev-dev, Error getting function clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   uclk = devm_clk_get(pdev-dev, usb_clk);
-   if (IS_ERR(uclk)) {
+   atmel_ehci-uclk = devm_clk_get(pdev-dev, usb_clk);
+   if (IS_ERR(atmel_ehci-uclk)) {
dev_err(pdev-dev, failed to get uclk\n);
-   retval = PTR_ERR

[PATCHv6 1/6] USB: host: ehci-atmel: Add suspend/resume support

2015-01-19 Thread Sylvain Rochet
This patch add suspend/resume support for Atmel EHCI, mostly
about disabling and unpreparing clocks so USB PLL is stopped
before entering sleep state.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..5a15e3d 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -37,6 +37,8 @@ static int clocked;
 
 static void atmel_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -48,6 +50,8 @@ static void atmel_start_clock(void)
 
 static void atmel_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
@@ -174,6 +178,29 @@ static int ehci_atmel_drv_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+   int ret;
+
+   ret = ehci_suspend(hcd, false);
+   if (ret)
+   return ret;
+
+   atmel_stop_clock();
+   return 0;
+}
+
+static int ehci_atmel_drv_resume(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+   atmel_start_clock();
+   return ehci_resume(hcd, false);
+}
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = atmel,at91sam9g45-ehci },
@@ -183,12 +210,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 #endif
 
+static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
+   ehci_atmel_drv_resume);
+
 static struct platform_driver ehci_atmel_driver = {
.probe  = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
.driver = {
.name   = atmel-ehci,
+   .pm = ehci_atmel_pm_ops,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv5 0/6] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-19 Thread Sylvain Rochet
Hello Nicolas,


On Mon, Jan 19, 2015 at 02:34:20PM +0100, Nicolas Ferre wrote:
 Le 18/01/2015 23:25, Sylvain Rochet a écrit :
  USB: host: Atmel OHCI and EHCI drivers improvements
  
  Suspend/resume support for EHCI.
  struct dev_pm_ops for OHCI.
  Removed global variables from both.
  Fixed OHCI wake up support for STANDBY(wake-up enabled) and MEM(wake-up 
  disabled) sleep targets.
 
 I'm okay with the whole series:
 Acked-by: Nicolas Ferre nicolas.fe...@atmel.com

Oops, you missed that, but there is a v6 I sent this morning, which 
fixes a small mistake I made in v5.


 Alan, It seems that Boris and Alexandre also add their tag to the 
 series already. Do you want us to collect them in a new series sent to 
 you?
 
 Sylvain,
 Thanks a lot for this nice series built at a high pace ;-)

Yeah, I have the feeling I messed up a little :-)

Anyway, v6 is fine, I hope.


 Even if I'm not sure to keep the separation between slow clock PM and
 normal PM on AT91 but more likely to use the slow clock for all the
 PM modes, let's go forward with this step for now. I mean, we will
 certainly rework this at91_suspend_entering_slow_clock() aspect in the
 future.

I agree, I discussed privately with Boris about that, this require a 
larger rework, lets only fix the OHCI wakeup bug for now.


Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv6 2/6] USB: host: ohci-at91: Use struct dev_pm_ops instead of struct platform_driver

2015-01-19 Thread Sylvain Rochet
This patch replace struct platform_driver.{resume,suspend} PM bindings
to a new struct dev_pm_ops.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 21 ++---
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..65e7836 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -593,11 +593,11 @@ static int ohci_hcd_at91_drv_remove(struct 
platform_device *pdev)
 #ifdef CONFIG_PM
 
 static int
-ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-   booldo_wakeup = device_may_wakeup(pdev-dev);
+   booldo_wakeup = device_may_wakeup(dev);
int ret;
 
if (do_wakeup)
@@ -629,11 +629,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, 
pm_message_t mesg)
return ret;
 }
 
-static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_at91_drv_resume(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
 
-   if (device_may_wakeup(pdev-dev))
+   if (device_may_wakeup(dev))
disable_irq_wake(hcd-irq);
 
if (!clocked)
@@ -642,19 +642,18 @@ static int ohci_hcd_at91_drv_resume(struct 
platform_device *pdev)
ohci_resume(hcd, false);
return 0;
 }
-#else
-#define ohci_hcd_at91_drv_suspend NULL
-#define ohci_hcd_at91_drv_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
+   ohci_hcd_at91_drv_resume);
+
 static struct platform_driver ohci_hcd_at91_driver = {
.probe  = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
-   .suspend= ohci_hcd_at91_drv_suspend,
-   .resume = ohci_hcd_at91_drv_resume,
.driver = {
.name   = at91_ohci,
+   .pm = ohci_hcd_at91_pm_ops,
.of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv3 2/2] USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

2015-01-19 Thread Sylvain Rochet
Hello Nicolas,


On Mon, Jan 19, 2015 at 05:55:18PM +0100, Nicolas Ferre wrote:
 Le 18/01/2015 18:24, Sylvain Rochet a écrit :
  Prepare_enable on rising edge, disable_unprepare on falling edge. Reduce

 Please re-write which edge we are talking about: ... falling edge of
 the Vbus signal for example.

  power consumption if USB PLL is not already necessary for OHCI or EHCI.

 Is a verb missing in the previous sentence?

  If USB host is not connected we can sleep with USB PLL stopped.
 
  This driver does not support suspend/resume yet, not suspending if we
  are still attached to an USB host is fine for what I need, this patch
  allow suspending with USB PLL stopped when USB device is not currently
  used.

 Can you please make it more clear. Several separated sentences seem
 necessary here.

Maybe :)


Proposal:

Start clocks on rising edge of the Vbus signal, stop clocks on 
falling edge of the Vbus signal.

If USB PLL is not necessary for other USB drivers (e.g. OHCI and EHCI) 
it will reduce power consumption by switching off the USB PLL if no USB 
Host is currently connected to this USB Device.

We are using Vbus GPIO signal to detect Host presence. If Vbus signal is 
not available then the device stay continuously clocked.

Note this driver does not support suspend/resume yet, it may stay 
clocked if USB Host is still connected when suspending. For what I need, 
forbidding suspend from userland if we are still attached to an USB host 
is fine, but we might as well add suspend/resume to this driver in the 
future.



  /* May happen if Vbus pin toggles during probe() */
  -   if (!udc-driver)
  +   spin_lock_irqsave(udc-lock, flags);
  +   if (!udc-driver) {
  +   spin_unlock_irqrestore(udc-lock, flags);
  goto out;
  +   }
  +   spin_unlock_irqrestore(udc-lock, flags);
 
 I'm not sure that the protection by spin_lock is needed above.

I'm not sure too, it was already in a spinlock area, I obviously kept it 
because it was not the purpose of this patch.

This seem to be in mirror of atmel_usba_start() which does:

  spin_lock_irqsave(udc-lock, flags);
  udc-devstatus = 1  USB_DEVICE_SELF_POWERED;
  udc-driver = driver;
  spin_unlock_irqrestore(udc-lock, flags);

… but vbus_pin IRQ is not yet enabled.


Same for atmel_usba_stop() which disable vbus_pin IRQ before setting 
udc-driver to NULL, but without spinlock this time (why?, this should 
be consistent IMHO).


I don't know if it is guaranteed that IRQ does not fire nor continue to 
run after disable_irq() returns, especially for threaded IRQ.


If the following sequence might happen:
  atmel_usba_stop()
disable_irq(vbus)
  usba_vbus_irq_thread() called lately
check for (!udc-driver) and continue
udc-driver = NULL;
if (udc-driver-disconnect)
 *CRASH*

Then the patch should be modified to protect udc-driver with the vbus 
mutex.

In this case the previous implementation wasn't perfect too, the 
atmel_usba_stop() does not lock around the NULLification of driver, 

Moreover the spinlock is (and was) unlocked in VBUS interrupt just 
before calling udc-driver-disconnect, which makes udc-driver actually 
not locked anywere.

If the previous sequence possible ?  If no, udc-driver does not need 
locking, if yes, it is currently not locked enough.


Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

2015-01-18 Thread Sylvain Rochet
Prepare_enable on rising edge, disable_unprepare on falling edge. Reduce
power consumption if USB PLL is not already necessary for OHCI or EHCI.
If USB host is not connected we can sleep with USB PLL stopped.

This driver does not support suspend/resume yet, not suspending if we
are still attached to an USB host is fine for what I need, this patch
allow suspending with USB PLL stopped when USB device is not currently
used.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 95 -
 drivers/usb/gadget/udc/atmel_usba_udc.h |  4 ++
 2 files changed, 73 insertions(+), 26 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index e207d75..986677b 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -315,6 +315,38 @@ static inline void usba_cleanup_debugfs(struct usba_udc 
*udc)
 }
 #endif
 
+static int start_clock(struct usba_udc *udc)
+{
+   int ret;
+
+   if (udc-clocked)
+   return 0;
+
+   ret = clk_prepare_enable(udc-pclk);
+   if (ret)
+   return ret;
+   ret = clk_prepare_enable(udc-hclk);
+   if (ret) {
+   clk_disable_unprepare(udc-pclk);
+   return ret;
+   }
+
+   udc-clocked = true;
+   return ret;
+}
+
+static int stop_clock(struct usba_udc *udc)
+{
+   if (!udc-clocked)
+   return 0;
+
+   clk_disable_unprepare(udc-hclk);
+   clk_disable_unprepare(udc-pclk);
+
+   udc-clocked = false;
+   return 0;
+}
+
 static int vbus_is_present(struct usba_udc *udc)
 {
if (gpio_is_valid(udc-vbus_pin))
@@ -1719,42 +1751,55 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
 }
 
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
+static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 {
struct usba_udc *udc = devid;
int vbus;
+   int ret;
 
/* debounce */
udelay(10);
 
-   spin_lock(udc-lock);
+   mutex_lock(udc-vbus_mutex);
 
/* May happen if Vbus pin toggles during probe() */
-   if (!udc-driver)
+   spin_lock(udc-lock);
+   if (!udc-driver) {
+   spin_unlock(udc-lock);
goto out;
+   }
+   spin_unlock(udc-lock);
 
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
+   ret = start_clock(udc);
+   if (ret)
+   goto out;
+
+   spin_lock(udc-lock);
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+   spin_unlock(udc-lock);
} else {
+   spin_lock(udc-lock);
udc-gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-   if (udc-driver-disconnect) {
-   spin_unlock(udc-lock);
+   spin_unlock(udc-lock);
+
+   stop_clock(udc);
+
+   if (udc-driver-disconnect)
udc-driver-disconnect(udc-gadget);
-   spin_lock(udc-lock);
-   }
}
udc-vbus_prev = vbus;
}
 
 out:
-   spin_unlock(udc-lock);
+   mutex_unlock(udc-vbus_mutex);
 
return IRQ_HANDLED;
 }
@@ -1762,7 +1807,7 @@ out:
 static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
 {
-   int ret;
+   int ret = 0;
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
 
@@ -1772,31 +1817,29 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
-   ret = clk_prepare_enable(udc-pclk);
-   if (ret)
-   return ret;
-   ret = clk_prepare_enable(udc-hclk);
-   if (ret) {
-   clk_disable_unprepare(udc-pclk);
-   return ret;
-   }
-
+   mutex_lock(udc-vbus_mutex);
udc-vbus_prev = 0;
if (gpio_is_valid(udc-vbus_pin))
enable_irq(gpio_to_irq(udc-vbus_pin));
 
/* If Vbus is present, enable the controller and wait for reset */
-   spin_lock_irqsave(udc-lock, flags);
if (vbus_is_present(udc)  udc-vbus_prev == 0) {
+   ret = start_clock(udc);
+   if (ret)
+   goto out;
+
+   spin_lock_irqsave(udc-lock, flags);
toggle_bias(1);
usba_writel(udc

[PATCHv2 1/2] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-01-18 Thread Sylvain Rochet
If vbus gpio is high at init, we should set vbus_prev to true
accordingly to the current vbus state. Without that, we skip the first
vbus interrupt because the saved vbus state is not consistent.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index ce88237..e207d75 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1791,6 +1791,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+
+   udc-vbus_prev = 1;
}
spin_unlock_irqrestore(udc-lock, flags);
 
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 0/2] USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

2015-01-18 Thread Sylvain Rochet
Prepare_enable on rising edge, disable_unprepare on falling edge. Reduce
power consumption if USB PLL is not already necessary for OHCI or EHCI.
If USB host is not connected we can sleep with USB PLL stopped.

This driver does not support suspend/resume yet, not suspending if we
are still attached to an USB host is fine for what I need, this patch
allow suspending with USB PLL stopped when USB device is not currently
used.

Change since v1:
  * Using a threaded irq and mutex instead of spinclock as suggested
  * Moved a silently fixed bug in a separate patch (1/2)

Sylvain Rochet (2):
  USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state
  USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

 drivers/usb/gadget/udc/atmel_usba_udc.c | 97 -
 drivers/usb/gadget/udc/atmel_usba_udc.h |  4 ++
 2 files changed, 75 insertions(+), 26 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv4 4/6] USB: host: ehci-atmel: Move global variables to private struct

2015-01-18 Thread Sylvain Rochet
This patch move Atmel EHCI global variables (clocks ptr and clocked
boolean) to private struct atmel_ehci_priv, stored in ehci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 79 +++
 1 file changed, 50 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 5a15e3d..663f790 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,48 +27,66 @@
 #define DRIVER_DESC EHCI Atmel driver
 
 static const char hcd_name[] = ehci-atmel;
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) \
+   ((struct atmel_ehci_priv *)hcd_to_ehci(h)-priv)
+
+struct atmel_ehci_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
 
 /*-*/
 
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (clocked)
+   if (atmel_ehci-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(atmel_ehci-uclk, 4800);
+   clk_prepare_enable(atmel_ehci-uclk);
}
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(atmel_ehci-iclk);
+   clk_prepare_enable(atmel_ehci-fclk);
+   atmel_ehci-clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (!clocked)
+   if (!atmel_ehci-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
+   clk_disable_unprepare(atmel_ehci-fclk);
+   clk_disable_unprepare(atmel_ehci-iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(atmel_ehci-uclk);
+   atmel_ehci-clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, start\n);
-   atmel_start_clock();
+   atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, stop\n);
-   atmel_stop_clock();
+   atmel_stop_clock(atmel_ehci);
 }
 
 /*-*/
@@ -79,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+   struct atmel_ehci_priv *atmel_ehci;
int irq;
int retval;
 
@@ -109,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+   atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(pdev-dev, res);
@@ -120,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(pdev-dev, ehci_clk);
-   if (IS_ERR(iclk)) {
+   atmel_ehci-iclk = devm_clk_get(pdev-dev, ehci_clk);
+   if (IS_ERR(atmel_ehci-iclk)) {
dev_err(pdev-dev, Error getting interface clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
-   fclk = devm_clk_get(pdev-dev, uhpck);
-   if (IS_ERR(fclk)) {
+   atmel_ehci-fclk = devm_clk_get(pdev-dev, uhpck);
+   if (IS_ERR(atmel_ehci-fclk)) {
dev_err(pdev-dev, Error getting function clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   uclk = devm_clk_get(pdev-dev, usb_clk);
-   if (IS_ERR(uclk)) {
+   atmel_ehci-uclk = devm_clk_get(pdev-dev, usb_clk);
+   if (IS_ERR(atmel_ehci-uclk)) {
dev_err(pdev-dev, failed to get uclk\n);
-   retval = PTR_ERR

[PATCHv4 6/6] USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack initialisation

2015-01-18 Thread Sylvain Rochet
struct usb_hcd *hcd = NULL;
...
hcd = usb_create_hcd(driver, dev, at91);

This patch remove *hcd useless initialisation

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 2e50d3b..8edc5df 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -146,7 +146,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
-   struct usb_hcd *hcd = NULL;
+   struct usb_hcd *hcd;
struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv4 0/6] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-18 Thread Sylvain Rochet
Suspend/resume support for EHCI.
struct dev_pm_ops for OHCI.
PLL stop for all sleep modes for OHCI.
Removed global variables from both.
Removed at91_suspend_entering_slow_clock() from both.

Changes since v3:
  * Using struct dev_pm_ops instead of static struct platform_driver
resume and suspend bindings for both EHCI and OHCI
  * Fixed inconsistency in patch subjects, _ intead of - for file names
  * Patch cleaning with the help of checkpatch.pl, fixed lines over
80 characters

Changes since v2:
  * Added patchs from an other submission, because this series
depended on this one
* EHCI: Move global variables to private struct
* OHCI: Move global variables to private struct
  * Using ohci-priv and ehci-priv instead of hcd-hcd_priv,
which were not the right way to do that

Changes since v1:
  * Don't use at91_suspend_entering_slow_clock() on EHCI,
we are trying to get read of this of this function
  * Removed at91_suspend_entering_slow_clock() from OHCI

Sylvain Rochet (6):
  USB: host: ehci-atmel: Add suspend/resume support
  USB: host: ohci-at91: Use struct dev_pm_ops instead of struct
platform_driver
  USB: host: ohci-at91: Stop/start USB PLL for all sleep modes
  USB: host: ehci-atmel: Move global variables to private struct
  USB: host: ohci-at91: Move global variables to private struct
  USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack
initialisation

 drivers/usb/host/ehci-atmel.c | 102 +-
 drivers/usb/host/ohci-at91.c  | 126 --
 2 files changed, 149 insertions(+), 79 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv4 3/6] USB: host: ohci-at91: Stop/start USB PLL for all sleep modes

2015-01-18 Thread Sylvain Rochet
Disable/unprepare clocks without testing the sleep target_state, removed
the at91_suspend_entering_slow_clock() call (which is only a
target_state == PM_SUSPEND_MEM).

Other kind of suspend now benefit from the power save induced by this
PLL deactivation. The resume penalty is about 500 us, which is not
negligible but acceptable considering the amount of power we are saving.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Reported-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/host/ohci-at91.c | 25 +
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 65e7836..79e343e 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -49,6 +49,8 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -61,6 +63,8 @@ static void at91_start_clock(void)
 
 static void at91_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
clk_disable_unprepare(hclk);
@@ -615,16 +619,14 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
 *
 * REVISIT: some boards will be able to turn VBUS off...
 */
-   if (at91_suspend_entering_slow_clock()) {
-   ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
-   ohci-hc_control = OHCI_CTRL_RWC;
-   ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
-   ohci-rh_state = OHCI_RH_HALTED;
-
-   /* flush the writes */
-   (void) ohci_readl (ohci, ohci-regs-control);
-   at91_stop_clock();
-   }
+   ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
+   ohci-hc_control = OHCI_CTRL_RWC;
+   ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
+   ohci-rh_state = OHCI_RH_HALTED;
+
+   /* flush the writes */
+   (void) ohci_readl (ohci, ohci-regs-control);
+   at91_stop_clock();
 
return ret;
 }
@@ -636,8 +638,7 @@ static int ohci_hcd_at91_drv_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(hcd-irq);
 
-   if (!clocked)
-   at91_start_clock();
+   at91_start_clock();
 
ohci_resume(hcd, false);
return 0;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv4 5/6] USB: host: ohci-at91: Move global variables to private struct

2015-01-18 Thread Sylvain Rochet
This patch move AT91 OHCI global variables (clocks ptr and clocked
boolean) to private struct ohci_at91_priv, stored in ohci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 86 ++--
 1 file changed, 52 insertions(+), 34 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 79e343e..2e50d3b 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,16 @@
for ((index) = 0; (index)  AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) \
+   ((struct ohci_at91_priv *)hcd_to_ohci(h)-priv)
+
+struct ohci_at91_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   struct clk *hclk;
+   bool clocked;
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC OHCI Atmel driver
@@ -41,49 +50,53 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
 static const char hcd_name[] = ohci-atmel;
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct ohci_at91_priv),
+};
 
 extern int usb_disabled(void);
 
 /*-*/
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
-   if (clocked)
+   if (ohci_at91-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(ohci_at91-uclk, 4800);
+   clk_prepare_enable(ohci_at91-uclk);
}
-   clk_prepare_enable(hclk);
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(ohci_at91-hclk);
+   clk_prepare_enable(ohci_at91-iclk);
+   clk_prepare_enable(ohci_at91-fclk);
+   ohci_at91-clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-   if (!clocked)
+   if (!ohci_at91-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
-   clk_disable_unprepare(hclk);
+   clk_disable_unprepare(ohci_at91-fclk);
+   clk_disable_unprepare(ohci_at91-iclk);
+   clk_disable_unprepare(ohci_at91-hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(ohci_at91-uclk);
+   ohci_at91-clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, start\n);
 
/*
 * Start the USB clocks.
 */
-   at91_start_clock();
+   at91_start_clock(ohci_at91);
 
/*
 * The USB host controller must remain in reset.
@@ -95,6 +108,7 @@ static void at91_stop_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, stop\n);
 
@@ -106,7 +120,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
 * Stop the USB clocks.
 */
-   at91_stop_clock();
+   at91_stop_clock(ohci_at91);
 }
 
 
@@ -133,6 +147,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct ohci_hcd *ohci;
int retval;
struct usb_hcd *hcd = NULL;
+   struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
int irq;
@@ -146,6 +161,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd = usb_create_hcd(driver, dev, at91);
if (!hcd)
return -ENOMEM;
+   ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(dev, res);
@@ -156,29 +172,29 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(dev, ohci_clk);
-   if (IS_ERR(iclk)) {
+   ohci_at91-iclk = devm_clk_get(dev, ohci_clk);
+   if (IS_ERR(ohci_at91-iclk)) {
dev_err(dev, failed to get ohci_clk\n);
-   retval = PTR_ERR(iclk);
+   retval = PTR_ERR(ohci_at91-iclk);
goto err

[PATCHv4 2/6] USB: host: ohci-at91: Use struct dev_pm_ops instead of struct platform_driver

2015-01-18 Thread Sylvain Rochet
This patch replace struct platform_driver.{resume,suspend} PM bindings
to a new struct dev_pm_ops.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 21 ++---
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..65e7836 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -593,11 +593,11 @@ static int ohci_hcd_at91_drv_remove(struct 
platform_device *pdev)
 #ifdef CONFIG_PM
 
 static int
-ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-   booldo_wakeup = device_may_wakeup(pdev-dev);
+   booldo_wakeup = device_may_wakeup(dev);
int ret;
 
if (do_wakeup)
@@ -629,11 +629,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, 
pm_message_t mesg)
return ret;
 }
 
-static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_at91_drv_resume(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
 
-   if (device_may_wakeup(pdev-dev))
+   if (device_may_wakeup(dev))
disable_irq_wake(hcd-irq);
 
if (!clocked)
@@ -642,19 +642,18 @@ static int ohci_hcd_at91_drv_resume(struct 
platform_device *pdev)
ohci_resume(hcd, false);
return 0;
 }
-#else
-#define ohci_hcd_at91_drv_suspend NULL
-#define ohci_hcd_at91_drv_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
+   ohci_hcd_at91_drv_resume);
+
 static struct platform_driver ohci_hcd_at91_driver = {
.probe  = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
-   .suspend= ohci_hcd_at91_drv_suspend,
-   .resume = ohci_hcd_at91_drv_resume,
.driver = {
.name   = at91_ohci,
+   .pm = ohci_hcd_at91_pm_ops,
.of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv4 1/6] USB: host: ehci-atmel: Add suspend/resume support

2015-01-18 Thread Sylvain Rochet
This patch add suspend/resume support for Atmel EHCI, mostly
about disabling and unpreparing clocks so USB PLL is stopped
before entering sleep state.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..5a15e3d 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -37,6 +37,8 @@ static int clocked;
 
 static void atmel_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -48,6 +50,8 @@ static void atmel_start_clock(void)
 
 static void atmel_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
@@ -174,6 +178,29 @@ static int ehci_atmel_drv_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+   int ret;
+
+   ret = ehci_suspend(hcd, false);
+   if (ret)
+   return ret;
+
+   atmel_stop_clock();
+   return 0;
+}
+
+static int ehci_atmel_drv_resume(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+   atmel_start_clock();
+   return ehci_resume(hcd, false);
+}
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = atmel,at91sam9g45-ehci },
@@ -183,12 +210,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 #endif
 
+static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
+   ehci_atmel_drv_resume);
+
 static struct platform_driver ehci_atmel_driver = {
.probe  = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
.driver = {
.name   = atmel-ehci,
+   .pm = ehci_atmel_pm_ops,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv3 0/5] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-18 Thread Sylvain Rochet
Hello Alan,

On Sun, Jan 18, 2015 at 12:20:49PM -0500, Alan Stern wrote:
 On Sat, 17 Jan 2015, Sylvain Rochet wrote:
 
  Sylvain Rochet (5):
USB: host: ehci_atmel: Add suspend/resume support
USB: host: ohci_at91: Stop/start USB PLL for all sleep modes
USB: host: ehci_atmel: Move global variables to private struct
USB: host: ohci_at91: Move global variables to private struct
USB: host: ohci_at91: usb_hcd_at91_probe(), remove useless stack
  initialisation
  
   drivers/usb/host/ehci-atmel.c | 102 
  +++--
   drivers/usb/host/ohci-at91.c  | 104 
  +-
   2 files changed, 138 insertions(+), 68 deletions(-)
 
 These patches look pretty good to me.  Have you run them through 
 checkpatch.pl?

Just did, fixed some lines over 80 characters + Sergei suggestion about 
using struct dev_pm_ops instead of struct platform_driver.{resume,suspend}.

Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 1/2] USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state

2015-01-18 Thread Sylvain Rochet
If vbus gpio is high at init, we should set vbus_prev to true
accordingly to the current vbus state. Without that, we skip the first
vbus interrupt because the saved vbus state is not consistent.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index ce88237..e207d75 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1791,6 +1791,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+
+   udc-vbus_prev = 1;
}
spin_unlock_irqrestore(udc-lock, flags);
 
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 2/2] USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

2015-01-18 Thread Sylvain Rochet
Prepare_enable on rising edge, disable_unprepare on falling edge. Reduce
power consumption if USB PLL is not already necessary for OHCI or EHCI.
If USB host is not connected we can sleep with USB PLL stopped.

This driver does not support suspend/resume yet, not suspending if we
are still attached to an USB host is fine for what I need, this patch
allow suspending with USB PLL stopped when USB device is not currently
used.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/gadget/udc/atmel_usba_udc.c | 96 -
 drivers/usb/gadget/udc/atmel_usba_udc.h |  4 ++
 2 files changed, 74 insertions(+), 26 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c 
b/drivers/usb/gadget/udc/atmel_usba_udc.c
index e207d75..9cce50a 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -315,6 +315,38 @@ static inline void usba_cleanup_debugfs(struct usba_udc 
*udc)
 }
 #endif
 
+static int start_clock(struct usba_udc *udc)
+{
+   int ret;
+
+   if (udc-clocked)
+   return 0;
+
+   ret = clk_prepare_enable(udc-pclk);
+   if (ret)
+   return ret;
+   ret = clk_prepare_enable(udc-hclk);
+   if (ret) {
+   clk_disable_unprepare(udc-pclk);
+   return ret;
+   }
+
+   udc-clocked = true;
+   return ret;
+}
+
+static int stop_clock(struct usba_udc *udc)
+{
+   if (!udc-clocked)
+   return 0;
+
+   clk_disable_unprepare(udc-hclk);
+   clk_disable_unprepare(udc-pclk);
+
+   udc-clocked = false;
+   return 0;
+}
+
 static int vbus_is_present(struct usba_udc *udc)
 {
if (gpio_is_valid(udc-vbus_pin))
@@ -1719,42 +1751,56 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
 }
 
-static irqreturn_t usba_vbus_irq(int irq, void *devid)
+static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 {
struct usba_udc *udc = devid;
int vbus;
+   int ret;
+   unsigned long flags;
 
/* debounce */
udelay(10);
 
-   spin_lock(udc-lock);
+   mutex_lock(udc-vbus_mutex);
 
/* May happen if Vbus pin toggles during probe() */
-   if (!udc-driver)
+   spin_lock_irqsave(udc-lock, flags);
+   if (!udc-driver) {
+   spin_unlock_irqrestore(udc-lock, flags);
goto out;
+   }
+   spin_unlock_irqrestore(udc-lock, flags);
 
vbus = vbus_is_present(udc);
if (vbus != udc-vbus_prev) {
if (vbus) {
+   ret = start_clock(udc);
+   if (ret)
+   goto out;
+
+   spin_lock_irqsave(udc-lock, flags);
toggle_bias(1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+   spin_unlock_irqrestore(udc-lock, flags);
} else {
+   spin_lock_irqsave(udc-lock, flags);
udc-gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-   if (udc-driver-disconnect) {
-   spin_unlock(udc-lock);
+   spin_unlock_irqrestore(udc-lock, flags);
+
+   stop_clock(udc);
+
+   if (udc-driver-disconnect)
udc-driver-disconnect(udc-gadget);
-   spin_lock(udc-lock);
-   }
}
udc-vbus_prev = vbus;
}
 
 out:
-   spin_unlock(udc-lock);
+   mutex_unlock(udc-vbus_mutex);
 
return IRQ_HANDLED;
 }
@@ -1762,7 +1808,7 @@ out:
 static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
 {
-   int ret;
+   int ret = 0;
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
 
@@ -1772,31 +1818,29 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc-driver = driver;
spin_unlock_irqrestore(udc-lock, flags);
 
-   ret = clk_prepare_enable(udc-pclk);
-   if (ret)
-   return ret;
-   ret = clk_prepare_enable(udc-hclk);
-   if (ret) {
-   clk_disable_unprepare(udc-pclk);
-   return ret;
-   }
-
+   mutex_lock(udc-vbus_mutex);
udc-vbus_prev = 0;
if (gpio_is_valid(udc-vbus_pin))
enable_irq(gpio_to_irq(udc-vbus_pin));
 
/* If Vbus is present, enable the controller and wait for reset */
-   spin_lock_irqsave(udc-lock, flags);
if (vbus_is_present(udc)  udc-vbus_prev == 0) {
+   ret = start_clock(udc);
+   if (ret

[PATCHv3 0/2] USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

2015-01-18 Thread Sylvain Rochet
Prepare_enable on rising edge, disable_unprepare on falling edge. Reduce
power consumption if USB PLL is not already necessary for OHCI or EHCI.
If USB host is not connected we can sleep with USB PLL stopped.

This driver does not support suspend/resume yet, not suspending if we
are still attached to an USB host is fine for what I need, this patch
allow suspending with USB PLL stopped when USB device is not currently
used.

Changes since v2:
  * Use spin_lock_irqsave/unlock_irqrestore instead of spin_lock/unlock in
threaded interrupt because we are not in irq context anymore
  * Removed useless and probably harmful IRQF_NO_SUSPEND from
devm_request_threaded_irq() flags

Changes since v1:
  * Using a threaded irq and mutex instead of spinclock as suggested
  * Moved a silently fixed bug in a separate patch (1/2)

Sylvain Rochet (2):
  USB: gadget: atmel_usba_udc: Fixed vbus_prev initial state
  USB: gadget: atmel_usba_udc: Enable/disable USB PLL on Vbus change

 drivers/usb/gadget/udc/atmel_usba_udc.c | 98 -
 drivers/usb/gadget/udc/atmel_usba_udc.h |  4 ++
 2 files changed, 76 insertions(+), 26 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 0/6] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-18 Thread Sylvain Rochet
USB: host: Atmel OHCI and EHCI drivers improvements

Suspend/resume support for EHCI.
struct dev_pm_ops for OHCI.
Removed global variables from both.
Fixed OHCI wake up support for STANDBY(wake-up enabled) and MEM(wake-up 
disabled) sleep targets.

Changes since v4:
  * Re-add at91_suspend_entering_slow_clock() to OHCI, we can't naively
remove this one, this device needs to be continuously clocked to
provide wake up support.
The removal of at91_suspend_entering_slow_clock() actually lighted up
an issue on wake up support, which is now fixed.

Changes since v3:
  * Using struct dev_pm_ops instead of static struct platform_driver
resume and suspend bindings for both EHCI and OHCI
  * Fixed inconsistency in patch subjects, _ intead of - for file names
  * Patch cleaning with the help of checkpatch.pl, fixed lines over
80 characters

Changes since v2:
  * Added patchs from an other submission, because this series
depended on this one
* EHCI: Move global variables to private struct
* OHCI: Move global variables to private struct
  * Using ohci-priv and ehci-priv instead of hcd-hcd_priv,
which were not the right way to do that

Changes since v1:
  * Don't use at91_suspend_entering_slow_clock() on EHCI,
we are trying to get read of this of this function
  * Removed at91_suspend_entering_slow_clock() from OHCI

Sylvain Rochet (6):
  USB: host: ehci-atmel: Add suspend/resume support
  USB: host: ohci-at91: Use struct dev_pm_ops instead of struct
platform_driver
  USB: host: ehci-atmel: Move global variables to private struct
  USB: host: ohci-at91: Fix wake-up support
  USB: host: ohci-at91: Move global variables to private struct
  USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack
initialisation

 drivers/usb/host/ehci-atmel.c | 102 ++-
 drivers/usb/host/ohci-at91.c  | 120 +-
 2 files changed, 150 insertions(+), 72 deletions(-)

-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 3/6] USB: host: ehci-atmel: Move global variables to private struct

2015-01-18 Thread Sylvain Rochet
This patch move Atmel EHCI global variables (clocks ptr and clocked
boolean) to private struct atmel_ehci_priv, stored in ehci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 79 +++
 1 file changed, 50 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 5a15e3d..663f790 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,48 +27,66 @@
 #define DRIVER_DESC EHCI Atmel driver
 
 static const char hcd_name[] = ehci-atmel;
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) \
+   ((struct atmel_ehci_priv *)hcd_to_ehci(h)-priv)
+
+struct atmel_ehci_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
 
 /*-*/
 
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (clocked)
+   if (atmel_ehci-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(atmel_ehci-uclk, 4800);
+   clk_prepare_enable(atmel_ehci-uclk);
}
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(atmel_ehci-iclk);
+   clk_prepare_enable(atmel_ehci-fclk);
+   atmel_ehci-clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (!clocked)
+   if (!atmel_ehci-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
+   clk_disable_unprepare(atmel_ehci-fclk);
+   clk_disable_unprepare(atmel_ehci-iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(atmel_ehci-uclk);
+   atmel_ehci-clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, start\n);
-   atmel_start_clock();
+   atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, stop\n);
-   atmel_stop_clock();
+   atmel_stop_clock(atmel_ehci);
 }
 
 /*-*/
@@ -79,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+   struct atmel_ehci_priv *atmel_ehci;
int irq;
int retval;
 
@@ -109,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+   atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(pdev-dev, res);
@@ -120,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(pdev-dev, ehci_clk);
-   if (IS_ERR(iclk)) {
+   atmel_ehci-iclk = devm_clk_get(pdev-dev, ehci_clk);
+   if (IS_ERR(atmel_ehci-iclk)) {
dev_err(pdev-dev, Error getting interface clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
-   fclk = devm_clk_get(pdev-dev, uhpck);
-   if (IS_ERR(fclk)) {
+   atmel_ehci-fclk = devm_clk_get(pdev-dev, uhpck);
+   if (IS_ERR(atmel_ehci-fclk)) {
dev_err(pdev-dev, Error getting function clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   uclk = devm_clk_get(pdev-dev, usb_clk);
-   if (IS_ERR(uclk)) {
+   atmel_ehci-uclk = devm_clk_get(pdev-dev, usb_clk);
+   if (IS_ERR(atmel_ehci-uclk)) {
dev_err(pdev-dev, failed to get uclk\n);
-   retval = PTR_ERR

[PATCHv5 1/6] USB: host: ehci-atmel: Add suspend/resume support

2015-01-18 Thread Sylvain Rochet
This patch add suspend/resume support for Atmel EHCI, mostly
about disabling and unpreparing clocks so USB PLL is stopped
before entering sleep state.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..5a15e3d 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -37,6 +37,8 @@ static int clocked;
 
 static void atmel_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -48,6 +50,8 @@ static void atmel_start_clock(void)
 
 static void atmel_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
@@ -174,6 +178,29 @@ static int ehci_atmel_drv_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+   int ret;
+
+   ret = ehci_suspend(hcd, false);
+   if (ret)
+   return ret;
+
+   atmel_stop_clock();
+   return 0;
+}
+
+static int ehci_atmel_drv_resume(struct device *dev)
+{
+   struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+   atmel_start_clock();
+   return ehci_resume(hcd, false);
+}
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = atmel,at91sam9g45-ehci },
@@ -183,12 +210,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 #endif
 
+static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
+   ehci_atmel_drv_resume);
+
 static struct platform_driver ehci_atmel_driver = {
.probe  = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
.driver = {
.name   = atmel-ehci,
+   .pm = ehci_atmel_pm_ops,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 5/6] USB: host: ohci-at91: Move global variables to private struct

2015-01-18 Thread Sylvain Rochet
This patch move AT91 OHCI global variables (clocks ptr and clocked
boolean) to private struct ohci_at91_priv, stored in ohci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 86 ++--
 1 file changed, 52 insertions(+), 34 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 2738352..e1d0a75 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,16 @@
for ((index) = 0; (index)  AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) \
+   ((struct ohci_at91_priv *)hcd_to_ohci(h)-priv)
+
+struct ohci_at91_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   struct clk *hclk;
+   bool clocked;
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC OHCI Atmel driver
@@ -41,49 +50,53 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
 static const char hcd_name[] = ohci-atmel;
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct ohci_at91_priv),
+};
 
 extern int usb_disabled(void);
 
 /*-*/
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
-   if (clocked)
+   if (ohci_at91-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(ohci_at91-uclk, 4800);
+   clk_prepare_enable(ohci_at91-uclk);
}
-   clk_prepare_enable(hclk);
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(ohci_at91-hclk);
+   clk_prepare_enable(ohci_at91-iclk);
+   clk_prepare_enable(ohci_at91-fclk);
+   ohci_at91-clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-   if (!clocked)
+   if (!ohci_at91-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
-   clk_disable_unprepare(hclk);
+   clk_disable_unprepare(ohci_at91-fclk);
+   clk_disable_unprepare(ohci_at91-iclk);
+   clk_disable_unprepare(ohci_at91-hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(ohci_at91-uclk);
+   ohci_at91-clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, start\n);
 
/*
 * Start the USB clocks.
 */
-   at91_start_clock();
+   at91_start_clock(ohci_at91);
 
/*
 * The USB host controller must remain in reset.
@@ -95,6 +108,7 @@ static void at91_stop_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, stop\n);
 
@@ -106,7 +120,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
 * Stop the USB clocks.
 */
-   at91_stop_clock();
+   at91_stop_clock(ohci_at91);
 }
 
 
@@ -133,6 +147,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct ohci_hcd *ohci;
int retval;
struct usb_hcd *hcd = NULL;
+   struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
int irq;
@@ -146,6 +161,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd = usb_create_hcd(driver, dev, at91);
if (!hcd)
return -ENOMEM;
+   ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(dev, res);
@@ -156,29 +172,29 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(dev, ohci_clk);
-   if (IS_ERR(iclk)) {
+   ohci_at91-iclk = devm_clk_get(dev, ohci_clk);
+   if (IS_ERR(ohci_at91-iclk)) {
dev_err(dev, failed to get ohci_clk\n);
-   retval = PTR_ERR(iclk);
+   retval = PTR_ERR(ohci_at91-iclk);
goto err

[PATCHv5 6/6] USB: host: ohci-at91: usb_hcd_at91_probe(), remove useless stack initialisation

2015-01-18 Thread Sylvain Rochet
struct usb_hcd *hcd = NULL;
...
hcd = usb_create_hcd(driver, dev, at91);

This patch remove *hcd useless initialisation

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index e1d0a75..bb53231 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -146,7 +146,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
-   struct usb_hcd *hcd = NULL;
+   struct usb_hcd *hcd;
struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 2/6] USB: host: ohci-at91: Use struct dev_pm_ops instead of struct platform_driver

2015-01-18 Thread Sylvain Rochet
This patch replace struct platform_driver.{resume,suspend} PM bindings
to a new struct dev_pm_ops.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 21 ++---
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..65e7836 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -593,11 +593,11 @@ static int ohci_hcd_at91_drv_remove(struct 
platform_device *pdev)
 #ifdef CONFIG_PM
 
 static int
-ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-   booldo_wakeup = device_may_wakeup(pdev-dev);
+   booldo_wakeup = device_may_wakeup(dev);
int ret;
 
if (do_wakeup)
@@ -629,11 +629,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, 
pm_message_t mesg)
return ret;
 }
 
-static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_at91_drv_resume(struct device *dev)
 {
-   struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+   struct usb_hcd  *hcd = dev_get_drvdata(dev);
 
-   if (device_may_wakeup(pdev-dev))
+   if (device_may_wakeup(dev))
disable_irq_wake(hcd-irq);
 
if (!clocked)
@@ -642,19 +642,18 @@ static int ohci_hcd_at91_drv_resume(struct 
platform_device *pdev)
ohci_resume(hcd, false);
return 0;
 }
-#else
-#define ohci_hcd_at91_drv_suspend NULL
-#define ohci_hcd_at91_drv_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
+   ohci_hcd_at91_drv_resume);
+
 static struct platform_driver ohci_hcd_at91_driver = {
.probe  = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
-   .suspend= ohci_hcd_at91_drv_suspend,
-   .resume = ohci_hcd_at91_drv_resume,
.driver = {
.name   = at91_ohci,
+   .pm = ohci_hcd_at91_pm_ops,
.of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv5 4/6] USB: host: ohci-at91: Fix wake-up support

2015-01-18 Thread Sylvain Rochet
This device needs to be continuously clocked to provide wake up support,
previously, if STANDBY target were chosen the device were
enable_irq_wake()-prepared and clock still active and if MEM target were
chosen the device were also enable_irq_wake()-prepared but not clocked
anymore, which is wrong.

Now, if STANDBY target is chosen the device is still clocked with wake
up support enabled, which were the previous default and if MEM target is
chosen the device is declocked with wake up support disabled.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 19 ++-
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 65e7836..2738352 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -49,6 +49,8 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -61,6 +63,8 @@ static void at91_start_clock(void)
 
 static void at91_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
clk_disable_unprepare(hclk);
@@ -597,15 +601,20 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
 {
struct usb_hcd  *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-   booldo_wakeup = device_may_wakeup(dev);
+   booldo_wakeup;
int ret;
 
+   if (at91_suspend_entering_slow_clock())
+   device_init_wakeup(dev, 0);
+
+   do_wakeup = device_may_wakeup(dev);
if (do_wakeup)
enable_irq_wake(hcd-irq);
 
ret = ohci_suspend(hcd, do_wakeup);
if (ret) {
-   disable_irq_wake(hcd-irq);
+   if (do_wakeup)
+   disable_irq_wake(hcd-irq);
return ret;
}
/*
@@ -615,7 +624,7 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
 *
 * REVISIT: some boards will be able to turn VBUS off...
 */
-   if (at91_suspend_entering_slow_clock()) {
+   if (!do_wakeup) {
ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
ohci-hc_control = OHCI_CTRL_RWC;
ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
@@ -635,9 +644,9 @@ static int ohci_hcd_at91_drv_resume(struct device *dev)
 
if (device_may_wakeup(dev))
disable_irq_wake(hcd-irq);
+   device_init_wakeup(dev, 1);
 
-   if (!clocked)
-   at91_start_clock();
+   at91_start_clock();
 
ohci_resume(hcd, false);
return 0;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv4 3/6] USB: host: ohci-at91: Stop/start USB PLL for all sleep modes

2015-01-18 Thread Sylvain Rochet
Hello,

On Sun, Jan 18, 2015 at 08:36:03PM +0100, Sylvain Rochet wrote:
 Disable/unprepare clocks without testing the sleep target_state, removed
 the at91_suspend_entering_slow_clock() call (which is only a
 target_state == PM_SUSPEND_MEM).
 
 Other kind of suspend now benefit from the power save induced by this
 PLL deactivation. The resume penalty is about 500 us, which is not
 negligible but acceptable considering the amount of power we are saving.

Well, this patch actually lights up a previous issue on wake up support.

This device needs to be continuously clocked to provide wake up support, 
previously, if STANDBY target were chosen the device were 
enable_irq_wake-prepared and clock still active and if MEM target were 
chosen the device were also enable_irq_wake-prepared but not clocked 
anymore, which is wrong, but not so wrong.

This patch actually breaks wake up support for STANDBY sleep target. I 
am going to propose a v5 which reinitiate at91_suspend_entering_slow_clock()
and fix wake up support on this driver.

Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 3/5] USB: host: ehci_atmel: Move global variables to private struct

2015-01-17 Thread Sylvain Rochet
This patch move Atmel EHCI global variables (clocks ptr and clocked
boolean) to private struct atmel_ehci_priv, stored in ehci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 78 +++
 1 file changed, 49 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 2e0043b..eb0924f 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,48 +27,65 @@
 #define DRIVER_DESC EHCI Atmel driver
 
 static const char hcd_name[] = ehci-atmel;
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) ((struct atmel_ehci_priv 
*)hcd_to_ehci(h)-priv)
+
+struct atmel_ehci_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
 
 /*-*/
 
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (clocked)
+   if (atmel_ehci-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(atmel_ehci-uclk, 4800);
+   clk_prepare_enable(atmel_ehci-uclk);
}
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(atmel_ehci-iclk);
+   clk_prepare_enable(atmel_ehci-fclk);
+   atmel_ehci-clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-   if (!clocked)
+   if (!atmel_ehci-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
+   clk_disable_unprepare(atmel_ehci-fclk);
+   clk_disable_unprepare(atmel_ehci-iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(atmel_ehci-uclk);
+   atmel_ehci-clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, start\n);
-   atmel_start_clock();
+   atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(pdev-dev, stop\n);
-   atmel_stop_clock();
+   atmel_stop_clock(atmel_ehci);
 }
 
 /*-*/
@@ -79,6 +96,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+   struct atmel_ehci_priv *atmel_ehci;
int irq;
int retval;
 
@@ -109,6 +127,7 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+   atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(pdev-dev, res);
@@ -120,23 +139,23 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(pdev-dev, ehci_clk);
-   if (IS_ERR(iclk)) {
+   atmel_ehci-iclk = devm_clk_get(pdev-dev, ehci_clk);
+   if (IS_ERR(atmel_ehci-iclk)) {
dev_err(pdev-dev, Error getting interface clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
-   fclk = devm_clk_get(pdev-dev, uhpck);
-   if (IS_ERR(fclk)) {
+   atmel_ehci-fclk = devm_clk_get(pdev-dev, uhpck);
+   if (IS_ERR(atmel_ehci-fclk)) {
dev_err(pdev-dev, Error getting function clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   uclk = devm_clk_get(pdev-dev, usb_clk);
-   if (IS_ERR(uclk)) {
+   atmel_ehci-uclk = devm_clk_get(pdev-dev, usb_clk);
+   if (IS_ERR(atmel_ehci-uclk)) {
dev_err(pdev-dev, failed to get uclk\n);
-   retval = PTR_ERR(uclk

[PATCHv3 0/5] USB: host: Atmel OHCI and EHCI drivers improvements

2015-01-17 Thread Sylvain Rochet
Sylvain Rochet (5):
  USB: host: ehci_atmel: Add suspend/resume support
  USB: host: ohci_at91: Stop/start USB PLL for all sleep modes
  USB: host: ehci_atmel: Move global variables to private struct
  USB: host: ohci_at91: Move global variables to private struct
  USB: host: ohci_at91: usb_hcd_at91_probe(), remove useless stack
initialisation

 drivers/usb/host/ehci-atmel.c | 102 +++--
 drivers/usb/host/ohci-at91.c  | 104 +-
 2 files changed, 138 insertions(+), 68 deletions(-)

-- 
2.1.4
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 5/5] USB: host: ohci_at91: usb_hcd_at91_probe(), remove useless stack initialisation

2015-01-17 Thread Sylvain Rochet
struct usb_hcd *hcd = NULL;
...
hcd = usb_create_hcd(driver, dev, at91);

This patch remove *hcd useless initialisation

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index ab39b94..7e37657 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -145,7 +145,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
-   struct usb_hcd *hcd = NULL;
+   struct usb_hcd *hcd;
struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 4/5] USB: host: ohci_at91: Move global variables to private struct

2015-01-17 Thread Sylvain Rochet
This patch move AT91 OHCI global variables (clocks ptr and clocked
boolean) to private struct ohci_at91_priv, stored in ohci-priv.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 85 ++--
 1 file changed, 51 insertions(+), 34 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index f0da734..ab39b94 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,15 @@
for ((index) = 0; (index)  AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) ((struct ohci_at91_priv 
*)hcd_to_ohci(h)-priv)
+
+struct ohci_at91_priv {
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   struct clk *hclk;
+   bool clocked;
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC OHCI Atmel driver
@@ -41,49 +49,53 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
 static const char hcd_name[] = ohci-atmel;
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst 
= {
+   .extra_priv_size = sizeof(struct ohci_at91_priv),
+};
 
 extern int usb_disabled(void);
 
 /*-*/
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
-   if (clocked)
+   if (ohci_at91-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(ohci_at91-uclk, 4800);
+   clk_prepare_enable(ohci_at91-uclk);
}
-   clk_prepare_enable(hclk);
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(ohci_at91-hclk);
+   clk_prepare_enable(ohci_at91-iclk);
+   clk_prepare_enable(ohci_at91-fclk);
+   ohci_at91-clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-   if (!clocked)
+   if (!ohci_at91-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
-   clk_disable_unprepare(hclk);
+   clk_disable_unprepare(ohci_at91-fclk);
+   clk_disable_unprepare(ohci_at91-iclk);
+   clk_disable_unprepare(ohci_at91-hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(ohci_at91-uclk);
+   ohci_at91-clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, start\n);
 
/*
 * Start the USB clocks.
 */
-   at91_start_clock();
+   at91_start_clock(ohci_at91);
 
/*
 * The USB host controller must remain in reset.
@@ -95,6 +107,7 @@ static void at91_stop_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
dev_dbg(pdev-dev, stop\n);
 
@@ -106,7 +119,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
 * Stop the USB clocks.
 */
-   at91_stop_clock();
+   at91_stop_clock(ohci_at91);
 }
 
 
@@ -133,6 +146,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct ohci_hcd *ohci;
int retval;
struct usb_hcd *hcd = NULL;
+   struct ohci_at91_priv *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
int irq;
@@ -146,6 +160,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd = usb_create_hcd(driver, dev, at91);
if (!hcd)
return -ENOMEM;
+   ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(dev, res);
@@ -156,29 +171,29 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(dev, ohci_clk);
-   if (IS_ERR(iclk)) {
+   ohci_at91-iclk = devm_clk_get(dev, ohci_clk);
+   if (IS_ERR(ohci_at91-iclk)) {
dev_err(dev, failed to get ohci_clk\n);
-   retval = PTR_ERR(iclk);
+   retval = PTR_ERR(ohci_at91-iclk);
goto err

[PATCHv3 2/5] USB: host: ohci_at91: Stop/start USB PLL for all sleep modes

2015-01-17 Thread Sylvain Rochet
Disable/unprepare clocks without testing the sleep target_state, removed
the at91_suspend_entering_slow_clock() call (which is only a
target_state == PM_SUSPEND_MEM).

Other kind of suspend now benefit from the power save induced by this
PLL deactivation. The resume penalty is about 500 us, which is not
negligible but acceptable considering the amount of power we are saving.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Reported-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/host/ohci-at91.c | 25 +
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..f0da734 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -49,6 +49,8 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -61,6 +63,8 @@ static void at91_start_clock(void)
 
 static void at91_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
clk_disable_unprepare(hclk);
@@ -615,16 +619,14 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, 
pm_message_t mesg)
 *
 * REVISIT: some boards will be able to turn VBUS off...
 */
-   if (at91_suspend_entering_slow_clock()) {
-   ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
-   ohci-hc_control = OHCI_CTRL_RWC;
-   ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
-   ohci-rh_state = OHCI_RH_HALTED;
-
-   /* flush the writes */
-   (void) ohci_readl (ohci, ohci-regs-control);
-   at91_stop_clock();
-   }
+   ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
+   ohci-hc_control = OHCI_CTRL_RWC;
+   ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
+   ohci-rh_state = OHCI_RH_HALTED;
+
+   /* flush the writes */
+   (void) ohci_readl (ohci, ohci-regs-control);
+   at91_stop_clock();
 
return ret;
 }
@@ -636,8 +638,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device 
*pdev)
if (device_may_wakeup(pdev-dev))
disable_irq_wake(hcd-irq);
 
-   if (!clocked)
-   at91_start_clock();
+   at91_start_clock();
 
ohci_resume(hcd, false);
return 0;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 1/5] USB: host: ehci_atmel: Add suspend/resume support

2015-01-17 Thread Sylvain Rochet
This patch add suspend/resume support for Atmel EHCI, mostly
about disabling and unpreparing clocks so USB PLL is stopped
before entering sleep state.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..2e0043b 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -37,6 +37,8 @@ static int clocked;
 
 static void atmel_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -48,6 +50,8 @@ static void atmel_start_clock(void)
 
 static void atmel_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
@@ -174,6 +178,32 @@ static int ehci_atmel_drv_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct platform_device *pdev, pm_message_t 
mesg)
+{
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   int ret;
+
+   ret = ehci_suspend(hcd, false);
+   if (ret)
+   return ret;
+
+   atmel_stop_clock();
+   return 0;
+}
+
+static int ehci_atmel_drv_resume(struct platform_device *pdev)
+{
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+   atmel_start_clock();
+   return ehci_resume(hcd, false);
+}
+#else
+#define ehci_atmel_drv_suspend NULL
+#define ehci_atmel_drv_resume  NULL
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = atmel,at91sam9g45-ehci },
@@ -187,6 +217,8 @@ static struct platform_driver ehci_atmel_driver = {
.probe  = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
+   .suspend= ehci_atmel_drv_suspend,
+   .resume = ehci_atmel_drv_resume,
.driver = {
.name   = atmel-ehci,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/3] USB: host: ohci_at91: Move global variables to private struct

2015-01-17 Thread Sylvain Rochet
This patch move Atmel OHCI global variables (clocks ptr and clocked
boolean) to private struct ohci_at91, appended at the end of the parent
struct usb_hcd.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 85 +++-
 1 file changed, 52 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index f0da734..ca53f8a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,15 @@
for ((index) = 0; (index)  AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+struct ohci_at91 {
+   struct ohci_hcd ohci;
+
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   struct clk *hclk;
+   bool clocked;
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC OHCI Atmel driver
@@ -41,49 +49,54 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
 static const char hcd_name[] = ohci-atmel;
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
 
 extern int usb_disabled(void);
 
 /*-*/
 
-static void at91_start_clock(void)
+static inline struct ohci_at91 *hcd_to_ohci_at91(struct usb_hcd *hcd)
+{
+   return (struct ohci_at91 *) hcd-hcd_priv;
+}
+
+static void at91_start_clock(struct ohci_at91 *ohci_at91)
 {
-   if (clocked)
+   if (ohci_at91-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(ohci_at91-uclk, 4800);
+   clk_prepare_enable(ohci_at91-uclk);
}
-   clk_prepare_enable(hclk);
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(ohci_at91-hclk);
+   clk_prepare_enable(ohci_at91-iclk);
+   clk_prepare_enable(ohci_at91-fclk);
+   ohci_at91-clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91 *ohci_at91)
 {
-   if (!clocked)
+   if (!ohci_at91-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
-   clk_disable_unprepare(hclk);
+   clk_disable_unprepare(ohci_at91-fclk);
+   clk_disable_unprepare(ohci_at91-iclk);
+   clk_disable_unprepare(ohci_at91-hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(ohci_at91-uclk);
+   ohci_at91-clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91 *ohci_at91 = hcd_to_ohci_at91(hcd);
 
dev_dbg(pdev-dev, start\n);
 
/*
 * Start the USB clocks.
 */
-   at91_start_clock();
+   at91_start_clock(ohci_at91);
 
/*
 * The USB host controller must remain in reset.
@@ -95,6 +108,7 @@ static void at91_stop_hc(struct platform_device *pdev)
 {
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd-regs;
+   struct ohci_at91 *ohci_at91 = hcd_to_ohci_at91(hcd);
 
dev_dbg(pdev-dev, stop\n);
 
@@ -106,7 +120,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
 * Stop the USB clocks.
 */
-   at91_stop_clock();
+   at91_stop_clock(ohci_at91);
 }
 
 
@@ -133,6 +147,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct ohci_hcd *ohci;
int retval;
struct usb_hcd *hcd = NULL;
+   struct ohci_at91 *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
int irq;
@@ -146,6 +161,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd = usb_create_hcd(driver, dev, at91);
if (!hcd)
return -ENOMEM;
+   ohci_at91 = hcd_to_ohci_at91(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(dev, res);
@@ -156,29 +172,29 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(dev, ohci_clk);
-   if (IS_ERR(iclk)) {
+   ohci_at91-iclk = devm_clk_get(dev, ohci_clk);
+   if (IS_ERR(ohci_at91-iclk)) {
dev_err(dev, failed to get ohci_clk\n);
-   retval = PTR_ERR(iclk);
+   retval = PTR_ERR(ohci_at91-iclk);
goto err;
}
-   fclk = devm_clk_get(dev, uhpck);
-   if (IS_ERR(fclk)) {
+   ohci_at91

[PATCH 3/3] USB: host: ohci_at91: usb_hcd_at91_probe(), remove useless stack initialisation

2015-01-17 Thread Sylvain Rochet
struct usb_hcd *hcd = NULL;
...
hcd = usb_create_hcd(driver, dev, at91);

This patch remove *hcd useless initialisation to NULL;

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ohci-at91.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index ca53f8a..10c9d76 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -146,7 +146,7 @@ static int usb_hcd_at91_probe(const struct hc_driver 
*driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
-   struct usb_hcd *hcd = NULL;
+   struct usb_hcd *hcd;
struct ohci_at91 *ohci_at91;
struct device *dev = pdev-dev;
struct resource *res;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/3] USB: host: ehci_atmel: Move global variables to private struct

2015-01-17 Thread Sylvain Rochet
This patch move Atmel EHCI global variables (clocks ptr and clocked
boolean) to private struct atmel_ehci, appended at the end of the parent
struct usb_hcd.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 75 +++
 1 file changed, 48 insertions(+), 27 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 2e0043b..a47fe3f 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -30,45 +30,62 @@ static const char hcd_name[] = ehci-atmel;
 static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+struct atmel_ehci {
+   struct ehci_hcd ehci;
+
+   struct clk *iclk;
+   struct clk *fclk;
+   struct clk *uclk;
+   bool clocked;
+};
 
 /*-*/
 
-static void atmel_start_clock(void)
+static inline struct atmel_ehci *hcd_to_atmel_ehci(struct usb_hcd *hcd)
+{
+   return (struct atmel_ehci *) hcd-hcd_priv;
+}
+
+static void atmel_start_clock(struct atmel_ehci *atmel_ehci)
 {
-   if (clocked)
+   if (atmel_ehci-clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   clk_set_rate(uclk, 4800);
-   clk_prepare_enable(uclk);
+   clk_set_rate(atmel_ehci-uclk, 4800);
+   clk_prepare_enable(atmel_ehci-uclk);
}
-   clk_prepare_enable(iclk);
-   clk_prepare_enable(fclk);
-   clocked = 1;
+   clk_prepare_enable(atmel_ehci-iclk);
+   clk_prepare_enable(atmel_ehci-fclk);
+   atmel_ehci-clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci *atmel_ehci)
 {
-   if (!clocked)
+   if (!atmel_ehci-clocked)
return;
-   clk_disable_unprepare(fclk);
-   clk_disable_unprepare(iclk);
+   clk_disable_unprepare(atmel_ehci-fclk);
+   clk_disable_unprepare(atmel_ehci-iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
-   clk_disable_unprepare(uclk);
-   clocked = 0;
+   clk_disable_unprepare(atmel_ehci-uclk);
+   atmel_ehci-clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci *atmel_ehci = hcd_to_atmel_ehci(hcd);
+
dev_dbg(pdev-dev, start\n);
-   atmel_start_clock();
+   atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   struct atmel_ehci *atmel_ehci = hcd_to_atmel_ehci(hcd);
+
dev_dbg(pdev-dev, stop\n);
-   atmel_stop_clock();
+   atmel_stop_clock(atmel_ehci);
 }
 
 /*-*/
@@ -79,6 +96,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+   struct atmel_ehci *atmel_ehci;
int irq;
int retval;
 
@@ -109,6 +127,7 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+   atmel_ehci = hcd_to_atmel_ehci(hcd);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd-regs = devm_ioremap_resource(pdev-dev, res);
@@ -120,23 +139,23 @@ static int ehci_atmel_drv_probe(struct platform_device 
*pdev)
hcd-rsrc_start = res-start;
hcd-rsrc_len = resource_size(res);
 
-   iclk = devm_clk_get(pdev-dev, ehci_clk);
-   if (IS_ERR(iclk)) {
+   atmel_ehci-iclk = devm_clk_get(pdev-dev, ehci_clk);
+   if (IS_ERR(atmel_ehci-iclk)) {
dev_err(pdev-dev, Error getting interface clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
-   fclk = devm_clk_get(pdev-dev, uhpck);
-   if (IS_ERR(fclk)) {
+   atmel_ehci-fclk = devm_clk_get(pdev-dev, uhpck);
+   if (IS_ERR(atmel_ehci-fclk)) {
dev_err(pdev-dev, Error getting function clock\n);
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-   uclk = devm_clk_get(pdev-dev, usb_clk);
-   if (IS_ERR(uclk)) {
+   atmel_ehci-uclk = devm_clk_get(pdev-dev, usb_clk);
+   if (IS_ERR(atmel_ehci-uclk)) {
dev_err(pdev-dev, failed to get uclk\n);
-   retval = PTR_ERR(uclk);
+   retval = PTR_ERR(atmel_ehci-uclk);
goto fail_request_resource;
}
}
@@ -173,7 +192,6 @@ static int ehci_atmel_drv_remove(struct

Re: [PATCH 1/3] USB: host: ehci_atmel: Move global variables to private struct

2015-01-17 Thread Sylvain Rochet
Hello Alan,

On Sat, Jan 17, 2015 at 03:30:45PM -0500, Alan Stern wrote:
 
 This is not the right way to do it.  For an example of the right way, 
 see the ehci-platform.c file.  Your private structure is stored in 
 ehci-priv, and its size is specified by the .extra_priv_size member of 
 an ehci_driver_overrides structure passed to ehci_init_driver().

Dammit… reworked this way, thanks for the heads-up !

Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCHv3 1/5] USB: host: ehci_atmel: Add suspend/resume support

2015-01-17 Thread Sylvain Rochet
Hi Sergei,


On Sun, Jan 18, 2015 at 01:22:38AM +0300, Sergei Shtylyov wrote:
 
There's little inconsistency in your patch subjects: you're using
 '_' but the files you're modifying are named using '-'...

Indeed.


 @@ -187,6 +217,8 @@ static struct platform_driver ehci_atmel_driver = {
  .probe  = ehci_atmel_drv_probe,
  .remove = ehci_atmel_drv_remove,
  .shutdown   = usb_hcd_platform_shutdown,
 +.suspend= ehci_atmel_drv_suspend,
 +.resume = ehci_atmel_drv_resume,
 
I think you should use 'struct dev_pm_ops' now.

This way ?

static int ehci_atmel_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
(...)


static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend, 
ehci_atmel_drv_resume);

(...)
.driver = {
.pm = ehci_atmel_pm_ops,
}
(...)


Should I send a v4 or can I send this change separately on top of the 
previous change ?


Sylvain
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 1/2] USB: host: ehci_atmel: Add suspend/resume support

2015-01-17 Thread Sylvain Rochet
This patch add suspend/resume support for Atmel EHCI, mostly
about disabling and unpreparing clocks so USB PLL is stopped
before entering sleep state.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
---
 drivers/usb/host/ehci-atmel.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..2e0043b 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -37,6 +37,8 @@ static int clocked;
 
 static void atmel_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -48,6 +50,8 @@ static void atmel_start_clock(void)
 
 static void atmel_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
@@ -174,6 +178,32 @@ static int ehci_atmel_drv_remove(struct platform_device 
*pdev)
return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct platform_device *pdev, pm_message_t 
mesg)
+{
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+   int ret;
+
+   ret = ehci_suspend(hcd, false);
+   if (ret)
+   return ret;
+
+   atmel_stop_clock();
+   return 0;
+}
+
+static int ehci_atmel_drv_resume(struct platform_device *pdev)
+{
+   struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+   atmel_start_clock();
+   return ehci_resume(hcd, false);
+}
+#else
+#define ehci_atmel_drv_suspend NULL
+#define ehci_atmel_drv_resume  NULL
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = atmel,at91sam9g45-ehci },
@@ -187,6 +217,8 @@ static struct platform_driver ehci_atmel_driver = {
.probe  = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown   = usb_hcd_platform_shutdown,
+   .suspend= ehci_atmel_drv_suspend,
+   .resume = ehci_atmel_drv_resume,
.driver = {
.name   = atmel-ehci,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 2/2] USB: host: ohci_at91: Stop/start USB PLL for all sleep modes

2015-01-17 Thread Sylvain Rochet
Disable/unprepare clocks without testing the sleep target_state, removed
the at91_suspend_entering_slow_clock() call (which is only a
target_state == PM_SUSPEND_MEM).

Other kind of suspend now benefit from the power save induced by this
PLL deactivation. The resume penalty is about 500 us, which is not
negligible but acceptable considering the amount of power we are saving.

Signed-off-by: Sylvain Rochet sylvain.roc...@finsecur.com
Reported-by: Boris Brezillon boris.brezil...@free-electrons.com
---
 drivers/usb/host/ohci-at91.c | 25 +
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..f0da734 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -49,6 +49,8 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(void)
 {
+   if (clocked)
+   return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(uclk, 4800);
clk_prepare_enable(uclk);
@@ -61,6 +63,8 @@ static void at91_start_clock(void)
 
 static void at91_stop_clock(void)
 {
+   if (!clocked)
+   return;
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
clk_disable_unprepare(hclk);
@@ -615,16 +619,14 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, 
pm_message_t mesg)
 *
 * REVISIT: some boards will be able to turn VBUS off...
 */
-   if (at91_suspend_entering_slow_clock()) {
-   ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
-   ohci-hc_control = OHCI_CTRL_RWC;
-   ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
-   ohci-rh_state = OHCI_RH_HALTED;
-
-   /* flush the writes */
-   (void) ohci_readl (ohci, ohci-regs-control);
-   at91_stop_clock();
-   }
+   ohci-hc_control = ohci_readl(ohci, ohci-regs-control);
+   ohci-hc_control = OHCI_CTRL_RWC;
+   ohci_writel(ohci, ohci-hc_control, ohci-regs-control);
+   ohci-rh_state = OHCI_RH_HALTED;
+
+   /* flush the writes */
+   (void) ohci_readl (ohci, ohci-regs-control);
+   at91_stop_clock();
 
return ret;
 }
@@ -636,8 +638,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device 
*pdev)
if (device_may_wakeup(pdev-dev))
disable_irq_wake(hcd-irq);
 
-   if (!clocked)
-   at91_start_clock();
+   at91_start_clock();
 
ohci_resume(hcd, false);
return 0;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html