1 /* 2 * OHCI HCD (Host Controller Driver) for USB. 3 * 4 * Copyright (C) 2010 ST Microelectronics. 5 * Deepak Sikri<deepak.sikri@st.com> 6 * 7 * Based on various ohci-*.c drivers 8 * 9 * This file is licensed under the terms of the GNU General Public 10 * License version 2. This program is licensed "as is" without any 11 * warranty of any kind, whether express or implied. 12 */ 13 14 #include <linux/signal.h> 15 #include <linux/platform_device.h> 16 #include <linux/clk.h> 17 18 struct spear_ohci { 19 struct ohci_hcd ohci; 20 struct clk *clk; 21 }; 22 23 #define to_spear_ohci(hcd) (struct spear_ohci *)hcd_to_ohci(hcd) 24 25 static void spear_start_ohci(struct spear_ohci *ohci) 26 { 27 clk_enable(ohci->clk); 28 } 29 30 static void spear_stop_ohci(struct spear_ohci *ohci) 31 { 32 clk_disable(ohci->clk); 33 } 34 35 static int __devinit ohci_spear_start(struct usb_hcd *hcd) 36 { 37 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 38 int ret; 39 40 ret = ohci_init(ohci); 41 if (ret < 0) 42 return ret; 43 ohci->regs = hcd->regs; 44 45 ret = ohci_run(ohci); 46 if (ret < 0) { 47 dev_err(hcd->self.controller, "can't start\n"); 48 ohci_stop(hcd); 49 return ret; 50 } 51 52 create_debug_files(ohci); 53 54 #ifdef DEBUG 55 ohci_dump(ohci, 1); 56 #endif 57 return 0; 58 } 59 60 static const struct hc_driver ohci_spear_hc_driver = { 61 .description = hcd_name, 62 .product_desc = "SPEAr OHCI", 63 .hcd_priv_size = sizeof(struct spear_ohci), 64 65 /* generic hardware linkage */ 66 .irq = ohci_irq, 67 .flags = HCD_USB11 | HCD_MEMORY, 68 69 /* basic lifecycle operations */ 70 .start = ohci_spear_start, 71 .stop = ohci_stop, 72 .shutdown = ohci_shutdown, 73 #ifdef CONFIG_PM 74 .bus_suspend = ohci_bus_suspend, 75 .bus_resume = ohci_bus_resume, 76 #endif 77 78 /* managing i/o requests and associated device resources */ 79 .urb_enqueue = ohci_urb_enqueue, 80 .urb_dequeue = ohci_urb_dequeue, 81 .endpoint_disable = ohci_endpoint_disable, 82 83 /* scheduling support */ 84 .get_frame_number = ohci_get_frame, 85 86 /* root hub support */ 87 .hub_status_data = ohci_hub_status_data, 88 .hub_control = ohci_hub_control, 89 90 .start_port_reset = ohci_start_port_reset, 91 }; 92 93 static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) 94 { 95 const struct hc_driver *driver = &ohci_spear_hc_driver; 96 struct usb_hcd *hcd = NULL; 97 struct clk *usbh_clk; 98 struct spear_ohci *ohci_p; 99 struct resource *res; 100 int retval, irq; 101 int *pdata = pdev->dev.platform_data; 102 char clk_name[20] = "usbh_clk"; 103 104 if (pdata == NULL) 105 return -EFAULT; 106 107 irq = platform_get_irq(pdev, 0); 108 if (irq < 0) { 109 retval = irq; 110 goto fail_irq_get; 111 } 112 113 if (*pdata >= 0) 114 sprintf(clk_name, "usbh.%01d_clk", *pdata); 115 116 usbh_clk = clk_get(NULL, clk_name); 117 if (IS_ERR(usbh_clk)) { 118 dev_err(&pdev->dev, "Error getting interface clock\n"); 119 retval = PTR_ERR(usbh_clk); 120 goto fail_get_usbh_clk; 121 } 122 123 hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 124 if (!hcd) { 125 retval = -ENOMEM; 126 goto fail_create_hcd; 127 } 128 129 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 130 if (!res) { 131 retval = -ENODEV; 132 goto fail_request_resource; 133 } 134 135 hcd->rsrc_start = pdev->resource[0].start; 136 hcd->rsrc_len = resource_size(res); 137 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 138 dev_dbg(&pdev->dev, "request_mem_region failed\n"); 139 retval = -EBUSY; 140 goto fail_request_resource; 141 } 142 143 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 144 if (!hcd->regs) { 145 dev_dbg(&pdev->dev, "ioremap failed\n"); 146 retval = -ENOMEM; 147 goto fail_ioremap; 148 } 149 150 ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd); 151 ohci_p->clk = usbh_clk; 152 spear_start_ohci(ohci_p); 153 ohci_hcd_init(hcd_to_ohci(hcd)); 154 155 retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0); 156 if (retval == 0) 157 return retval; 158 159 spear_stop_ohci(ohci_p); 160 iounmap(hcd->regs); 161 fail_ioremap: 162 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 163 fail_request_resource: 164 usb_put_hcd(hcd); 165 fail_create_hcd: 166 clk_put(usbh_clk); 167 fail_get_usbh_clk: 168 fail_irq_get: 169 dev_err(&pdev->dev, "init fail, %d\n", retval); 170 171 return retval; 172 } 173 174 static int spear_ohci_hcd_drv_remove(struct platform_device *pdev) 175 { 176 struct usb_hcd *hcd = platform_get_drvdata(pdev); 177 struct spear_ohci *ohci_p = to_spear_ohci(hcd); 178 179 usb_remove_hcd(hcd); 180 if (ohci_p->clk) 181 spear_stop_ohci(ohci_p); 182 183 iounmap(hcd->regs); 184 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 185 usb_put_hcd(hcd); 186 187 if (ohci_p->clk) 188 clk_put(ohci_p->clk); 189 platform_set_drvdata(pdev, NULL); 190 return 0; 191 } 192 193 #if defined(CONFIG_PM) 194 static int spear_ohci_hcd_drv_suspend(struct platform_device *dev, 195 pm_message_t message) 196 { 197 struct usb_hcd *hcd = platform_get_drvdata(dev); 198 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 199 struct spear_ohci *ohci_p = to_spear_ohci(hcd); 200 201 if (time_before(jiffies, ohci->next_statechange)) 202 msleep(5); 203 ohci->next_statechange = jiffies; 204 205 spear_stop_ohci(ohci_p); 206 return 0; 207 } 208 209 static int spear_ohci_hcd_drv_resume(struct platform_device *dev) 210 { 211 struct usb_hcd *hcd = platform_get_drvdata(dev); 212 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 213 struct spear_ohci *ohci_p = to_spear_ohci(hcd); 214 215 if (time_before(jiffies, ohci->next_statechange)) 216 msleep(5); 217 ohci->next_statechange = jiffies; 218 219 spear_start_ohci(ohci_p); 220 ohci_finish_controller_resume(hcd); 221 return 0; 222 } 223 #endif 224 225 /* Driver definition to register with the platform bus */ 226 static struct platform_driver spear_ohci_hcd_driver = { 227 .probe = spear_ohci_hcd_drv_probe, 228 .remove = spear_ohci_hcd_drv_remove, 229 #ifdef CONFIG_PM 230 .suspend = spear_ohci_hcd_drv_suspend, 231 .resume = spear_ohci_hcd_drv_resume, 232 #endif 233 .driver = { 234 .owner = THIS_MODULE, 235 .name = "spear-ohci", 236 }, 237 }; 238 239 MODULE_ALIAS("platform:spear-ohci"); 240