X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fusb%2Fmusb-new%2Fmusb_uboot.c;h=51fb3fd7e2ecd75f7a55d68ab688f8e0883c6a86;hb=ebd468b2d26660ff7811e37cc64fa2369d4b5fff;hp=3f9a98c9070a9faf8a6d55256179fe39c7bd333c;hpb=accf04c2aa106a8ea5387d309e1ac037eba5ad63;p=u-boot diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 3f9a98c907..51fb3fd7e2 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -1,5 +1,8 @@ #include #include +#ifdef CONFIG_ARCH_SUNXI +#include +#endif #include #include #include @@ -12,6 +15,11 @@ #include "musb_gadget.h" #ifdef CONFIG_MUSB_HOST +struct int_queue { + struct usb_host_endpoint hep; + struct urb urb; +}; + static struct musb *host; static struct usb_hcd hcd; static enum usb_device_speed host_speed; @@ -112,6 +120,66 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, return submit_urb(&hcd, &urb); } +struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe, + int queuesize, int elementsize, void *buffer, int interval) +{ + struct int_queue *queue; + int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe); + + if (queuesize != 1) { + printf("ERROR musb int-queues only support queuesize 1\n"); + return NULL; + } + + if (dev->int_pending & (1 << index)) { + printf("ERROR int-urb is already pending on pipe %lx\n", pipe); + return NULL; + } + + queue = malloc(sizeof(*queue)); + if (!queue) + return NULL; + + construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT, + pipe, buffer, elementsize, NULL, interval); + + ret = musb_urb_enqueue(&hcd, &queue->urb, 0); + if (ret < 0) { + printf("Failed to enqueue URB to controller\n"); + free(queue); + return NULL; + } + + dev->int_pending |= 1 << index; + return queue; +} + +int destroy_int_queue(struct usb_device *dev, struct int_queue *queue) +{ + int index = usb_pipein(queue->urb.pipe) * 16 + + usb_pipeendpoint(queue->urb.pipe); + + if (queue->urb.status == -EINPROGRESS) + musb_urb_dequeue(&hcd, &queue->urb, -ETIME); + + dev->int_pending &= ~(1 << index); + free(queue); + return 0; +} + +void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) +{ + if (queue->urb.status != -EINPROGRESS) + return NULL; /* URB has already completed in a prev. poll */ + + host->isr(0, host); + + if (queue->urb.status != -EINPROGRESS) + return queue->urb.transfer_buffer; /* Done */ + + return NULL; /* URB still pending */ +} + void usb_reset_root_port(void) { void *mbase = host->mregs; @@ -121,8 +189,19 @@ void usb_reset_root_port(void) power &= 0xf0; musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); mdelay(50); +#ifdef CONFIG_ARCH_SUNXI + /* + * sunxi phy has a bug and it will wrongly detect high speed squelch + * when clearing reset on low-speed devices, temporary disable + * squelch detection to work around this. + */ + sunxi_usbc_enable_squelch_detect(0, 0); +#endif power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power); +#ifdef CONFIG_ARCH_SUNXI + sunxi_usbc_enable_squelch_detect(0, 1); +#endif host->isr(0, host); host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ? USB_SPEED_HIGH :