Commit b2ba27a5 authored by Ronald Wahl's avatar Ronald Wahl Committed by Felipe Balbi

usb: gadget: at91_udc: move prepare clk into process context

Commit 76280832 (usb: gadget: at91_udc:
prepare clk before calling enable) added clock preparation in interrupt
context. This is not allowed as it might sleep. Also setting the clock
rate is unsafe to call from there for the same reason. Move clock
preparation and setting clock rate into process context (at91udc_probe).
Signed-off-by: default avatarRonald Wahl <ronald.wahl@raritan.com>
Acked-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: <stable@vger.kernel.org> # v3.17+
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent cf0b1d13
...@@ -895,12 +895,10 @@ static void clk_on(struct at91_udc *udc) ...@@ -895,12 +895,10 @@ static void clk_on(struct at91_udc *udc)
return; return;
udc->clocked = 1; udc->clocked = 1;
if (IS_ENABLED(CONFIG_COMMON_CLK)) { if (IS_ENABLED(CONFIG_COMMON_CLK))
clk_set_rate(udc->uclk, 48000000); clk_enable(udc->uclk);
clk_prepare_enable(udc->uclk); clk_enable(udc->iclk);
} clk_enable(udc->fclk);
clk_prepare_enable(udc->iclk);
clk_prepare_enable(udc->fclk);
} }
static void clk_off(struct at91_udc *udc) static void clk_off(struct at91_udc *udc)
...@@ -909,10 +907,10 @@ static void clk_off(struct at91_udc *udc) ...@@ -909,10 +907,10 @@ static void clk_off(struct at91_udc *udc)
return; return;
udc->clocked = 0; udc->clocked = 0;
udc->gadget.speed = USB_SPEED_UNKNOWN; udc->gadget.speed = USB_SPEED_UNKNOWN;
clk_disable_unprepare(udc->fclk); clk_disable(udc->fclk);
clk_disable_unprepare(udc->iclk); clk_disable(udc->iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK)) if (IS_ENABLED(CONFIG_COMMON_CLK))
clk_disable_unprepare(udc->uclk); clk_disable(udc->uclk);
} }
/* /*
...@@ -1793,14 +1791,24 @@ static int at91udc_probe(struct platform_device *pdev) ...@@ -1793,14 +1791,24 @@ static int at91udc_probe(struct platform_device *pdev)
} }
/* don't do anything until we have both gadget driver and VBUS */ /* don't do anything until we have both gadget driver and VBUS */
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(udc->uclk, 48000000);
retval = clk_prepare(udc->uclk);
if (retval)
goto fail1;
}
retval = clk_prepare(udc->fclk);
if (retval)
goto fail1a;
retval = clk_prepare_enable(udc->iclk); retval = clk_prepare_enable(udc->iclk);
if (retval) if (retval)
goto fail1; goto fail1b;
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
/* Clear all pending interrupts - UDP may be used by bootloader. */ /* Clear all pending interrupts - UDP may be used by bootloader. */
at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
clk_disable_unprepare(udc->iclk); clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */ /* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0); udc->udp_irq = platform_get_irq(pdev, 0);
...@@ -1808,7 +1816,7 @@ static int at91udc_probe(struct platform_device *pdev) ...@@ -1808,7 +1816,7 @@ static int at91udc_probe(struct platform_device *pdev)
0, driver_name, udc); 0, driver_name, udc);
if (retval < 0) { if (retval < 0) {
DBG("request irq %d failed\n", udc->udp_irq); DBG("request irq %d failed\n", udc->udp_irq);
goto fail1; goto fail1c;
} }
if (gpio_is_valid(udc->board.vbus_pin)) { if (gpio_is_valid(udc->board.vbus_pin)) {
retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
...@@ -1861,6 +1869,13 @@ static int at91udc_probe(struct platform_device *pdev) ...@@ -1861,6 +1869,13 @@ static int at91udc_probe(struct platform_device *pdev)
gpio_free(udc->board.vbus_pin); gpio_free(udc->board.vbus_pin);
fail2: fail2:
free_irq(udc->udp_irq, udc); free_irq(udc->udp_irq, udc);
fail1c:
clk_unprepare(udc->iclk);
fail1b:
clk_unprepare(udc->fclk);
fail1a:
if (IS_ENABLED(CONFIG_COMMON_CLK))
clk_unprepare(udc->uclk);
fail1: fail1:
if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk)) if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
clk_put(udc->uclk); clk_put(udc->uclk);
...@@ -1909,6 +1924,11 @@ static int __exit at91udc_remove(struct platform_device *pdev) ...@@ -1909,6 +1924,11 @@ static int __exit at91udc_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
if (IS_ENABLED(CONFIG_COMMON_CLK))
clk_unprepare(udc->uclk);
clk_unprepare(udc->fclk);
clk_unprepare(udc->iclk);
clk_put(udc->iclk); clk_put(udc->iclk);
clk_put(udc->fclk); clk_put(udc->fclk);
if (IS_ENABLED(CONFIG_COMMON_CLK)) if (IS_ENABLED(CONFIG_COMMON_CLK))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment