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> 191da177e4SLinus Torvalds #include <asm/hardware/sa1111.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #ifndef CONFIG_SA1111 221da177e4SLinus Torvalds #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." 231da177e4SLinus Torvalds #endif 241da177e4SLinus Torvalds 252213536dSRussell King #define USB_STATUS 0x0118 262213536dSRussell King #define USB_RESET 0x011c 272213536dSRussell King #define USB_IRQTEST 0x0120 282213536dSRussell King 292213536dSRussell King #define USB_RESET_FORCEIFRESET (1 << 0) 302213536dSRussell King #define USB_RESET_FORCEHCRESET (1 << 1) 312213536dSRussell King #define USB_RESET_CLKGENRESET (1 << 2) 322213536dSRussell King #define USB_RESET_SIMSCALEDOWN (1 << 3) 332213536dSRussell King #define USB_RESET_USBINTTEST (1 << 4) 342213536dSRussell King #define USB_RESET_SLEEPSTBYEN (1 << 5) 352213536dSRussell King #define USB_RESET_PWRSENSELOW (1 << 6) 362213536dSRussell King #define USB_RESET_PWRCTRLLOW (1 << 7) 372213536dSRussell King 382213536dSRussell King #define USB_STATUS_IRQHCIRMTWKUP (1 << 7) 392213536dSRussell King #define USB_STATUS_IRQHCIBUFFACC (1 << 8) 402213536dSRussell King #define USB_STATUS_NIRQHCIM (1 << 9) 412213536dSRussell King #define USB_STATUS_NHCIMFCLR (1 << 10) 422213536dSRussell King #define USB_STATUS_USBPWRSENSE (1 << 11) 432213536dSRussell King 441da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 451da177e4SLinus Torvalds 46ae99ddbcSRussell King static int sa1111_start_hc(struct sa1111_dev *dev) 471da177e4SLinus Torvalds { 481da177e4SLinus Torvalds unsigned int usb_rst = 0; 49ae99ddbcSRussell King int ret; 501da177e4SLinus Torvalds 513f878dbcSRussell King dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n"); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds if (machine_is_xp860() || 541da177e4SLinus Torvalds machine_has_neponset() || 551da177e4SLinus Torvalds machine_is_pfs168() || 561da177e4SLinus Torvalds machine_is_badge4()) 571da177e4SLinus Torvalds usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* 601da177e4SLinus Torvalds * Configure the power sense and control lines. Place the USB 611da177e4SLinus Torvalds * host controller in reset. 621da177e4SLinus Torvalds */ 631da177e4SLinus Torvalds sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, 642213536dSRussell King dev->mapbase + USB_RESET); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /* 671da177e4SLinus Torvalds * Now, carefully enable the USB clock, and take 681da177e4SLinus Torvalds * the USB host controller out of reset. 691da177e4SLinus Torvalds */ 70ae99ddbcSRussell King ret = sa1111_enable_device(dev); 71ae99ddbcSRussell King if (ret == 0) { 721da177e4SLinus Torvalds udelay(11); 732213536dSRussell King sa1111_writel(usb_rst, dev->mapbase + USB_RESET); 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 76ae99ddbcSRussell King return ret; 77ae99ddbcSRussell King } 78ae99ddbcSRussell King 791da177e4SLinus Torvalds static void sa1111_stop_hc(struct sa1111_dev *dev) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds unsigned int usb_rst; 829cb0f819SRussell King 833f878dbcSRussell King dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n"); 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* 861da177e4SLinus Torvalds * Put the USB host controller into reset. 871da177e4SLinus Torvalds */ 882213536dSRussell King usb_rst = sa1111_readl(dev->mapbase + USB_RESET); 891da177e4SLinus Torvalds sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, 902213536dSRussell King dev->mapbase + USB_RESET); 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /* 931da177e4SLinus Torvalds * Stop the USB clock. 941da177e4SLinus Torvalds */ 951da177e4SLinus Torvalds sa1111_disable_device(dev); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds #if 0 1021da177e4SLinus Torvalds static void dump_hci_status(struct usb_hcd *hcd, const char *label) 1031da177e4SLinus Torvalds { 1042213536dSRussell King unsigned long status = sa1111_readl(hcd->regs + USB_STATUS); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds dbg("%s USB_STATUS = { %s%s%s%s%s}", label, 1071da177e4SLinus Torvalds ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), 1081da177e4SLinus Torvalds ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), 1091da177e4SLinus Torvalds ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), 1101da177e4SLinus Torvalds ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), 1111da177e4SLinus Torvalds ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds #endif 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds /* configure so an HC device and id are always provided */ 1181da177e4SLinus Torvalds /* always called with process context; sleeping is OK */ 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /** 1221da177e4SLinus Torvalds * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs 1231da177e4SLinus Torvalds * Context: !in_interrupt() 1241da177e4SLinus Torvalds * 1251da177e4SLinus Torvalds * Allocates basic resources for this USB host controller, and 1261da177e4SLinus Torvalds * then invokes the start() method for the HCD associated with it 1271da177e4SLinus Torvalds * through the hotplug entry's driver_data. 1281da177e4SLinus Torvalds * 1291da177e4SLinus Torvalds * Store this function in the HCD's struct pci_driver as probe(). 1301da177e4SLinus Torvalds */ 1319cb0f819SRussell King static int usb_hcd_sa1111_probe(const struct hc_driver *driver, 1321da177e4SLinus Torvalds struct sa1111_dev *dev) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds struct usb_hcd *hcd; 1351da177e4SLinus Torvalds int retval; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds hcd = usb_create_hcd(driver, &dev->dev, "sa1111"); 1381da177e4SLinus Torvalds if (!hcd) 1391da177e4SLinus Torvalds return -ENOMEM; 1409cb0f819SRussell King 1411da177e4SLinus Torvalds hcd->rsrc_start = dev->res.start; 14228f65c11SJoe Perches hcd->rsrc_len = resource_size(&dev->res); 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 1451da177e4SLinus Torvalds dbg("request_mem_region failed"); 1461da177e4SLinus Torvalds retval = -EBUSY; 1471da177e4SLinus Torvalds goto err1; 1481da177e4SLinus Torvalds } 1499cb0f819SRussell King 1501da177e4SLinus Torvalds hcd->regs = dev->mapbase; 1511da177e4SLinus Torvalds 152ae99ddbcSRussell King ret = sa1111_start_hc(dev); 153ae99ddbcSRussell King if (ret) 154ae99ddbcSRussell King goto err2; 155ae99ddbcSRussell King 1561da177e4SLinus Torvalds ohci_hcd_init(hcd_to_ohci(hcd)); 1571da177e4SLinus Torvalds 158b5dd18d8SYong Zhang retval = usb_add_hcd(hcd, dev->irq[1], 0); 1591da177e4SLinus Torvalds if (retval == 0) 1601da177e4SLinus Torvalds return retval; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds sa1111_stop_hc(dev); 163ae99ddbcSRussell King err2: 1641da177e4SLinus Torvalds release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 1651da177e4SLinus Torvalds err1: 1661da177e4SLinus Torvalds usb_put_hcd(hcd); 1671da177e4SLinus Torvalds return retval; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* may be called without controller electrically present */ 1721da177e4SLinus Torvalds /* may be called with controller, bus, and devices active */ 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds /** 1751da177e4SLinus Torvalds * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs 1761da177e4SLinus Torvalds * @dev: USB Host Controller being removed 1771da177e4SLinus Torvalds * Context: !in_interrupt() 1781da177e4SLinus Torvalds * 1791da177e4SLinus Torvalds * Reverses the effect of usb_hcd_sa1111_probe(), first invoking 1801da177e4SLinus Torvalds * the HCD's stop() method. It is always called from a thread 1811da177e4SLinus Torvalds * context, normally "rmmod", "apmd", or something similar. 1821da177e4SLinus Torvalds */ 1839cb0f819SRussell King static void usb_hcd_sa1111_remove(struct usb_hcd *hcd, struct sa1111_dev *dev) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds usb_remove_hcd(hcd); 1861da177e4SLinus Torvalds sa1111_stop_hc(dev); 1871da177e4SLinus Torvalds release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 1881da177e4SLinus Torvalds usb_put_hcd(hcd); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 1921da177e4SLinus Torvalds 1939cb0f819SRussell King static int __devinit ohci_sa1111_start(struct usb_hcd *hcd) 1941da177e4SLinus Torvalds { 1951da177e4SLinus Torvalds struct ohci_hcd *ohci = hcd_to_ohci(hcd); 1961da177e4SLinus Torvalds int ret; 1971da177e4SLinus Torvalds 1989cb0f819SRussell King ret = ohci_init(ohci); 1999cb0f819SRussell King if (ret < 0) 2001da177e4SLinus Torvalds return ret; 2011da177e4SLinus Torvalds 2029cb0f819SRussell King ret = ohci_run(ohci); 2039cb0f819SRussell King if (ret < 0) { 2041da177e4SLinus Torvalds err("can't start %s", hcd->self.bus_name); 2051da177e4SLinus Torvalds ohci_stop(hcd); 2061da177e4SLinus Torvalds return ret; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds return 0; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static const struct hc_driver ohci_sa1111_hc_driver = { 2141da177e4SLinus Torvalds .description = hcd_name, 2151da177e4SLinus Torvalds .product_desc = "SA-1111 OHCI", 2161da177e4SLinus Torvalds .hcd_priv_size = sizeof(struct ohci_hcd), 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* 2191da177e4SLinus Torvalds * generic hardware linkage 2201da177e4SLinus Torvalds */ 2211da177e4SLinus Torvalds .irq = ohci_irq, 2221da177e4SLinus Torvalds .flags = HCD_USB11 | HCD_MEMORY, 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* 2251da177e4SLinus Torvalds * basic lifecycle operations 2261da177e4SLinus Torvalds */ 2271da177e4SLinus Torvalds .start = ohci_sa1111_start, 2281da177e4SLinus Torvalds .stop = ohci_stop, 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds /* 2311da177e4SLinus Torvalds * managing i/o requests and associated device resources 2321da177e4SLinus Torvalds */ 2331da177e4SLinus Torvalds .urb_enqueue = ohci_urb_enqueue, 2341da177e4SLinus Torvalds .urb_dequeue = ohci_urb_dequeue, 2351da177e4SLinus Torvalds .endpoint_disable = ohci_endpoint_disable, 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds /* 2381da177e4SLinus Torvalds * scheduling support 2391da177e4SLinus Torvalds */ 2401da177e4SLinus Torvalds .get_frame_number = ohci_get_frame, 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds /* 2431da177e4SLinus Torvalds * root hub support 2441da177e4SLinus Torvalds */ 2451da177e4SLinus Torvalds .hub_status_data = ohci_hub_status_data, 2461da177e4SLinus Torvalds .hub_control = ohci_hub_control, 2478ad7fe16SDavid Brownell #ifdef CONFIG_PM 2480c0382e3SAlan Stern .bus_suspend = ohci_bus_suspend, 2490c0382e3SAlan Stern .bus_resume = ohci_bus_resume, 2501da177e4SLinus Torvalds #endif 2519293677aSDavid Brownell .start_port_reset = ohci_start_port_reset, 2521da177e4SLinus Torvalds }; 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /*-------------------------------------------------------------------------*/ 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev) 2571da177e4SLinus Torvalds { 2581da177e4SLinus Torvalds int ret; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds if (usb_disabled()) 2611da177e4SLinus Torvalds return -ENODEV; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev); 2641da177e4SLinus Torvalds return ret; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev) 2681da177e4SLinus Torvalds { 2691da177e4SLinus Torvalds struct usb_hcd *hcd = sa1111_get_drvdata(dev); 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds usb_hcd_sa1111_remove(hcd, dev); 2721da177e4SLinus Torvalds return 0; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds static struct sa1111_driver ohci_hcd_sa1111_driver = { 2761da177e4SLinus Torvalds .drv = { 2771da177e4SLinus Torvalds .name = "sa1111-ohci", 2781ebcd765SRussell King .owner = THIS_MODULE, 2791da177e4SLinus Torvalds }, 2801da177e4SLinus Torvalds .devid = SA1111_DEVID_USB, 2811da177e4SLinus Torvalds .probe = ohci_hcd_sa1111_drv_probe, 2821da177e4SLinus Torvalds .remove = ohci_hcd_sa1111_drv_remove, 2831da177e4SLinus Torvalds }; 2841da177e4SLinus Torvalds 285