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-rc4 203 lines 4.6 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 OHCI 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_ohc(void) 30{ 31} 32 33static void tilegx_stop_ohc(void) 34{ 35} 36 37static int tilegx_ohci_start(struct usb_hcd *hcd) 38{ 39 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 40 int ret; 41 42 ret = ohci_init(ohci); 43 if (ret < 0) 44 return ret; 45 46 ret = ohci_run(ohci); 47 if (ret < 0) { 48 dev_err(hcd->self.controller, "can't start %s\n", 49 hcd->self.bus_name); 50 ohci_stop(hcd); 51 return ret; 52 } 53 54 return 0; 55} 56 57static const struct hc_driver ohci_tilegx_hc_driver = { 58 .description = hcd_name, 59 .product_desc = "Tile-Gx OHCI", 60 .hcd_priv_size = sizeof(struct ohci_hcd), 61 62 /* 63 * Generic hardware linkage. 64 */ 65 .irq = ohci_irq, 66 .flags = HCD_MEMORY | HCD_LOCAL_MEM | HCD_USB11, 67 68 /* 69 * Basic lifecycle operations. 70 */ 71 .start = tilegx_ohci_start, 72 .stop = ohci_stop, 73 .shutdown = ohci_shutdown, 74 75 /* 76 * Managing I/O requests and associated device resources. 77 */ 78 .urb_enqueue = ohci_urb_enqueue, 79 .urb_dequeue = ohci_urb_dequeue, 80 .endpoint_disable = ohci_endpoint_disable, 81 82 /* 83 * Scheduling support. 84 */ 85 .get_frame_number = ohci_get_frame, 86 87 /* 88 * Root hub support. 89 */ 90 .hub_status_data = ohci_hub_status_data, 91 .hub_control = ohci_hub_control, 92 .start_port_reset = ohci_start_port_reset, 93}; 94 95static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) 96{ 97 struct usb_hcd *hcd; 98 struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; 99 pte_t pte = { 0 }; 100 int my_cpu = smp_processor_id(); 101 int ret; 102 103 if (usb_disabled()) 104 return -ENODEV; 105 106 /* 107 * Try to initialize our GXIO context; if we can't, the device 108 * doesn't exist. 109 */ 110 if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 0) != 0) 111 return -ENXIO; 112 113 hcd = usb_create_hcd(&ohci_tilegx_hc_driver, &pdev->dev, 114 dev_name(&pdev->dev)); 115 if (!hcd) 116 return -ENOMEM; 117 118 /* 119 * We don't use rsrc_start to map in our registers, but seems like 120 * we ought to set it to something, so we use the register VA. 121 */ 122 hcd->rsrc_start = 123 (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); 124 hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); 125 hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); 126 127 tilegx_start_ohc(); 128 129 /* Create our IRQs and register them. */ 130 pdata->irq = create_irq(); 131 if (pdata->irq < 0) { 132 ret = -ENXIO; 133 goto err_no_irq; 134 } 135 136 tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); 137 138 /* Configure interrupts. */ 139 ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, 140 cpu_x(my_cpu), cpu_y(my_cpu), 141 KERNEL_PL, pdata->irq); 142 if (ret) { 143 ret = -ENXIO; 144 goto err_have_irq; 145 } 146 147 /* Register all of our memory. */ 148 pte = pte_set_home(pte, PAGE_HOME_HASH); 149 ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); 150 if (ret) { 151 ret = -ENXIO; 152 goto err_have_irq; 153 } 154 155 ohci_hcd_init(hcd_to_ohci(hcd)); 156 157 ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); 158 if (ret == 0) { 159 platform_set_drvdata(pdev, hcd); 160 return ret; 161 } 162 163err_have_irq: 164 destroy_irq(pdata->irq); 165err_no_irq: 166 tilegx_stop_ohc(); 167 usb_put_hcd(hcd); 168 gxio_usb_host_destroy(&pdata->usb_ctx); 169 return ret; 170} 171 172static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) 173{ 174 struct usb_hcd *hcd = platform_get_drvdata(pdev); 175 struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data; 176 177 usb_remove_hcd(hcd); 178 usb_put_hcd(hcd); 179 tilegx_stop_ohc(); 180 gxio_usb_host_destroy(&pdata->usb_ctx); 181 destroy_irq(pdata->irq); 182 platform_set_drvdata(pdev, NULL); 183 184 return 0; 185} 186 187static void ohci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) 188{ 189 usb_hcd_platform_shutdown(pdev); 190 ohci_hcd_tilegx_drv_remove(pdev); 191} 192 193static struct platform_driver ohci_hcd_tilegx_driver = { 194 .probe = ohci_hcd_tilegx_drv_probe, 195 .remove = ohci_hcd_tilegx_drv_remove, 196 .shutdown = ohci_hcd_tilegx_drv_shutdown, 197 .driver = { 198 .name = "tilegx-ohci", 199 .owner = THIS_MODULE, 200 } 201}; 202 203MODULE_ALIAS("platform:tilegx-ohci");