ohci-ep93xx.c revision e3a6d01932f343c1cc0218909262f0f68b6f7db4
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 31static struct clk *usb_host_clock; 32 33static void ep93xx_start_hc(struct device *dev) 34{ 35 clk_enable(usb_host_clock); 36} 37 38static void ep93xx_stop_hc(struct device *dev) 39{ 40 clk_disable(usb_host_clock); 41} 42 43static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, 44 struct platform_device *pdev) 45{ 46 int retval; 47 struct usb_hcd *hcd; 48 49 if (pdev->resource[1].flags != IORESOURCE_IRQ) { 50 dbg("resource[1] is not IORESOURCE_IRQ"); 51 return -ENOMEM; 52 } 53 54 hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx"); 55 if (hcd == NULL) 56 return -ENOMEM; 57 58 hcd->rsrc_start = pdev->resource[0].start; 59 hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; 60 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 61 usb_put_hcd(hcd); 62 retval = -EBUSY; 63 goto err1; 64 } 65 66 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 67 if (hcd->regs == NULL) { 68 dbg("ioremap failed"); 69 retval = -ENOMEM; 70 goto err2; 71 } 72 73 usb_host_clock = clk_get(&pdev->dev, NULL); 74 if (IS_ERR(usb_host_clock)) { 75 dbg("clk_get failed"); 76 retval = PTR_ERR(usb_host_clock); 77 goto err3; 78 } 79 80 ep93xx_start_hc(&pdev->dev); 81 82 ohci_hcd_init(hcd_to_ohci(hcd)); 83 84 retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); 85 if (retval == 0) 86 return retval; 87 88 ep93xx_stop_hc(&pdev->dev); 89err3: 90 iounmap(hcd->regs); 91err2: 92 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 93err1: 94 usb_put_hcd(hcd); 95 96 return retval; 97} 98 99static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd, 100 struct platform_device *pdev) 101{ 102 usb_remove_hcd(hcd); 103 ep93xx_stop_hc(&pdev->dev); 104 clk_put(usb_host_clock); 105 iounmap(hcd->regs); 106 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 107 usb_put_hcd(hcd); 108} 109 110static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd) 111{ 112 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 113 int ret; 114 115 if ((ret = ohci_init(ohci)) < 0) 116 return ret; 117 118 if ((ret = ohci_run(ohci)) < 0) { 119 err("can't start %s", hcd->self.bus_name); 120 ohci_stop(hcd); 121 return ret; 122 } 123 124 return 0; 125} 126 127static struct hc_driver ohci_ep93xx_hc_driver = { 128 .description = hcd_name, 129 .product_desc = "EP93xx OHCI", 130 .hcd_priv_size = sizeof(struct ohci_hcd), 131 .irq = ohci_irq, 132 .flags = HCD_USB11 | HCD_MEMORY, 133 .start = ohci_ep93xx_start, 134 .stop = ohci_stop, 135 .shutdown = ohci_shutdown, 136 .urb_enqueue = ohci_urb_enqueue, 137 .urb_dequeue = ohci_urb_dequeue, 138 .endpoint_disable = ohci_endpoint_disable, 139 .get_frame_number = ohci_get_frame, 140 .hub_status_data = ohci_hub_status_data, 141 .hub_control = ohci_hub_control, 142#ifdef CONFIG_PM 143 .bus_suspend = ohci_bus_suspend, 144 .bus_resume = ohci_bus_resume, 145#endif 146 .start_port_reset = ohci_start_port_reset, 147}; 148 149extern int usb_disabled(void); 150 151static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) 152{ 153 int ret; 154 155 ret = -ENODEV; 156 if (!usb_disabled()) 157 ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev); 158 159 return ret; 160} 161 162static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) 163{ 164 struct usb_hcd *hcd = platform_get_drvdata(pdev); 165 166 usb_hcd_ep93xx_remove(hcd, pdev); 167 168 return 0; 169} 170 171#ifdef CONFIG_PM 172static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) 173{ 174 struct usb_hcd *hcd = platform_get_drvdata(pdev); 175 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 176 177 if (time_before(jiffies, ohci->next_statechange)) 178 msleep(5); 179 ohci->next_statechange = jiffies; 180 181 ep93xx_stop_hc(&pdev->dev); 182 hcd->state = HC_STATE_SUSPENDED; 183 184 return 0; 185} 186 187static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) 188{ 189 struct usb_hcd *hcd = platform_get_drvdata(pdev); 190 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 191 int status; 192 193 if (time_before(jiffies, ohci->next_statechange)) 194 msleep(5); 195 ohci->next_statechange = jiffies; 196 197 ep93xx_start_hc(&pdev->dev); 198 199 ohci_finish_controller_resume(hcd); 200 return 0; 201} 202#endif 203 204 205static struct platform_driver ohci_hcd_ep93xx_driver = { 206 .probe = ohci_hcd_ep93xx_drv_probe, 207 .remove = ohci_hcd_ep93xx_drv_remove, 208 .shutdown = usb_hcd_platform_shutdown, 209#ifdef CONFIG_PM 210 .suspend = ohci_hcd_ep93xx_drv_suspend, 211 .resume = ohci_hcd_ep93xx_drv_resume, 212#endif 213 .driver = { 214 .name = "ep93xx-ohci", 215 .owner = THIS_MODULE, 216 }, 217}; 218 219MODULE_ALIAS("platform:ep93xx-ohci"); 220