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

USB: Add EHCI bus glue for Loongson1x SoCs (UPDATED)

Use ehci_setup() in ehci_ls1x_reset().

The Loongson1x SoCs have a built-in EHCI controller.
This patch adds the necessary glue code to make the generic EHCI
driver usable for them.

Signed-off-by: Kelvin Cheung <keguang.zhang@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Kelvin Cheung and committed by
Greg Kroah-Hartman
f30cdbcb 761bbcb7

+165
+1
drivers/usb/Kconfig
··· 76 76 default y if MICROBLAZE 77 77 default y if SPARC_LEON 78 78 default y if ARCH_MMP 79 + default y if MACH_LOONGSON1 79 80 default PCI 80 81 81 82 # some non-PCI HCDs implement xHCI
+5
drivers/usb/host/ehci-hcd.c
··· 1376 1376 #define PLATFORM_DRIVER ehci_mv_driver 1377 1377 #endif 1378 1378 1379 + #ifdef CONFIG_MACH_LOONGSON1 1380 + #include "ehci-ls1x.c" 1381 + #define PLATFORM_DRIVER ehci_ls1x_driver 1382 + #endif 1383 + 1379 1384 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ 1380 1385 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ 1381 1386 !defined(XILINX_OF_PLATFORM_DRIVER)
+159
drivers/usb/host/ehci-ls1x.c
··· 1 + /* 2 + * Bus Glue for Loongson LS1X built-in EHCI controller. 3 + * 4 + * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License version 2 as published 8 + * by the Free Software Foundation. 9 + */ 10 + 11 + 12 + #include <linux/platform_device.h> 13 + 14 + static int ehci_ls1x_reset(struct usb_hcd *hcd) 15 + { 16 + struct ehci_hcd *ehci = hcd_to_ehci(hcd); 17 + int ret; 18 + 19 + ehci->caps = hcd->regs; 20 + 21 + ret = ehci_setup(hcd); 22 + if (ret) 23 + return ret; 24 + 25 + ehci_port_power(ehci, 0); 26 + 27 + return 0; 28 + } 29 + 30 + static const struct hc_driver ehci_ls1x_hc_driver = { 31 + .description = hcd_name, 32 + .product_desc = "LOONGSON1 EHCI", 33 + .hcd_priv_size = sizeof(struct ehci_hcd), 34 + 35 + /* 36 + * generic hardware linkage 37 + */ 38 + .irq = ehci_irq, 39 + .flags = HCD_MEMORY | HCD_USB2, 40 + 41 + /* 42 + * basic lifecycle operations 43 + */ 44 + .reset = ehci_ls1x_reset, 45 + .start = ehci_run, 46 + .stop = ehci_stop, 47 + .shutdown = ehci_shutdown, 48 + 49 + /* 50 + * managing i/o requests and associated device resources 51 + */ 52 + .urb_enqueue = ehci_urb_enqueue, 53 + .urb_dequeue = ehci_urb_dequeue, 54 + .endpoint_disable = ehci_endpoint_disable, 55 + .endpoint_reset = ehci_endpoint_reset, 56 + 57 + /* 58 + * scheduling support 59 + */ 60 + .get_frame_number = ehci_get_frame, 61 + 62 + /* 63 + * root hub support 64 + */ 65 + .hub_status_data = ehci_hub_status_data, 66 + .hub_control = ehci_hub_control, 67 + .relinquish_port = ehci_relinquish_port, 68 + .port_handed_over = ehci_port_handed_over, 69 + 70 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 71 + }; 72 + 73 + static int ehci_hcd_ls1x_probe(struct platform_device *pdev) 74 + { 75 + struct usb_hcd *hcd; 76 + struct resource *res; 77 + int irq; 78 + int ret; 79 + 80 + pr_debug("initializing loongson1 ehci USB Controller\n"); 81 + 82 + if (usb_disabled()) 83 + return -ENODEV; 84 + 85 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 86 + if (!res) { 87 + dev_err(&pdev->dev, 88 + "Found HC with no IRQ. Check %s setup!\n", 89 + dev_name(&pdev->dev)); 90 + return -ENODEV; 91 + } 92 + irq = res->start; 93 + 94 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 95 + if (!res) { 96 + dev_err(&pdev->dev, 97 + "Found HC with no register addr. Check %s setup!\n", 98 + dev_name(&pdev->dev)); 99 + return -ENODEV; 100 + } 101 + 102 + hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev, 103 + dev_name(&pdev->dev)); 104 + if (!hcd) 105 + return -ENOMEM; 106 + hcd->rsrc_start = res->start; 107 + hcd->rsrc_len = resource_size(res); 108 + 109 + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 110 + dev_dbg(&pdev->dev, "controller already in use\n"); 111 + ret = -EBUSY; 112 + goto err_put_hcd; 113 + } 114 + 115 + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 116 + if (hcd->regs == NULL) { 117 + dev_dbg(&pdev->dev, "error mapping memory\n"); 118 + ret = -EFAULT; 119 + goto err_release_region; 120 + } 121 + 122 + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); 123 + if (ret) 124 + goto err_iounmap; 125 + 126 + return ret; 127 + 128 + err_iounmap: 129 + iounmap(hcd->regs); 130 + err_release_region: 131 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 132 + err_put_hcd: 133 + usb_put_hcd(hcd); 134 + return ret; 135 + } 136 + 137 + static int ehci_hcd_ls1x_remove(struct platform_device *pdev) 138 + { 139 + struct usb_hcd *hcd = platform_get_drvdata(pdev); 140 + 141 + usb_remove_hcd(hcd); 142 + iounmap(hcd->regs); 143 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 144 + usb_put_hcd(hcd); 145 + 146 + return 0; 147 + } 148 + 149 + static struct platform_driver ehci_ls1x_driver = { 150 + .probe = ehci_hcd_ls1x_probe, 151 + .remove = ehci_hcd_ls1x_remove, 152 + .shutdown = usb_hcd_platform_shutdown, 153 + .driver = { 154 + .name = "ls1x-ehci", 155 + .owner = THIS_MODULE, 156 + }, 157 + }; 158 + 159 + MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");