-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
usb: Add support for VIA VT8500 and compatibles in EHCI HCD
VIA and WonderMedia Systems-on-Chip feature a standard EHCI host controller. This adds necessary glue to use the standard driver with these systems. Signed-off-by: Alexey Charkov <alchark@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
- Loading branch information
Alexey Charkov
authored and
Greg Kroah-Hartman
committed
Nov 11, 2010
1 parent
8be8a9d
commit ad78aca
Showing
3 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/* | ||
* drivers/usb/host/ehci-vt8500.c | ||
* | ||
* Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
* | ||
* Based on ehci-au1xxx.c | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
*/ | ||
|
||
#include <linux/platform_device.h> | ||
|
||
static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) | ||
{ | ||
struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
int rc = 0; | ||
|
||
if (!udev->parent) /* udev is root hub itself, impossible */ | ||
rc = -1; | ||
/* we only support lpm device connected to root hub yet */ | ||
if (ehci->has_lpm && !udev->parent->parent) { | ||
rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); | ||
if (!rc) | ||
rc = ehci_lpm_check(ehci, udev->portnum); | ||
} | ||
return rc; | ||
} | ||
|
||
static const struct hc_driver vt8500_ehci_hc_driver = { | ||
.description = hcd_name, | ||
.product_desc = "VT8500 EHCI", | ||
.hcd_priv_size = sizeof(struct ehci_hcd), | ||
|
||
/* | ||
* generic hardware linkage | ||
*/ | ||
.irq = ehci_irq, | ||
.flags = HCD_MEMORY | HCD_USB2, | ||
|
||
/* | ||
* basic lifecycle operations | ||
*/ | ||
.reset = ehci_init, | ||
.start = ehci_run, | ||
.stop = ehci_stop, | ||
.shutdown = ehci_shutdown, | ||
|
||
/* | ||
* managing i/o requests and associated device resources | ||
*/ | ||
.urb_enqueue = ehci_urb_enqueue, | ||
.urb_dequeue = ehci_urb_dequeue, | ||
.endpoint_disable = ehci_endpoint_disable, | ||
.endpoint_reset = ehci_endpoint_reset, | ||
|
||
/* | ||
* scheduling support | ||
*/ | ||
.get_frame_number = ehci_get_frame, | ||
|
||
/* | ||
* root hub support | ||
*/ | ||
.hub_status_data = ehci_hub_status_data, | ||
.hub_control = ehci_hub_control, | ||
.bus_suspend = ehci_bus_suspend, | ||
.bus_resume = ehci_bus_resume, | ||
.relinquish_port = ehci_relinquish_port, | ||
.port_handed_over = ehci_port_handed_over, | ||
|
||
/* | ||
* call back when device connected and addressed | ||
*/ | ||
.update_device = ehci_update_device, | ||
|
||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
}; | ||
|
||
static int vt8500_ehci_drv_probe(struct platform_device *pdev) | ||
{ | ||
struct usb_hcd *hcd; | ||
struct ehci_hcd *ehci; | ||
struct resource *res; | ||
int ret; | ||
|
||
if (usb_disabled()) | ||
return -ENODEV; | ||
|
||
if (pdev->resource[1].flags != IORESOURCE_IRQ) { | ||
pr_debug("resource[1] is not IORESOURCE_IRQ"); | ||
return -ENOMEM; | ||
} | ||
hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500"); | ||
if (!hcd) | ||
return -ENOMEM; | ||
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
hcd->rsrc_start = res->start; | ||
hcd->rsrc_len = resource_size(res); | ||
|
||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | ||
pr_debug("request_mem_region failed"); | ||
ret = -EBUSY; | ||
goto err1; | ||
} | ||
|
||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
if (!hcd->regs) { | ||
pr_debug("ioremap failed"); | ||
ret = -ENOMEM; | ||
goto err2; | ||
} | ||
|
||
ehci = hcd_to_ehci(hcd); | ||
ehci->caps = hcd->regs; | ||
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); | ||
|
||
dbg_hcs_params(ehci, "reset"); | ||
dbg_hcc_params(ehci, "reset"); | ||
|
||
/* cache this readonly data; minimize chip reads */ | ||
ehci->hcs_params = readl(&ehci->caps->hcs_params); | ||
|
||
ehci_port_power(ehci, 1); | ||
|
||
ret = usb_add_hcd(hcd, pdev->resource[1].start, | ||
IRQF_DISABLED | IRQF_SHARED); | ||
if (ret == 0) { | ||
platform_set_drvdata(pdev, hcd); | ||
return ret; | ||
} | ||
|
||
iounmap(hcd->regs); | ||
err2: | ||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
err1: | ||
usb_put_hcd(hcd); | ||
return ret; | ||
} | ||
|
||
static int vt8500_ehci_drv_remove(struct platform_device *pdev) | ||
{ | ||
struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
|
||
usb_remove_hcd(hcd); | ||
iounmap(hcd->regs); | ||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
usb_put_hcd(hcd); | ||
platform_set_drvdata(pdev, NULL); | ||
|
||
return 0; | ||
} | ||
|
||
static struct platform_driver vt8500_ehci_driver = { | ||
.probe = vt8500_ehci_drv_probe, | ||
.remove = vt8500_ehci_drv_remove, | ||
.shutdown = usb_hcd_platform_shutdown, | ||
.driver = { | ||
.name = "vt8500-ehci", | ||
.owner = THIS_MODULE, | ||
} | ||
}; | ||
|
||
MODULE_ALIAS("platform:vt8500-ehci"); |