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