1/* 2 * OHCI HCD (Host Controller Driver) for USB. 3 * 4 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> 5 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> 6 * (C) Copyright 2002 Hewlett-Packard Company 7 * 8 * Bus Glue for ep93xx. 9 * 10 * Written by Christopher Hoover <ch@hpl.hp.com> 11 * Based on fragments of previous driver by Russell King et al. 12 * 13 * Modified for LH7A404 from ohci-sa1111.c 14 * by Durgesh Pattamatta <pattamattad@sharpsec.com> 15 * 16 * Modified for pxa27x from ohci-lh7a404.c 17 * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004 18 * 19 * Modified for ep93xx from ohci-pxa27x.c 20 * by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006 21 * Based on an earlier driver by Ray Lehtiniemi 22 * 23 * This file is licenced under the GPL. 24 */ 25 26#include <linux/clk.h> 27#include <linux/device.h> 28#include <linux/signal.h> 29#include <linux/platform_device.h> 30 31#include <asm/mach-types.h> 32#include <asm/hardware.h> 33 34static struct clk *usb_host_clock; 35 36static void ep93xx_start_hc(struct device *dev) 37{ 38 clk_enable(usb_host_clock); 39} 40 41static void ep93xx_stop_hc(struct device *dev) 42{ 43 clk_disable(usb_host_clock); 44} 45 46static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, 47 struct platform_device *pdev) 48{ 49 int retval; 50 struct usb_hcd *hcd; 51 52 if (pdev->resource[1].flags != IORESOURCE_IRQ) { 53 pr_debug("resource[1] is not IORESOURCE_IRQ"); 54 return -ENOMEM; 55 } 56 57 hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx"); 58 if (hcd == NULL) 59 return -ENOMEM; 60 61 hcd->rsrc_start = pdev->resource[0].start; 62 hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; 63 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 64 usb_put_hcd(hcd); 65 retval = -EBUSY; 66 goto err1; 67 } 68 69 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 70 if (hcd->regs == NULL) { 71 pr_debug("ioremap failed"); 72 retval = -ENOMEM; 73 goto err2; 74 } 75 76 usb_host_clock = clk_get(&pdev->dev, "usb_host"); 77 ep93xx_start_hc(&pdev->dev); 78 79 ohci_hcd_init(hcd_to_ohci(hcd)); 80 81 retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); 82 if (retval == 0) 83 return retval; 84 85 ep93xx_stop_hc(&pdev->dev); 86 iounmap(hcd->regs); 87err2: 88 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 89err1: 90 usb_put_hcd(hcd); 91 92 return retval; 93} 94 95static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd, 96 struct platform_device *pdev) 97{ 98 usb_remove_hcd(hcd); 99 ep93xx_stop_hc(&pdev->dev); 100 clk_put(usb_host_clock); 101 iounmap(hcd->regs); 102 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 103 usb_put_hcd(hcd); 104} 105 106static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd) 107{ 108 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 109 int ret; 110 111 if ((ret = ohci_init(ohci)) < 0) 112 return ret; 113 114 if ((ret = ohci_run(ohci)) < 0) { 115 err("can't start %s", hcd->self.bus_name); 116 ohci_stop(hcd); 117 return ret; 118 } 119 120 return 0; 121} 122 123static struct hc_driver ohci_ep93xx_hc_driver = { 124 .description = hcd_name, 125 .product_desc = "EP93xx OHCI", 126 .hcd_priv_size = sizeof(struct ohci_hcd), 127 .irq = ohci_irq, 128 .flags = HCD_USB11 | HCD_MEMORY, 129 .start = ohci_ep93xx_start, 130 .stop = ohci_stop, 131 .shutdown = ohci_shutdown, 132 .urb_enqueue = ohci_urb_enqueue, 133 .urb_dequeue = ohci_urb_dequeue, 134 .endpoint_disable = ohci_endpoint_disable, 135 .get_frame_number = ohci_get_frame, 136 .hub_status_data = ohci_hub_status_data, 137 .hub_control = ohci_hub_control, 138 .hub_irq_enable = ohci_rhsc_enable, 139#ifdef CONFIG_PM 140 .bus_suspend = ohci_bus_suspend, 141 .bus_resume = ohci_bus_resume, 142#endif 143 .start_port_reset = ohci_start_port_reset, 144}; 145 146extern int usb_disabled(void); 147 148static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) 149{ 150 int ret; 151 152 ret = -ENODEV; 153 if (!usb_disabled()) 154 ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev); 155 156 return ret; 157} 158 159static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) 160{ 161 struct usb_hcd *hcd = platform_get_drvdata(pdev); 162 163 usb_hcd_ep93xx_remove(hcd, pdev); 164 165 return 0; 166} 167 168#ifdef CONFIG_PM 169static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) 170{ 171 struct usb_hcd *hcd = platform_get_drvdata(pdev); 172 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 173 174 if (time_before(jiffies, ohci->next_statechange)) 175 msleep(5); 176 ohci->next_statechange = jiffies; 177 178 ep93xx_stop_hc(&pdev->dev); 179 hcd->state = HC_STATE_SUSPENDED; 180 pdev->dev.power.power_state = PMSG_SUSPEND; 181 182 return 0; 183} 184 185static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) 186{ 187 struct usb_hcd *hcd = platform_get_drvdata(pdev); 188 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 189 int status; 190 191 if (time_before(jiffies, ohci->next_statechange)) 192 msleep(5); 193 ohci->next_statechange = jiffies; 194 195 ep93xx_start_hc(&pdev->dev); 196 pdev->dev.power.power_state = PMSG_ON; 197 usb_hcd_resume_root_hub(hcd); 198 199 return 0; 200} 201#endif 202 203 204static struct platform_driver ohci_hcd_ep93xx_driver = { 205 .probe = ohci_hcd_ep93xx_drv_probe, 206 .remove = ohci_hcd_ep93xx_drv_remove, 207 .shutdown = usb_hcd_platform_shutdown, 208#ifdef CONFIG_PM 209 .suspend = ohci_hcd_ep93xx_drv_suspend, 210 .resume = ohci_hcd_ep93xx_drv_resume, 211#endif 212 .driver = { 213 .name = "ep93xx-ohci", 214 }, 215}; 216