1eb81955bSIlya Yanok #include <common.h> 27a342785SHeiko Schocher #include <watchdog.h> 3eb81955bSIlya Yanok #include <asm/errno.h> 4eb81955bSIlya Yanok #include <linux/usb/ch9.h> 5eb81955bSIlya Yanok #include <linux/usb/gadget.h> 6eb81955bSIlya Yanok 7eb81955bSIlya Yanok #define __UBOOT__ 8eb81955bSIlya Yanok #include <usb.h> 9eb81955bSIlya Yanok #include "linux-compat.h" 10eb81955bSIlya Yanok #include "usb-compat.h" 11eb81955bSIlya Yanok #include "musb_core.h" 12eb81955bSIlya Yanok #include "musb_host.h" 13eb81955bSIlya Yanok #include "musb_gadget.h" 14eb81955bSIlya Yanok 15eb81955bSIlya Yanok #ifdef CONFIG_MUSB_HOST 16eb81955bSIlya Yanok static struct musb *host; 17eb81955bSIlya Yanok static struct usb_hcd hcd; 18eb81955bSIlya Yanok static enum usb_device_speed host_speed; 19eb81955bSIlya Yanok 20eb81955bSIlya Yanok static void musb_host_complete_urb(struct urb *urb) 21eb81955bSIlya Yanok { 22eb81955bSIlya Yanok urb->dev->status &= ~USB_ST_NOT_PROC; 23eb81955bSIlya Yanok urb->dev->act_len = urb->actual_length; 24eb81955bSIlya Yanok } 25eb81955bSIlya Yanok 26eb81955bSIlya Yanok static struct usb_host_endpoint hep; 27eb81955bSIlya Yanok static struct urb urb; 28eb81955bSIlya Yanok 29eb81955bSIlya Yanok static struct urb *construct_urb(struct usb_device *dev, int endpoint_type, 30eb81955bSIlya Yanok unsigned long pipe, void *buffer, int len, 31eb81955bSIlya Yanok struct devrequest *setup, int interval) 32eb81955bSIlya Yanok { 33eb81955bSIlya Yanok int epnum = usb_pipeendpoint(pipe); 34eb81955bSIlya Yanok int is_in = usb_pipein(pipe); 35eb81955bSIlya Yanok 36eb81955bSIlya Yanok memset(&urb, 0, sizeof(struct urb)); 37eb81955bSIlya Yanok memset(&hep, 0, sizeof(struct usb_host_endpoint)); 38eb81955bSIlya Yanok INIT_LIST_HEAD(&hep.urb_list); 39eb81955bSIlya Yanok INIT_LIST_HEAD(&urb.urb_list); 40eb81955bSIlya Yanok urb.ep = &hep; 41eb81955bSIlya Yanok urb.complete = musb_host_complete_urb; 42eb81955bSIlya Yanok urb.status = -EINPROGRESS; 43eb81955bSIlya Yanok urb.dev = dev; 44eb81955bSIlya Yanok urb.pipe = pipe; 45eb81955bSIlya Yanok urb.transfer_buffer = buffer; 46eb81955bSIlya Yanok urb.transfer_dma = (unsigned long)buffer; 47eb81955bSIlya Yanok urb.transfer_buffer_length = len; 48eb81955bSIlya Yanok urb.setup_packet = (unsigned char *)setup; 49eb81955bSIlya Yanok 50eb81955bSIlya Yanok urb.ep->desc.wMaxPacketSize = 51eb81955bSIlya Yanok __cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] : 52eb81955bSIlya Yanok dev->epmaxpacketout[epnum]); 53eb81955bSIlya Yanok urb.ep->desc.bmAttributes = endpoint_type; 54eb81955bSIlya Yanok urb.ep->desc.bEndpointAddress = 55eb81955bSIlya Yanok (is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum; 56eb81955bSIlya Yanok urb.ep->desc.bInterval = interval; 57eb81955bSIlya Yanok 58eb81955bSIlya Yanok return &urb; 59eb81955bSIlya Yanok } 60eb81955bSIlya Yanok 61eb81955bSIlya Yanok #define MUSB_HOST_TIMEOUT 0x3ffffff 62eb81955bSIlya Yanok 63eb81955bSIlya Yanok static int submit_urb(struct usb_hcd *hcd, struct urb *urb) 64eb81955bSIlya Yanok { 65eb81955bSIlya Yanok struct musb *host = hcd->hcd_priv; 66eb81955bSIlya Yanok int ret; 67eb81955bSIlya Yanok int timeout; 68eb81955bSIlya Yanok 69eb81955bSIlya Yanok ret = musb_urb_enqueue(hcd, urb, 0); 70eb81955bSIlya Yanok if (ret < 0) { 71eb81955bSIlya Yanok printf("Failed to enqueue URB to controller\n"); 72eb81955bSIlya Yanok return ret; 73eb81955bSIlya Yanok } 74eb81955bSIlya Yanok 75eb81955bSIlya Yanok timeout = MUSB_HOST_TIMEOUT; 76eb81955bSIlya Yanok do { 77eb81955bSIlya Yanok if (ctrlc()) 78eb81955bSIlya Yanok return -EIO; 79eb81955bSIlya Yanok host->isr(0, host); 80eb81955bSIlya Yanok } while ((urb->dev->status & USB_ST_NOT_PROC) && --timeout); 81eb81955bSIlya Yanok 82eb81955bSIlya Yanok return urb->status; 83eb81955bSIlya Yanok } 84eb81955bSIlya Yanok 85eb81955bSIlya Yanok int submit_control_msg(struct usb_device *dev, unsigned long pipe, 86eb81955bSIlya Yanok void *buffer, int len, struct devrequest *setup) 87eb81955bSIlya Yanok { 88eb81955bSIlya Yanok struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_CONTROL, pipe, 89eb81955bSIlya Yanok buffer, len, setup, 0); 90eb81955bSIlya Yanok 91eb81955bSIlya Yanok /* Fix speed for non hub-attached devices */ 92eb81955bSIlya Yanok if (!dev->parent) 93eb81955bSIlya Yanok dev->speed = host_speed; 94eb81955bSIlya Yanok 95eb81955bSIlya Yanok return submit_urb(&hcd, urb); 96eb81955bSIlya Yanok } 97eb81955bSIlya Yanok 98eb81955bSIlya Yanok 99eb81955bSIlya Yanok int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, 100eb81955bSIlya Yanok void *buffer, int len) 101eb81955bSIlya Yanok { 102eb81955bSIlya Yanok struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_BULK, pipe, 103eb81955bSIlya Yanok buffer, len, NULL, 0); 104eb81955bSIlya Yanok return submit_urb(&hcd, urb); 105eb81955bSIlya Yanok } 106eb81955bSIlya Yanok 107eb81955bSIlya Yanok int submit_int_msg(struct usb_device *dev, unsigned long pipe, 108eb81955bSIlya Yanok void *buffer, int len, int interval) 109eb81955bSIlya Yanok { 110eb81955bSIlya Yanok struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_INT, pipe, 111eb81955bSIlya Yanok buffer, len, NULL, interval); 112eb81955bSIlya Yanok return submit_urb(&hcd, urb); 113eb81955bSIlya Yanok } 114eb81955bSIlya Yanok 11506d513ecSTroy Kisky int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) 116eb81955bSIlya Yanok { 117eb81955bSIlya Yanok u8 power; 118eb81955bSIlya Yanok void *mbase; 119eb81955bSIlya Yanok int timeout = MUSB_HOST_TIMEOUT; 120eb81955bSIlya Yanok 121eb81955bSIlya Yanok if (!host) { 122eb81955bSIlya Yanok printf("MUSB host is not registered\n"); 123eb81955bSIlya Yanok return -ENODEV; 124eb81955bSIlya Yanok } 125eb81955bSIlya Yanok 126eb81955bSIlya Yanok musb_start(host); 127eb81955bSIlya Yanok mbase = host->mregs; 128eb81955bSIlya Yanok do { 129eb81955bSIlya Yanok if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM) 130eb81955bSIlya Yanok break; 131eb81955bSIlya Yanok } while (--timeout); 132eb81955bSIlya Yanok if (!timeout) 133eb81955bSIlya Yanok return -ENODEV; 134eb81955bSIlya Yanok 135eb81955bSIlya Yanok power = musb_readb(mbase, MUSB_POWER); 136eb81955bSIlya Yanok musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); 137eb81955bSIlya Yanok udelay(30000); 138eb81955bSIlya Yanok power = musb_readb(mbase, MUSB_POWER); 139eb81955bSIlya Yanok musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power); 140eb81955bSIlya Yanok host->isr(0, host); 141eb81955bSIlya Yanok host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ? 142eb81955bSIlya Yanok USB_SPEED_HIGH : 143eb81955bSIlya Yanok (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ? 144eb81955bSIlya Yanok USB_SPEED_FULL : USB_SPEED_LOW; 145eb81955bSIlya Yanok host->is_active = 1; 146eb81955bSIlya Yanok hcd.hcd_priv = host; 147eb81955bSIlya Yanok 148eb81955bSIlya Yanok return 0; 149eb81955bSIlya Yanok } 150eb81955bSIlya Yanok 151eb81955bSIlya Yanok int usb_lowlevel_stop(int index) 152eb81955bSIlya Yanok { 153eb81955bSIlya Yanok if (!host) { 154eb81955bSIlya Yanok printf("MUSB host is not registered\n"); 155eb81955bSIlya Yanok return -ENODEV; 156eb81955bSIlya Yanok } 157eb81955bSIlya Yanok 158eb81955bSIlya Yanok musb_stop(host); 159eb81955bSIlya Yanok return 0; 160eb81955bSIlya Yanok } 161eb81955bSIlya Yanok #endif /* CONFIG_MUSB_HOST */ 162eb81955bSIlya Yanok 163eb81955bSIlya Yanok #ifdef CONFIG_MUSB_GADGET 164eb81955bSIlya Yanok static struct musb *gadget; 165eb81955bSIlya Yanok 166eb81955bSIlya Yanok int usb_gadget_handle_interrupts(void) 167eb81955bSIlya Yanok { 1687a342785SHeiko Schocher WATCHDOG_RESET(); 169eb81955bSIlya Yanok if (!gadget || !gadget->isr) 170eb81955bSIlya Yanok return -EINVAL; 171eb81955bSIlya Yanok 172eb81955bSIlya Yanok return gadget->isr(0, gadget); 173eb81955bSIlya Yanok } 174eb81955bSIlya Yanok 175eb81955bSIlya Yanok int usb_gadget_register_driver(struct usb_gadget_driver *driver) 176eb81955bSIlya Yanok { 177eb81955bSIlya Yanok int ret; 178eb81955bSIlya Yanok 17976b09b85SBin Liu if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind || 180eb81955bSIlya Yanok !driver->setup) { 181eb81955bSIlya Yanok printf("bad parameter.\n"); 182eb81955bSIlya Yanok return -EINVAL; 183eb81955bSIlya Yanok } 184eb81955bSIlya Yanok 185eb81955bSIlya Yanok if (!gadget) { 186eb81955bSIlya Yanok printf("Controller uninitialized\n"); 187eb81955bSIlya Yanok return -ENXIO; 188eb81955bSIlya Yanok } 189eb81955bSIlya Yanok 190eb81955bSIlya Yanok ret = musb_gadget_start(&gadget->g, driver); 191eb81955bSIlya Yanok if (ret < 0) { 192eb81955bSIlya Yanok printf("gadget_start failed with %d\n", ret); 193eb81955bSIlya Yanok return ret; 194eb81955bSIlya Yanok } 195eb81955bSIlya Yanok 196eb81955bSIlya Yanok ret = driver->bind(&gadget->g); 197eb81955bSIlya Yanok if (ret < 0) { 198eb81955bSIlya Yanok printf("bind failed with %d\n", ret); 199eb81955bSIlya Yanok return ret; 200eb81955bSIlya Yanok } 201eb81955bSIlya Yanok 202eb81955bSIlya Yanok return 0; 203eb81955bSIlya Yanok } 204eb81955bSIlya Yanok 205eb81955bSIlya Yanok int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) 206eb81955bSIlya Yanok { 207*078d7302SRob Herring if (driver->disconnect) 208*078d7302SRob Herring driver->disconnect(&gadget->g); 209*078d7302SRob Herring if (driver->unbind) 210*078d7302SRob Herring driver->unbind(&gadget->g); 211eb81955bSIlya Yanok return 0; 212eb81955bSIlya Yanok } 213eb81955bSIlya Yanok #endif /* CONFIG_MUSB_GADGET */ 214eb81955bSIlya Yanok 215eb81955bSIlya Yanok int musb_register(struct musb_hdrc_platform_data *plat, void *bdata, 216eb81955bSIlya Yanok void *ctl_regs) 217eb81955bSIlya Yanok { 218eb81955bSIlya Yanok struct musb **musbp; 219eb81955bSIlya Yanok 220eb81955bSIlya Yanok switch (plat->mode) { 221eb81955bSIlya Yanok #ifdef CONFIG_MUSB_HOST 222eb81955bSIlya Yanok case MUSB_HOST: 223eb81955bSIlya Yanok musbp = &host; 224eb81955bSIlya Yanok break; 225eb81955bSIlya Yanok #endif 226eb81955bSIlya Yanok #ifdef CONFIG_MUSB_GADGET 227eb81955bSIlya Yanok case MUSB_PERIPHERAL: 228eb81955bSIlya Yanok musbp = &gadget; 229eb81955bSIlya Yanok break; 230eb81955bSIlya Yanok #endif 231eb81955bSIlya Yanok default: 232eb81955bSIlya Yanok return -EINVAL; 233eb81955bSIlya Yanok } 234eb81955bSIlya Yanok 235eb81955bSIlya Yanok *musbp = musb_init_controller(plat, (struct device *)bdata, ctl_regs); 236eb81955bSIlya Yanok if (!musbp) { 237eb81955bSIlya Yanok printf("Failed to init the controller\n"); 238eb81955bSIlya Yanok return -EIO; 239eb81955bSIlya Yanok } 240eb81955bSIlya Yanok 241eb81955bSIlya Yanok return 0; 242eb81955bSIlya Yanok } 243