Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc5 214 lines 5.1 kB view raw
1/* 2 * Copyright 2012 Tilera Corporation. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 11 * NON INFRINGEMENT. See the GNU General Public License for 12 * more details. 13 */ 14 15/* 16 * Tilera TILE-Gx USB EHCI host controller driver. 17 */ 18 19#include <linux/irq.h> 20#include <linux/platform_device.h> 21#include <linux/usb/tilegx.h> 22#include <linux/usb.h> 23 24#include <asm/homecache.h> 25 26#include <gxio/iorpc_usb_host.h> 27#include <gxio/usb_host.h> 28 29static void tilegx_start_ehc(void) 30{ 31} 32 33static void tilegx_stop_ehc(void) 34{ 35} 36 37static int tilegx_ehci_setup(struct usb_hcd *hcd) 38{ 39 int ret = ehci_init(hcd); 40 41 /* 42 * Some drivers do: 43 * 44 * struct ehci_hcd *ehci = hcd_to_ehci(hcd); 45 * ehci->need_io_watchdog = 0; 46 * 47 * here, but since this is a new driver we're going to leave the 48 * watchdog enabled. Later we may try to turn it off and see 49 * whether we run into any problems. 50 */ 51 52 return ret; 53} 54 55static const struct hc_driver ehci_tilegx_hc_driver = { 56 .description = hcd_name, 57 .product_desc = "Tile-Gx EHCI", 58 .hcd_priv_size = sizeof(struct ehci_hcd), 59 60 /* 61 * Generic hardware linkage. 62 */ 63 .irq = ehci_irq, 64 .flags = HCD_MEMORY | HCD_USB2, 65 66 /* 67 * Basic lifecycle operations. 68 */ 69 .reset = tilegx_ehci_setup, 70 .start = ehci_run, 71 .stop = ehci_stop, 72 .shutdown = ehci_shutdown, 73 74 /* 75 * Managing I/O requests and associated device resources. 76 */ 77 .urb_enqueue = ehci_urb_enqueue, 78 .urb_dequeue = ehci_urb_dequeue, 79 .endpoint_disable = ehci_endpoint_disable, 80 .endpoint_reset = ehci_endpoint_reset, 81 82 /* 83 * Scheduling support. 84 */ 85 .get_frame_number = ehci_get_frame, 86 87 /* 88 * Root hub support. 89 */ 90 .hub_status_data = ehci_hub_status_data, 91 .hub_control = ehci_hub_control, 92 .bus_suspend = ehci_bus_suspend, 93 .bus_resume = ehci_bus_resume, 94 .relinquish_port = ehci_relinquish_port, 95 .port_handed_over = ehci_port_handed_over, 96 97 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 98}; 99 100static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) 101{ 102 struct usb_hcd *hcd; 103 struct ehci_hcd *ehci; 104 struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; 105 pte_t pte = { 0 }; 106 int my_cpu = smp_processor_id(); 107 int ret; 108 109 if (usb_disabled()) 110 return -ENODEV; 111 112 /* 113 * Try to initialize our GXIO context; if we can't, the device 114 * doesn't exist. 115 */ 116 if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 1) != 0) 117 return -ENXIO; 118 119 hcd = usb_create_hcd(&ehci_tilegx_hc_driver, &pdev->dev, 120 dev_name(&pdev->dev)); 121 if (!hcd) 122 return -ENOMEM; 123 124 /* 125 * We don't use rsrc_start to map in our registers, but seems like 126 * we ought to set it to something, so we use the register VA. 127 */ 128 hcd->rsrc_start = 129 (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); 130 hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); 131 hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); 132 133 tilegx_start_ehc(); 134 135 ehci = hcd_to_ehci(hcd); 136 ehci->caps = hcd->regs; 137 ehci->regs = 138 hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); 139 /* cache this readonly data; minimize chip reads */ 140 ehci->hcs_params = readl(&ehci->caps->hcs_params); 141 142 /* Create our IRQs and register them. */ 143 pdata->irq = create_irq(); 144 if (pdata->irq < 0) { 145 ret = -ENXIO; 146 goto err_no_irq; 147 } 148 149 tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); 150 151 /* Configure interrupts. */ 152 ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, 153 cpu_x(my_cpu), cpu_y(my_cpu), 154 KERNEL_PL, pdata->irq); 155 if (ret) { 156 ret = -ENXIO; 157 goto err_have_irq; 158 } 159 160 /* Register all of our memory. */ 161 pte = pte_set_home(pte, PAGE_HOME_HASH); 162 ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); 163 if (ret) { 164 ret = -ENXIO; 165 goto err_have_irq; 166 } 167 168 ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); 169 if (ret == 0) { 170 platform_set_drvdata(pdev, hcd); 171 return ret; 172 } 173 174err_have_irq: 175 destroy_irq(pdata->irq); 176err_no_irq: 177 tilegx_stop_ehc(); 178 usb_put_hcd(hcd); 179 gxio_usb_host_destroy(&pdata->usb_ctx); 180 return ret; 181} 182 183static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) 184{ 185 struct usb_hcd *hcd = platform_get_drvdata(pdev); 186 struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; 187 188 usb_remove_hcd(hcd); 189 usb_put_hcd(hcd); 190 tilegx_stop_ehc(); 191 gxio_usb_host_destroy(&pdata->usb_ctx); 192 destroy_irq(pdata->irq); 193 platform_set_drvdata(pdev, NULL); 194 195 return 0; 196} 197 198static void ehci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) 199{ 200 usb_hcd_platform_shutdown(pdev); 201 ehci_hcd_tilegx_drv_remove(pdev); 202} 203 204static struct platform_driver ehci_hcd_tilegx_driver = { 205 .probe = ehci_hcd_tilegx_drv_probe, 206 .remove = ehci_hcd_tilegx_drv_remove, 207 .shutdown = ehci_hcd_tilegx_drv_shutdown, 208 .driver = { 209 .name = "tilegx-ehci", 210 .owner = THIS_MODULE, 211 } 212}; 213 214MODULE_ALIAS("platform:tilegx-ehci");