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.18-rc5 202 lines 4.0 kB view raw
1/* 2 * EHCI HCD glue for Cavium Octeon II SOCs. 3 * 4 * Loosely based on ehci-au1xxx.c 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 * 10 * Copyright (C) 2010 Cavium Networks 11 * 12 */ 13 14#include <linux/platform_device.h> 15 16#include <asm/octeon/octeon.h> 17#include <asm/octeon/cvmx-uctlx-defs.h> 18 19#define OCTEON_OHCI_HCD_NAME "octeon-ohci" 20 21/* Common clock init code. */ 22void octeon2_usb_clocks_start(void); 23void octeon2_usb_clocks_stop(void); 24 25static void ohci_octeon_hw_start(void) 26{ 27 union cvmx_uctlx_ohci_ctl ohci_ctl; 28 29 octeon2_usb_clocks_start(); 30 31 ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); 32 ohci_ctl.s.l2c_addr_msb = 0; 33 ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 34 ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 35 cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); 36 37} 38 39static void ohci_octeon_hw_stop(void) 40{ 41 /* Undo ohci_octeon_start() */ 42 octeon2_usb_clocks_stop(); 43} 44 45static int ohci_octeon_start(struct usb_hcd *hcd) 46{ 47 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 48 int ret; 49 50 ret = ohci_init(ohci); 51 52 if (ret < 0) 53 return ret; 54 55 ret = ohci_run(ohci); 56 57 if (ret < 0) { 58 ohci_err(ohci, "can't start %s", hcd->self.bus_name); 59 ohci_stop(hcd); 60 return ret; 61 } 62 63 return 0; 64} 65 66static const struct hc_driver ohci_octeon_hc_driver = { 67 .description = hcd_name, 68 .product_desc = "Octeon OHCI", 69 .hcd_priv_size = sizeof(struct ohci_hcd), 70 71 /* 72 * generic hardware linkage 73 */ 74 .irq = ohci_irq, 75 .flags = HCD_USB11 | HCD_MEMORY, 76 77 /* 78 * basic lifecycle operations 79 */ 80 .start = ohci_octeon_start, 81 .stop = ohci_stop, 82 .shutdown = ohci_shutdown, 83 84 /* 85 * managing i/o requests and associated device resources 86 */ 87 .urb_enqueue = ohci_urb_enqueue, 88 .urb_dequeue = ohci_urb_dequeue, 89 .endpoint_disable = ohci_endpoint_disable, 90 91 /* 92 * scheduling support 93 */ 94 .get_frame_number = ohci_get_frame, 95 96 /* 97 * root hub support 98 */ 99 .hub_status_data = ohci_hub_status_data, 100 .hub_control = ohci_hub_control, 101 102 .start_port_reset = ohci_start_port_reset, 103}; 104 105static int ohci_octeon_drv_probe(struct platform_device *pdev) 106{ 107 struct usb_hcd *hcd; 108 struct ohci_hcd *ohci; 109 void *reg_base; 110 struct resource *res_mem; 111 int irq; 112 int ret; 113 114 if (usb_disabled()) 115 return -ENODEV; 116 117 irq = platform_get_irq(pdev, 0); 118 if (irq < 0) { 119 dev_err(&pdev->dev, "No irq assigned\n"); 120 return -ENODEV; 121 } 122 123 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 124 if (res_mem == NULL) { 125 dev_err(&pdev->dev, "No register space assigned\n"); 126 return -ENODEV; 127 } 128 129 /* Ohci is a 32-bit device. */ 130 ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 131 if (ret) 132 return ret; 133 134 hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); 135 if (!hcd) 136 return -ENOMEM; 137 138 hcd->rsrc_start = res_mem->start; 139 hcd->rsrc_len = resource_size(res_mem); 140 141 reg_base = devm_ioremap_resource(&pdev->dev, res_mem); 142 if (IS_ERR(reg_base)) { 143 ret = PTR_ERR(reg_base); 144 goto err1; 145 } 146 147 ohci_octeon_hw_start(); 148 149 hcd->regs = reg_base; 150 151 ohci = hcd_to_ohci(hcd); 152 153 /* Octeon OHCI matches CPU endianness. */ 154#ifdef __BIG_ENDIAN 155 ohci->flags |= OHCI_QUIRK_BE_MMIO; 156#endif 157 158 ohci_hcd_init(ohci); 159 160 ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 161 if (ret) { 162 dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); 163 goto err2; 164 } 165 166 device_wakeup_enable(hcd->self.controller); 167 168 platform_set_drvdata(pdev, hcd); 169 170 return 0; 171 172err2: 173 ohci_octeon_hw_stop(); 174 175err1: 176 usb_put_hcd(hcd); 177 return ret; 178} 179 180static int ohci_octeon_drv_remove(struct platform_device *pdev) 181{ 182 struct usb_hcd *hcd = platform_get_drvdata(pdev); 183 184 usb_remove_hcd(hcd); 185 186 ohci_octeon_hw_stop(); 187 usb_put_hcd(hcd); 188 189 return 0; 190} 191 192static struct platform_driver ohci_octeon_driver = { 193 .probe = ohci_octeon_drv_probe, 194 .remove = ohci_octeon_drv_remove, 195 .shutdown = usb_hcd_platform_shutdown, 196 .driver = { 197 .name = OCTEON_OHCI_HCD_NAME, 198 .owner = THIS_MODULE, 199 } 200}; 201 202MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME);