11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * OHCI HCD (Host Controller Driver) for USB. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> 51da177e4SLinus Torvalds * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> 61da177e4SLinus Torvalds * (C) Copyright 2002 Hewlett-Packard Company 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * SA1111 Bus Glue 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Written by Christopher Hoover <ch@hpl.hp.com> 11ac310bb5SUwe Kleine-König * Based on fragments of previous driver by Russell King et al. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This file is licenced under the GPL. 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 16a09e64fbSRussell King #include <mach/hardware.h> 171da177e4SLinus Torvalds #include <asm/mach-types.h> 18a09e64fbSRussell King #include <mach/assabet.h> 19a09e64fbSRussell King #include <mach/badge4.h> 201da177e4SLinus Torvalds #include <asm/hardware/sa1111.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #ifndef CONFIG_SA1111 231da177e4SLinus Torvalds #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." 241da177e4SLinus Torvalds #endif 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds extern int usb_disabled(void); 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds static void sa1111_start_hc(struct sa1111_dev *dev) 311da177e4SLinus Torvalds { 321da177e4SLinus Torvalds unsigned int usb_rst = 0; 331da177e4SLinus Torvalds 34f45ba776SJoe Perches printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n", 35f45ba776SJoe Perches __FILE__); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #ifdef CONFIG_SA1100_BADGE4 381da177e4SLinus Torvalds if (machine_is_badge4()) { 391da177e4SLinus Torvalds badge4_set_5V(BADGE4_5V_USB, 1); 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds #endif 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds if (machine_is_xp860() || 441da177e4SLinus Torvalds machine_has_neponset() || 451da177e4SLinus Torvalds machine_is_pfs168() || 461da177e4SLinus Torvalds machine_is_badge4()) 471da177e4SLinus Torvalds usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds /* 501da177e4SLinus Torvalds * Configure the power sense and control lines. Place the USB 511da177e4SLinus Torvalds * host controller in reset. 521da177e4SLinus Torvalds */ 531da177e4SLinus Torvalds sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, 541da177e4SLinus Torvalds dev->mapbase + SA1111_USB_RESET); 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* 571da177e4SLinus Torvalds * Now, carefully enable the USB clock, and take 581da177e4SLinus Torvalds * the USB host controller out of reset. 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds sa1111_enable_device(dev); 611da177e4SLinus Torvalds udelay(11); 621da177e4SLinus Torvalds sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET); 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds static void sa1111_stop_hc(struct sa1111_dev *dev) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds unsigned int usb_rst; 68f45ba776SJoe Perches printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n", 69f45ba776SJoe Perches __FILE__); 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds /* 721da177e4SLinus Torvalds * Put the USB host controller into reset. 731da177e4SLinus Torvalds */ 741da177e4SLinus Torvalds usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET); 751da177e4SLinus Torvalds sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, 761da177e4SLinus Torvalds dev->mapbase + SA1111_USB_RESET); 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* 791da177e4SLinus Torvalds * Stop the USB clock. 801da177e4SLinus Torvalds */ 811da177e4SLinus Torvalds sa1111_disable_device(dev); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds #ifdef CONFIG_SA1100_BADGE4 841da177e4SLinus Torvalds if (machine_is_badge4()) { 851da177e4SLinus Torvalds /* Disable power to the USB bus */ 861da177e4SLinus Torvalds badge4_set_5V(BADGE4_5V_USB, 0); 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds #endif 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds #if 0 951da177e4SLinus Torvalds static void dump_hci_status(struct usb_hcd *hcd, const char *label) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds dbg ("%s USB_STATUS = { %s%s%s%s%s}", label, 1001da177e4SLinus Torvalds ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), 1011da177e4SLinus Torvalds ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), 1021da177e4SLinus Torvalds ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), 1031da177e4SLinus Torvalds ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), 1041da177e4SLinus Torvalds ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds #endif 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds /* configure so an HC device and id are always provided */ 1111da177e4SLinus Torvalds /* always called with process context; sleeping is OK */ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /** 1151da177e4SLinus Torvalds * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs 1161da177e4SLinus Torvalds * Context: !in_interrupt() 1171da177e4SLinus Torvalds * 1181da177e4SLinus Torvalds * Allocates basic resources for this USB host controller, and 1191da177e4SLinus Torvalds * then invokes the start() method for the HCD associated with it 1201da177e4SLinus Torvalds * through the hotplug entry's driver_data. 1211da177e4SLinus Torvalds * 1221da177e4SLinus Torvalds * Store this function in the HCD's struct pci_driver as probe(). 1231da177e4SLinus Torvalds */ 1241da177e4SLinus Torvalds int usb_hcd_sa1111_probe (const struct hc_driver *driver, 1251da177e4SLinus Torvalds struct sa1111_dev *dev) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds struct usb_hcd *hcd; 1281da177e4SLinus Torvalds int retval; 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds hcd = usb_create_hcd (driver, &dev->dev, "sa1111"); 1311da177e4SLinus Torvalds if (!hcd) 1321da177e4SLinus Torvalds return -ENOMEM; 1331da177e4SLinus Torvalds hcd->rsrc_start = dev->res.start; 13428f65c11SJoe Perches hcd->rsrc_len = resource_size(&dev->res); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 1371da177e4SLinus Torvalds dbg("request_mem_region failed"); 1381da177e4SLinus Torvalds retval = -EBUSY; 1391da177e4SLinus Torvalds goto err1; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds hcd->regs = dev->mapbase; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds sa1111_start_hc(dev); 1441da177e4SLinus Torvalds ohci_hcd_init(hcd_to_ohci(hcd)); 1451da177e4SLinus Torvalds 146d54b5caaSThomas Gleixner retval = usb_add_hcd(hcd, dev->irq[1], IRQF_DISABLED); 1471da177e4SLinus Torvalds if (retval == 0) 1481da177e4SLinus Torvalds return retval; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds sa1111_stop_hc(dev); 1511da177e4SLinus Torvalds release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 1521da177e4SLinus Torvalds err1: 1531da177e4SLinus Torvalds usb_put_hcd(hcd); 1541da177e4SLinus Torvalds return retval; 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds /* may be called without controller electrically present */ 1591da177e4SLinus Torvalds /* may be called with controller, bus, and devices active */ 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /** 1621da177e4SLinus Torvalds * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs 1631da177e4SLinus Torvalds * @dev: USB Host Controller being removed 1641da177e4SLinus Torvalds * Context: !in_interrupt() 1651da177e4SLinus Torvalds * 1661da177e4SLinus Torvalds * Reverses the effect of usb_hcd_sa1111_probe(), first invoking 1671da177e4SLinus Torvalds * the HCD's stop() method. It is always called from a thread 1681da177e4SLinus Torvalds * context, normally "rmmod", "apmd", or something similar. 1691da177e4SLinus Torvalds * 1701da177e4SLinus Torvalds */ 1711da177e4SLinus Torvalds void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds usb_remove_hcd(hcd); 1741da177e4SLinus Torvalds sa1111_stop_hc(dev); 1751da177e4SLinus Torvalds release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 1761da177e4SLinus Torvalds usb_put_hcd(hcd); 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds static int __devinit 1821da177e4SLinus Torvalds ohci_sa1111_start (struct usb_hcd *hcd) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds struct ohci_hcd *ohci = hcd_to_ohci (hcd); 1851da177e4SLinus Torvalds int ret; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds if ((ret = ohci_init(ohci)) < 0) 1881da177e4SLinus Torvalds return ret; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds if ((ret = ohci_run (ohci)) < 0) { 1911da177e4SLinus Torvalds err ("can't start %s", hcd->self.bus_name); 1921da177e4SLinus Torvalds ohci_stop (hcd); 1931da177e4SLinus Torvalds return ret; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds return 0; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds static const struct hc_driver ohci_sa1111_hc_driver = { 2011da177e4SLinus Torvalds .description = hcd_name, 2021da177e4SLinus Torvalds .product_desc = "SA-1111 OHCI", 2031da177e4SLinus Torvalds .hcd_priv_size = sizeof(struct ohci_hcd), 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds /* 2061da177e4SLinus Torvalds * generic hardware linkage 2071da177e4SLinus Torvalds */ 2081da177e4SLinus Torvalds .irq = ohci_irq, 2091da177e4SLinus Torvalds .flags = HCD_USB11 | HCD_MEMORY, 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* 2121da177e4SLinus Torvalds * basic lifecycle operations 2131da177e4SLinus Torvalds */ 2141da177e4SLinus Torvalds .start = ohci_sa1111_start, 2151da177e4SLinus Torvalds .stop = ohci_stop, 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* 2181da177e4SLinus Torvalds * managing i/o requests and associated device resources 2191da177e4SLinus Torvalds */ 2201da177e4SLinus Torvalds .urb_enqueue = ohci_urb_enqueue, 2211da177e4SLinus Torvalds .urb_dequeue = ohci_urb_dequeue, 2221da177e4SLinus Torvalds .endpoint_disable = ohci_endpoint_disable, 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* 2251da177e4SLinus Torvalds * scheduling support 2261da177e4SLinus Torvalds */ 2271da177e4SLinus Torvalds .get_frame_number = ohci_get_frame, 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* 2301da177e4SLinus Torvalds * root hub support 2311da177e4SLinus Torvalds */ 2321da177e4SLinus Torvalds .hub_status_data = ohci_hub_status_data, 2331da177e4SLinus Torvalds .hub_control = ohci_hub_control, 2348ad7fe16SDavid Brownell #ifdef CONFIG_PM 2350c0382e3SAlan Stern .bus_suspend = ohci_bus_suspend, 2360c0382e3SAlan Stern .bus_resume = ohci_bus_resume, 2371da177e4SLinus Torvalds #endif 2389293677aSDavid Brownell .start_port_reset = ohci_start_port_reset, 2391da177e4SLinus Torvalds }; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds int ret; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds if (usb_disabled()) 2481da177e4SLinus Torvalds return -ENODEV; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev); 2511da177e4SLinus Torvalds return ret; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev) 2551da177e4SLinus Torvalds { 2561da177e4SLinus Torvalds struct usb_hcd *hcd = sa1111_get_drvdata(dev); 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds usb_hcd_sa1111_remove(hcd, dev); 2591da177e4SLinus Torvalds return 0; 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds static struct sa1111_driver ohci_hcd_sa1111_driver = { 2631da177e4SLinus Torvalds .drv = { 2641da177e4SLinus Torvalds .name = "sa1111-ohci", 2651da177e4SLinus Torvalds }, 2661da177e4SLinus Torvalds .devid = SA1111_DEVID_USB, 2671da177e4SLinus Torvalds .probe = ohci_hcd_sa1111_drv_probe, 2681da177e4SLinus Torvalds .remove = ohci_hcd_sa1111_drv_remove, 2691da177e4SLinus Torvalds }; 2701da177e4SLinus Torvalds 271