1 /* 2 * Driver for EHCI UHP on Atmel chips 3 * 4 * Copyright (C) 2009 Atmel Corporation, 5 * Nicolas Ferre <nicolas.ferre@atmel.com> 6 * 7 * Based on various ehci-*.c drivers 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file COPYING in the main directory of this archive for 11 * more details. 12 */ 13 14 #include <linux/clk.h> 15 #include <linux/platform_device.h> 16 #include <linux/of.h> 17 #include <linux/of_platform.h> 18 19 /* interface and function clocks */ 20 static struct clk *iclk, *fclk; 21 static int clocked; 22 23 /*-------------------------------------------------------------------------*/ 24 25 static void atmel_start_clock(void) 26 { 27 clk_enable(iclk); 28 clk_enable(fclk); 29 clocked = 1; 30 } 31 32 static void atmel_stop_clock(void) 33 { 34 clk_disable(fclk); 35 clk_disable(iclk); 36 clocked = 0; 37 } 38 39 static void atmel_start_ehci(struct platform_device *pdev) 40 { 41 dev_dbg(&pdev->dev, "start\n"); 42 atmel_start_clock(); 43 } 44 45 static void atmel_stop_ehci(struct platform_device *pdev) 46 { 47 dev_dbg(&pdev->dev, "stop\n"); 48 atmel_stop_clock(); 49 } 50 51 /*-------------------------------------------------------------------------*/ 52 53 static int ehci_atmel_setup(struct usb_hcd *hcd) 54 { 55 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 56 int retval = 0; 57 58 /* registers start at offset 0x0 */ 59 ehci->caps = hcd->regs; 60 ehci->regs = hcd->regs + 61 HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); 62 dbg_hcs_params(ehci, "reset"); 63 dbg_hcc_params(ehci, "reset"); 64 65 /* cache this readonly data; minimize chip reads */ 66 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 67 68 retval = ehci_halt(ehci); 69 if (retval) 70 return retval; 71 72 /* data structure init */ 73 retval = ehci_init(hcd); 74 if (retval) 75 return retval; 76 77 ehci->sbrn = 0x20; 78 79 ehci_reset(ehci); 80 ehci_port_power(ehci, 0); 81 82 return retval; 83 } 84 85 static const struct hc_driver ehci_atmel_hc_driver = { 86 .description = hcd_name, 87 .product_desc = "Atmel EHCI UHP HS", 88 .hcd_priv_size = sizeof(struct ehci_hcd), 89 90 /* generic hardware linkage */ 91 .irq = ehci_irq, 92 .flags = HCD_MEMORY | HCD_USB2, 93 94 /* basic lifecycle operations */ 95 .reset = ehci_atmel_setup, 96 .start = ehci_run, 97 .stop = ehci_stop, 98 .shutdown = ehci_shutdown, 99 100 /* managing i/o requests and associated device resources */ 101 .urb_enqueue = ehci_urb_enqueue, 102 .urb_dequeue = ehci_urb_dequeue, 103 .endpoint_disable = ehci_endpoint_disable, 104 .endpoint_reset = ehci_endpoint_reset, 105 106 /* scheduling support */ 107 .get_frame_number = ehci_get_frame, 108 109 /* root hub support */ 110 .hub_status_data = ehci_hub_status_data, 111 .hub_control = ehci_hub_control, 112 .bus_suspend = ehci_bus_suspend, 113 .bus_resume = ehci_bus_resume, 114 .relinquish_port = ehci_relinquish_port, 115 .port_handed_over = ehci_port_handed_over, 116 117 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 118 }; 119 120 static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32); 121 122 static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev) 123 { 124 struct usb_hcd *hcd; 125 const struct hc_driver *driver = &ehci_atmel_hc_driver; 126 struct resource *res; 127 int irq; 128 int retval; 129 130 if (usb_disabled()) 131 return -ENODEV; 132 133 pr_debug("Initializing Atmel-SoC USB Host Controller\n"); 134 135 irq = platform_get_irq(pdev, 0); 136 if (irq <= 0) { 137 dev_err(&pdev->dev, 138 "Found HC with no IRQ. Check %s setup!\n", 139 dev_name(&pdev->dev)); 140 retval = -ENODEV; 141 goto fail_create_hcd; 142 } 143 144 /* Right now device-tree probed devices don't get dma_mask set. 145 * Since shared usb code relies on it, set it here for now. 146 * Once we have dma capability bindings this can go away. 147 */ 148 if (!pdev->dev.dma_mask) 149 pdev->dev.dma_mask = &at91_ehci_dma_mask; 150 151 hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 152 if (!hcd) { 153 retval = -ENOMEM; 154 goto fail_create_hcd; 155 } 156 157 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 158 if (!res) { 159 dev_err(&pdev->dev, 160 "Found HC with no register addr. Check %s setup!\n", 161 dev_name(&pdev->dev)); 162 retval = -ENODEV; 163 goto fail_request_resource; 164 } 165 hcd->rsrc_start = res->start; 166 hcd->rsrc_len = resource_size(res); 167 168 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, 169 driver->description)) { 170 dev_dbg(&pdev->dev, "controller already in use\n"); 171 retval = -EBUSY; 172 goto fail_request_resource; 173 } 174 175 hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); 176 if (hcd->regs == NULL) { 177 dev_dbg(&pdev->dev, "error mapping memory\n"); 178 retval = -EFAULT; 179 goto fail_ioremap; 180 } 181 182 iclk = clk_get(&pdev->dev, "ehci_clk"); 183 if (IS_ERR(iclk)) { 184 dev_err(&pdev->dev, "Error getting interface clock\n"); 185 retval = -ENOENT; 186 goto fail_get_iclk; 187 } 188 fclk = clk_get(&pdev->dev, "uhpck"); 189 if (IS_ERR(fclk)) { 190 dev_err(&pdev->dev, "Error getting function clock\n"); 191 retval = -ENOENT; 192 goto fail_get_fclk; 193 } 194 195 atmel_start_ehci(pdev); 196 197 retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 198 if (retval) 199 goto fail_add_hcd; 200 201 return retval; 202 203 fail_add_hcd: 204 atmel_stop_ehci(pdev); 205 clk_put(fclk); 206 fail_get_fclk: 207 clk_put(iclk); 208 fail_get_iclk: 209 iounmap(hcd->regs); 210 fail_ioremap: 211 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 212 fail_request_resource: 213 usb_put_hcd(hcd); 214 fail_create_hcd: 215 dev_err(&pdev->dev, "init %s fail, %d\n", 216 dev_name(&pdev->dev), retval); 217 218 return retval; 219 } 220 221 static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev) 222 { 223 struct usb_hcd *hcd = platform_get_drvdata(pdev); 224 225 ehci_shutdown(hcd); 226 usb_remove_hcd(hcd); 227 iounmap(hcd->regs); 228 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 229 usb_put_hcd(hcd); 230 231 atmel_stop_ehci(pdev); 232 clk_put(fclk); 233 clk_put(iclk); 234 fclk = iclk = NULL; 235 236 return 0; 237 } 238 239 #ifdef CONFIG_OF 240 static const struct of_device_id atmel_ehci_dt_ids[] = { 241 { .compatible = "atmel,at91sam9g45-ehci" }, 242 { /* sentinel */ } 243 }; 244 245 MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids); 246 #endif 247 248 static struct platform_driver ehci_atmel_driver = { 249 .probe = ehci_atmel_drv_probe, 250 .remove = __devexit_p(ehci_atmel_drv_remove), 251 .shutdown = usb_hcd_platform_shutdown, 252 .driver = { 253 .name = "atmel-ehci", 254 .of_match_table = of_match_ptr(atmel_ehci_dt_ids), 255 }, 256 }; 257