diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2015-01-06 08:46:59 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2015-01-12 13:13:29 -0500 |
commit | 258e2ddd634c20065d1c41290d10d2e5cf2f56e2 (patch) | |
tree | 92fe7b3861717a0696c185a9c8c661b1bea52e2f | |
parent | 3280e67536f8a4d4adf8dcde10cb4c4b577c34f4 (diff) |
usb: atmel_usba_udc: Add at91sam9g45 and at91sam9x5 errata handling
at91sam9g45 and at91sam9x5 SoCs have an hardware bug forcing us to
generate a pulse on the BIAS signal on "USB end of reset” and
“USB end of resume" events.
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Reported-by: Patrice VILCHEZ <patrice.vilchez@atmel.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/gadget/udc/atmel_usba_udc.c | 28 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/atmel_usba_udc.h | 2 |
2 files changed, 29 insertions, 1 deletions
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 36fd34b77387..55c8dde67f83 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c | |||
@@ -331,6 +331,17 @@ static void toggle_bias(struct usba_udc *udc, int is_on) | |||
331 | udc->errata->toggle_bias(udc, is_on); | 331 | udc->errata->toggle_bias(udc, is_on); |
332 | } | 332 | } |
333 | 333 | ||
334 | static void generate_bias_pulse(struct usba_udc *udc) | ||
335 | { | ||
336 | if (!udc->bias_pulse_needed) | ||
337 | return; | ||
338 | |||
339 | if (udc->errata && udc->errata->pulse_bias) | ||
340 | udc->errata->pulse_bias(udc); | ||
341 | |||
342 | udc->bias_pulse_needed = false; | ||
343 | } | ||
344 | |||
334 | static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) | 345 | static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) |
335 | { | 346 | { |
336 | unsigned int transaction_len; | 347 | unsigned int transaction_len; |
@@ -1607,6 +1618,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
1607 | if (status & USBA_DET_SUSPEND) { | 1618 | if (status & USBA_DET_SUSPEND) { |
1608 | toggle_bias(udc, 0); | 1619 | toggle_bias(udc, 0); |
1609 | usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); | 1620 | usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); |
1621 | udc->bias_pulse_needed = true; | ||
1610 | DBG(DBG_BUS, "Suspend detected\n"); | 1622 | DBG(DBG_BUS, "Suspend detected\n"); |
1611 | if (udc->gadget.speed != USB_SPEED_UNKNOWN | 1623 | if (udc->gadget.speed != USB_SPEED_UNKNOWN |
1612 | && udc->driver && udc->driver->suspend) { | 1624 | && udc->driver && udc->driver->suspend) { |
@@ -1624,6 +1636,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
1624 | 1636 | ||
1625 | if (status & USBA_END_OF_RESUME) { | 1637 | if (status & USBA_END_OF_RESUME) { |
1626 | usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); | 1638 | usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); |
1639 | generate_bias_pulse(udc); | ||
1627 | DBG(DBG_BUS, "Resume detected\n"); | 1640 | DBG(DBG_BUS, "Resume detected\n"); |
1628 | if (udc->gadget.speed != USB_SPEED_UNKNOWN | 1641 | if (udc->gadget.speed != USB_SPEED_UNKNOWN |
1629 | && udc->driver && udc->driver->resume) { | 1642 | && udc->driver && udc->driver->resume) { |
@@ -1659,6 +1672,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
1659 | struct usba_ep *ep0; | 1672 | struct usba_ep *ep0; |
1660 | 1673 | ||
1661 | usba_writel(udc, INT_CLR, USBA_END_OF_RESET); | 1674 | usba_writel(udc, INT_CLR, USBA_END_OF_RESET); |
1675 | generate_bias_pulse(udc); | ||
1662 | reset_all_endpoints(udc); | 1676 | reset_all_endpoints(udc); |
1663 | 1677 | ||
1664 | if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) { | 1678 | if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) { |
@@ -1818,13 +1832,25 @@ static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on) | |||
1818 | at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); | 1832 | at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); |
1819 | } | 1833 | } |
1820 | 1834 | ||
1835 | static void at91sam9g45_pulse_bias(struct usba_udc *udc) | ||
1836 | { | ||
1837 | unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR); | ||
1838 | |||
1839 | at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); | ||
1840 | at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); | ||
1841 | } | ||
1842 | |||
1821 | static const struct usba_udc_errata at91sam9rl_errata = { | 1843 | static const struct usba_udc_errata at91sam9rl_errata = { |
1822 | .toggle_bias = at91sam9rl_toggle_bias, | 1844 | .toggle_bias = at91sam9rl_toggle_bias, |
1823 | }; | 1845 | }; |
1824 | 1846 | ||
1847 | static const struct usba_udc_errata at91sam9g45_errata = { | ||
1848 | .pulse_bias = at91sam9g45_pulse_bias, | ||
1849 | }; | ||
1850 | |||
1825 | static const struct of_device_id atmel_udc_dt_ids[] = { | 1851 | static const struct of_device_id atmel_udc_dt_ids[] = { |
1826 | { .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata }, | 1852 | { .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata }, |
1827 | { .compatible = "atmel,at91sam9g45-udc" }, | 1853 | { .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata }, |
1828 | { .compatible = "atmel,sama5d3-udc" }, | 1854 | { .compatible = "atmel,sama5d3-udc" }, |
1829 | { /* sentinel */ } | 1855 | { /* sentinel */ } |
1830 | }; | 1856 | }; |
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index 456899e9ee62..72b3537f56ce 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h | |||
@@ -306,6 +306,7 @@ struct usba_request { | |||
306 | 306 | ||
307 | struct usba_udc_errata { | 307 | struct usba_udc_errata { |
308 | void (*toggle_bias)(struct usba_udc *udc, int is_on); | 308 | void (*toggle_bias)(struct usba_udc *udc, int is_on); |
309 | void (*pulse_bias)(struct usba_udc *udc); | ||
309 | }; | 310 | }; |
310 | 311 | ||
311 | struct usba_udc { | 312 | struct usba_udc { |
@@ -326,6 +327,7 @@ struct usba_udc { | |||
326 | struct clk *pclk; | 327 | struct clk *pclk; |
327 | struct clk *hclk; | 328 | struct clk *hclk; |
328 | struct usba_ep *usba_ep; | 329 | struct usba_ep *usba_ep; |
330 | bool bias_pulse_needed; | ||
329 | 331 | ||
330 | u16 devstatus; | 332 | u16 devstatus; |
331 | 333 | ||