1/* 2 * Bus Glue for the built-in OHCI controller of the Ralink RT3662/RT3883 SoCs 3 * 4 * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> 5 * 6 * Parts of this file are based on Ralink's 2.6.21 BSP 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License version 2 as published 10 * by the Free Software Foundation. 11 */ 12 13#include <linux/platform_device.h> 14#include <asm/mach-ralink/rt3883.h> 15#include <asm/mach-ralink/rt3883_ohci_platform.h> 16 17static int __devinit ohci_rt3883_start(struct usb_hcd *hcd) 18{ 19 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 20 int ret; 21 22 ret = ohci_init(ohci); 23 if (ret < 0) 24 return ret; 25 26 ret = ohci_run(ohci); 27 if (ret < 0) 28 goto err; 29 30 return 0; 31 32err: 33 ohci_stop(hcd); 34 return ret; 35} 36 37static const struct hc_driver ohci_rt3883_hc_driver = { 38 .description = hcd_name, 39 .product_desc = "Ralink RT3883 built-in OHCI controller", 40 .hcd_priv_size = sizeof(struct ohci_hcd), 41 42 .irq = ohci_irq, 43 .flags = HCD_USB11 | HCD_MEMORY, 44 45 .start = ohci_rt3883_start, 46 .stop = ohci_stop, 47 .shutdown = ohci_shutdown, 48 49 .urb_enqueue = ohci_urb_enqueue, 50 .urb_dequeue = ohci_urb_dequeue, 51 .endpoint_disable = ohci_endpoint_disable, 52 53 /* 54 * scheduling support 55 */ 56 .get_frame_number = ohci_get_frame, 57 58 /* 59 * root hub support 60 */ 61 .hub_status_data = ohci_hub_status_data, 62 .hub_control = ohci_hub_control, 63 .start_port_reset = ohci_start_port_reset, 64}; 65 66static int ohci_rt3883_probe(struct platform_device *pdev) 67{ 68 struct rt3883_ohci_platform_data *pdata; 69 struct usb_hcd *hcd; 70 struct resource *res; 71 int irq; 72 int ret; 73 74 if (usb_disabled()) 75 return -ENODEV; 76 77 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 78 if (!res) { 79 dev_dbg(&pdev->dev, "no IRQ specified for %s\n", 80 dev_name(&pdev->dev)); 81 return -ENODEV; 82 } 83 irq = res->start; 84 85 hcd = usb_create_hcd(&ohci_rt3883_hc_driver, 86 &pdev->dev, dev_name(&pdev->dev)); 87 if (!hcd) 88 return -ENOMEM; 89 90 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 91 if (!res) { 92 dev_dbg(&pdev->dev, "no base address specified for %s\n", 93 dev_name(&pdev->dev)); 94 ret = -ENODEV; 95 goto err_put_hcd; 96 } 97 hcd->rsrc_start = res->start; 98 hcd->rsrc_len = res->end - res->start + 1; 99 100 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 101 dev_dbg(&pdev->dev, "controller already in use\n"); 102 ret = -EBUSY; 103 goto err_put_hcd; 104 } 105 106 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 107 if (!hcd->regs) { 108 dev_dbg(&pdev->dev, "error mapping memory\n"); 109 ret = -EFAULT; 110 goto err_release_region; 111 } 112 113 pdata = pdev->dev.platform_data; 114 if (pdata && pdata->start_hw) 115 pdata->start_hw(); 116 117 ohci_hcd_init(hcd_to_ohci(hcd)); 118 119 ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 120 if (ret) 121 goto err_stop_hcd; 122 123 return 0; 124 125err_stop_hcd: 126 iounmap(hcd->regs); 127err_release_region: 128 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 129err_put_hcd: 130 usb_put_hcd(hcd); 131 return ret; 132} 133 134static int ohci_rt3883_remove(struct platform_device *pdev) 135{ 136 struct usb_hcd *hcd = platform_get_drvdata(pdev); 137 struct rt3883_ohci_platform_data *pdata; 138 139 usb_remove_hcd(hcd); 140 iounmap(hcd->regs); 141 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 142 usb_put_hcd(hcd); 143 144 pdata = pdev->dev.platform_data; 145 if (pdata && pdata->stop_hw) 146 pdata->stop_hw(); 147 148 return 0; 149} 150 151static struct platform_driver ohci_rt3883_driver = { 152 .probe = ohci_rt3883_probe, 153 .remove = ohci_rt3883_remove, 154 .shutdown = usb_hcd_platform_shutdown, 155 .driver = { 156 .name = "rt3883-ohci", 157 .owner = THIS_MODULE, 158 }, 159}; 160 161MODULE_ALIAS("platform:rt3883-ohci"); 162