1 /* ohci-s5pv210.c - Driver for USB HOST on Samsung S5PV210 processor
3 * Bus Glue for SAMSUNG S5PV210 USB HOST OHCI Controller
5 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
6 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
7 * (C) Copyright 2002 Hewlett-Packard Company
8 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
9 * Author: Jingoo Han <jg1.han@samsung.com>
11 * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
12 * Modified for SAMSUNG s5pv210 OHCI by Jingoo Han <jg1.han@samsung.com>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
19 #include <linux/platform_device.h>
21 extern int usb_disabled(void);
23 extern void usb_host_phy_init(void);
24 extern void usb_host_phy_off(void);
26 static void s5pv210_start_ohc(void);
27 static void s5pv210_stop_ohc(void);
28 static int ohci_hcd_s5pv210_drv_probe(struct platform_device *pdev);
29 static int ohci_hcd_s5pv210_drv_remove(struct platform_device *pdev);
32 static int ohci_hcd_s5pv210_drv_suspend(
33 struct platform_device *pdev,
36 struct usb_hcd *hcd = platform_get_drvdata(pdev);
37 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
41 /* Root hub was already suspended. Disable irq emission and
42 * mark HW unaccessible, bail out if RH has been resumed. Use
43 * the spinlock to properly synchronize with possible pending
44 * RH suspend or resume activity.
46 * This is still racy as hcd->state is manipulated outside of
47 * any locks =P But that will be a different fix.
49 spin_lock_irqsave(&ohci->lock, flags);
50 if (hcd->state != HC_STATE_SUSPENDED) {
55 /* make sure snapshot being resumed re-enumerates everything */
56 if (message.event == PM_EVENT_PRETHAW)
59 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
63 spin_unlock_irqrestore(&ohci->lock, flags);
67 static int ohci_hcd_s5pv210_drv_resume(struct platform_device *pdev)
69 struct usb_hcd *hcd = platform_get_drvdata(pdev);
74 /* Mark hardware accessible again as we are out of D3 state by now */
75 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
77 ohci_finish_controller_resume(hcd);
82 #define ohci_hcd_s5pv210_drv_suspend NULL
83 #define ohci_hcd_s5pv210_drv_resume NULL
87 static void s5pv210_start_ohc(void)
92 static void s5pv210_stop_ohc(void)
97 static int __devinit ohci_s5pv210_start(struct usb_hcd *hcd)
99 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
102 ohci_dbg(ohci, "ohci_s5pv210_start, ohci:%p", ohci);
104 ret = ohci_init(ohci);
108 ret = ohci_run(ohci);
110 err("can't start %s", hcd->self.bus_name);
118 static const struct hc_driver ohci_s5pv210_hc_driver = {
119 .description = hcd_name,
120 .product_desc = "s5pv210 OHCI",
121 .hcd_priv_size = sizeof(struct ohci_hcd),
124 .flags = HCD_MEMORY|HCD_USB11,
126 .start = ohci_s5pv210_start,
128 .shutdown = ohci_shutdown,
130 .get_frame_number = ohci_get_frame,
132 .urb_enqueue = ohci_urb_enqueue,
133 .urb_dequeue = ohci_urb_dequeue,
134 .endpoint_disable = ohci_endpoint_disable,
136 .hub_status_data = ohci_hub_status_data,
137 .hub_control = ohci_hub_control,
139 .bus_suspend = ohci_bus_suspend,
140 .bus_resume = ohci_bus_resume,
142 .start_port_reset = ohci_start_port_reset,
145 static int ohci_hcd_s5pv210_drv_probe(struct platform_device *pdev)
147 struct usb_hcd *hcd = NULL;
153 if (pdev->resource[1].flags != IORESOURCE_IRQ) {
154 dev_err(&pdev->dev, "resource[1] is not IORESOURCE_IRQ.\n");
158 hcd = usb_create_hcd(&ohci_s5pv210_hc_driver, &pdev->dev, "s5pv210");
160 dev_err(&pdev->dev, "usb_create_hcd failed!\n");
164 hcd->rsrc_start = pdev->resource[0].start;
165 hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
167 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
168 dev_err(&pdev->dev, "request_mem_region failed!\n");
175 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
177 dev_err(&pdev->dev, "ioremap failed!\n");
182 ohci_hcd_init(hcd_to_ohci(hcd));
184 retval = usb_add_hcd(hcd, pdev->resource[1].start,
185 IRQF_DISABLED | IRQF_SHARED);
188 platform_set_drvdata(pdev, hcd);
195 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
201 static int ohci_hcd_s5pv210_drv_remove(struct platform_device *pdev)
203 struct usb_hcd *hcd = platform_get_drvdata(pdev);
207 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
210 platform_set_drvdata(pdev, NULL);
215 static struct platform_driver ohci_hcd_s5pv210_driver = {
216 .probe = ohci_hcd_s5pv210_drv_probe,
217 .remove = ohci_hcd_s5pv210_drv_remove,
218 .shutdown = usb_hcd_platform_shutdown,
219 .suspend = ohci_hcd_s5pv210_drv_suspend,
220 .resume = ohci_hcd_s5pv210_drv_resume,
223 .owner = THIS_MODULE,
227 MODULE_ALIAS("platform:s5p-ohci");