162194244cf871aec73b5854077f1c527416ccd7bJingoo Han/*
262194244cf871aec73b5854077f1c527416ccd7bJingoo Han * SAMSUNG EXYNOS USB HOST OHCI Controller
362194244cf871aec73b5854077f1c527416ccd7bJingoo Han *
462194244cf871aec73b5854077f1c527416ccd7bJingoo Han * Copyright (C) 2011 Samsung Electronics Co.Ltd
562194244cf871aec73b5854077f1c527416ccd7bJingoo Han * Author: Jingoo Han <jg1.han@samsung.com>
662194244cf871aec73b5854077f1c527416ccd7bJingoo Han *
762194244cf871aec73b5854077f1c527416ccd7bJingoo Han * This program is free software; you can redistribute  it and/or modify it
862194244cf871aec73b5854077f1c527416ccd7bJingoo Han * under  the terms of  the GNU General  Public License as published by the
962194244cf871aec73b5854077f1c527416ccd7bJingoo Han * Free Software Foundation;  either version 2 of the  License, or (at your
1062194244cf871aec73b5854077f1c527416ccd7bJingoo Han * option) any later version.
1162194244cf871aec73b5854077f1c527416ccd7bJingoo Han *
1262194244cf871aec73b5854077f1c527416ccd7bJingoo Han */
1362194244cf871aec73b5854077f1c527416ccd7bJingoo Han
1462194244cf871aec73b5854077f1c527416ccd7bJingoo Han#include <linux/clk.h>
1562194244cf871aec73b5854077f1c527416ccd7bJingoo Han#include <linux/platform_device.h>
1662194244cf871aec73b5854077f1c527416ccd7bJingoo Han#include <mach/ohci.h>
1762194244cf871aec73b5854077f1c527416ccd7bJingoo Han#include <plat/usb-phy.h>
1862194244cf871aec73b5854077f1c527416ccd7bJingoo Han
1962194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstruct exynos_ohci_hcd {
2062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct device *dev;
2162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct usb_hcd *hcd;
2262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct clk *clk;
2362194244cf871aec73b5854077f1c527416ccd7bJingoo Han};
2462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
2562194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic int ohci_exynos_start(struct usb_hcd *hcd)
2662194244cf871aec73b5854077f1c527416ccd7bJingoo Han{
2762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
2862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	int ret;
2962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
3062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci);
3162194244cf871aec73b5854077f1c527416ccd7bJingoo Han
3262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	ret = ohci_init(ohci);
3362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (ret < 0)
3462194244cf871aec73b5854077f1c527416ccd7bJingoo Han		return ret;
3562194244cf871aec73b5854077f1c527416ccd7bJingoo Han
3662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	ret = ohci_run(ohci);
3762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (ret < 0) {
3862194244cf871aec73b5854077f1c527416ccd7bJingoo Han		err("can't start %s", hcd->self.bus_name);
3962194244cf871aec73b5854077f1c527416ccd7bJingoo Han		ohci_stop(hcd);
4062194244cf871aec73b5854077f1c527416ccd7bJingoo Han		return ret;
4162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
4262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
4362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	return 0;
4462194244cf871aec73b5854077f1c527416ccd7bJingoo Han}
4562194244cf871aec73b5854077f1c527416ccd7bJingoo Han
4662194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic const struct hc_driver exynos_ohci_hc_driver = {
4762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.description		= hcd_name,
4862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.product_desc		= "EXYNOS OHCI Host Controller",
4962194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.hcd_priv_size		= sizeof(struct ohci_hcd),
5062194244cf871aec73b5854077f1c527416ccd7bJingoo Han
5162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.irq			= ohci_irq,
5262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.flags			= HCD_MEMORY|HCD_USB11,
5362194244cf871aec73b5854077f1c527416ccd7bJingoo Han
5462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.start			= ohci_exynos_start,
5562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.stop			= ohci_stop,
5662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.shutdown		= ohci_shutdown,
5762194244cf871aec73b5854077f1c527416ccd7bJingoo Han
5862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.get_frame_number	= ohci_get_frame,
5962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
6062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.urb_enqueue		= ohci_urb_enqueue,
6162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.urb_dequeue		= ohci_urb_dequeue,
6262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.endpoint_disable	= ohci_endpoint_disable,
6362194244cf871aec73b5854077f1c527416ccd7bJingoo Han
6462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.hub_status_data	= ohci_hub_status_data,
6562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.hub_control		= ohci_hub_control,
6662194244cf871aec73b5854077f1c527416ccd7bJingoo Han#ifdef	CONFIG_PM
6762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.bus_suspend		= ohci_bus_suspend,
6862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.bus_resume		= ohci_bus_resume,
6962194244cf871aec73b5854077f1c527416ccd7bJingoo Han#endif
7062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.start_port_reset	= ohci_start_port_reset,
7162194244cf871aec73b5854077f1c527416ccd7bJingoo Han};
7262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
7362194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic int __devinit exynos_ohci_probe(struct platform_device *pdev)
7462194244cf871aec73b5854077f1c527416ccd7bJingoo Han{
7562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos4_ohci_platdata *pdata;
7662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos_ohci_hcd *exynos_ohci;
7762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct usb_hcd *hcd;
7862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct ohci_hcd *ohci;
7962194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct resource *res;
8062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	int irq;
8162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	int err;
8262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
8362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	pdata = pdev->dev.platform_data;
8462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (!pdata) {
8562194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "No platform data defined\n");
8662194244cf871aec73b5854077f1c527416ccd7bJingoo Han		return -EINVAL;
8762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
8862194244cf871aec73b5854077f1c527416ccd7bJingoo Han
8962194244cf871aec73b5854077f1c527416ccd7bJingoo Han	exynos_ohci = kzalloc(sizeof(struct exynos_ohci_hcd), GFP_KERNEL);
9062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (!exynos_ohci)
9162194244cf871aec73b5854077f1c527416ccd7bJingoo Han		return -ENOMEM;
9262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
9362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	exynos_ohci->dev = &pdev->dev;
9462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
9562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
9662194244cf871aec73b5854077f1c527416ccd7bJingoo Han					dev_name(&pdev->dev));
9762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (!hcd) {
9862194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "Unable to create HCD\n");
9962194244cf871aec73b5854077f1c527416ccd7bJingoo Han		err = -ENOMEM;
10062194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail_hcd;
10162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
10262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
10362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	exynos_ohci->hcd = hcd;
10462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	exynos_ohci->clk = clk_get(&pdev->dev, "usbhost");
10562194244cf871aec73b5854077f1c527416ccd7bJingoo Han
10662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (IS_ERR(exynos_ohci->clk)) {
10762194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "Failed to get usbhost clock\n");
10862194244cf871aec73b5854077f1c527416ccd7bJingoo Han		err = PTR_ERR(exynos_ohci->clk);
10962194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail_clk;
11062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
11162194244cf871aec73b5854077f1c527416ccd7bJingoo Han
11262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	err = clk_enable(exynos_ohci->clk);
11362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (err)
11462194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail_clken;
11562194244cf871aec73b5854077f1c527416ccd7bJingoo Han
11662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (!res) {
11862194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "Failed to get I/O memory\n");
11962194244cf871aec73b5854077f1c527416ccd7bJingoo Han		err = -ENXIO;
12062194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail_io;
12162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
12262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
12362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	hcd->rsrc_start = res->start;
12462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	hcd->rsrc_len = resource_size(res);
12562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	hcd->regs = ioremap(res->start, resource_size(res));
12662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (!hcd->regs) {
12762194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
12862194244cf871aec73b5854077f1c527416ccd7bJingoo Han		err = -ENOMEM;
12962194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail_io;
13062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
13162194244cf871aec73b5854077f1c527416ccd7bJingoo Han
13262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	irq = platform_get_irq(pdev, 0);
13362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (!irq) {
13462194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "Failed to get IRQ\n");
13562194244cf871aec73b5854077f1c527416ccd7bJingoo Han		err = -ENODEV;
13662194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail;
13762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
13862194244cf871aec73b5854077f1c527416ccd7bJingoo Han
13962194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (pdata->phy_init)
14062194244cf871aec73b5854077f1c527416ccd7bJingoo Han		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
14162194244cf871aec73b5854077f1c527416ccd7bJingoo Han
14262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	ohci = hcd_to_ohci(hcd);
14362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	ohci_hcd_init(ohci);
14462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
14562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
14662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (err) {
14762194244cf871aec73b5854077f1c527416ccd7bJingoo Han		dev_err(&pdev->dev, "Failed to add USB HCD\n");
14862194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail;
14962194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
15062194244cf871aec73b5854077f1c527416ccd7bJingoo Han
15162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	platform_set_drvdata(pdev, exynos_ohci);
15262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
15362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	return 0;
15462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
15562194244cf871aec73b5854077f1c527416ccd7bJingoo Hanfail:
15662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	iounmap(hcd->regs);
15762194244cf871aec73b5854077f1c527416ccd7bJingoo Hanfail_io:
15862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	clk_disable(exynos_ohci->clk);
15962194244cf871aec73b5854077f1c527416ccd7bJingoo Hanfail_clken:
16062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	clk_put(exynos_ohci->clk);
16162194244cf871aec73b5854077f1c527416ccd7bJingoo Hanfail_clk:
16262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	usb_put_hcd(hcd);
16362194244cf871aec73b5854077f1c527416ccd7bJingoo Hanfail_hcd:
16462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	kfree(exynos_ohci);
16562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	return err;
16662194244cf871aec73b5854077f1c527416ccd7bJingoo Han}
16762194244cf871aec73b5854077f1c527416ccd7bJingoo Han
16862194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic int __devexit exynos_ohci_remove(struct platform_device *pdev)
16962194244cf871aec73b5854077f1c527416ccd7bJingoo Han{
17062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
17162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
17262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct usb_hcd *hcd = exynos_ohci->hcd;
17362194244cf871aec73b5854077f1c527416ccd7bJingoo Han
17462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	usb_remove_hcd(hcd);
17562194244cf871aec73b5854077f1c527416ccd7bJingoo Han
17662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (pdata && pdata->phy_exit)
17762194244cf871aec73b5854077f1c527416ccd7bJingoo Han		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
17862194244cf871aec73b5854077f1c527416ccd7bJingoo Han
17962194244cf871aec73b5854077f1c527416ccd7bJingoo Han	iounmap(hcd->regs);
18062194244cf871aec73b5854077f1c527416ccd7bJingoo Han
18162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	clk_disable(exynos_ohci->clk);
18262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	clk_put(exynos_ohci->clk);
18362194244cf871aec73b5854077f1c527416ccd7bJingoo Han
18462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	usb_put_hcd(hcd);
18562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	kfree(exynos_ohci);
18662194244cf871aec73b5854077f1c527416ccd7bJingoo Han
18762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	return 0;
18862194244cf871aec73b5854077f1c527416ccd7bJingoo Han}
18962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
19062194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic void exynos_ohci_shutdown(struct platform_device *pdev)
19162194244cf871aec73b5854077f1c527416ccd7bJingoo Han{
19262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
19362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct usb_hcd *hcd = exynos_ohci->hcd;
19462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
19562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (hcd->driver->shutdown)
19662194244cf871aec73b5854077f1c527416ccd7bJingoo Han		hcd->driver->shutdown(hcd);
19762194244cf871aec73b5854077f1c527416ccd7bJingoo Han}
19862194244cf871aec73b5854077f1c527416ccd7bJingoo Han
19962194244cf871aec73b5854077f1c527416ccd7bJingoo Han#ifdef CONFIG_PM
20062194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic int exynos_ohci_suspend(struct device *dev)
20162194244cf871aec73b5854077f1c527416ccd7bJingoo Han{
20262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
20362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct usb_hcd *hcd = exynos_ohci->hcd;
20462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
20562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct platform_device *pdev = to_platform_device(dev);
20662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
20762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	unsigned long flags;
20862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	int rc = 0;
20962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
21062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	/*
21162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	 * Root hub was already suspended. Disable irq emission and
21262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	 * mark HW unaccessible, bail out if RH has been resumed. Use
21362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	 * the spinlock to properly synchronize with possible pending
21462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	 * RH suspend or resume activity.
21562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	 */
21662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	spin_lock_irqsave(&ohci->lock, flags);
2172b4ffe31a2380de7c893e345659b0730d6dc62d3Jingoo Han	if (ohci->rh_state != OHCI_RH_SUSPENDED &&
2182b4ffe31a2380de7c893e345659b0730d6dc62d3Jingoo Han			ohci->rh_state != OHCI_RH_HALTED) {
21962194244cf871aec73b5854077f1c527416ccd7bJingoo Han		rc = -EINVAL;
22062194244cf871aec73b5854077f1c527416ccd7bJingoo Han		goto fail;
22162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
22262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
22362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
22462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
22562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (pdata && pdata->phy_exit)
22662194244cf871aec73b5854077f1c527416ccd7bJingoo Han		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
22762194244cf871aec73b5854077f1c527416ccd7bJingoo Hanfail:
22862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	spin_unlock_irqrestore(&ohci->lock, flags);
22962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
23062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	return rc;
23162194244cf871aec73b5854077f1c527416ccd7bJingoo Han}
23262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
23362194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic int exynos_ohci_resume(struct device *dev)
23462194244cf871aec73b5854077f1c527416ccd7bJingoo Han{
23562194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
23662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct usb_hcd *hcd = exynos_ohci->hcd;
23762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct platform_device *pdev = to_platform_device(dev);
23862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
23962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
24062194244cf871aec73b5854077f1c527416ccd7bJingoo Han	if (pdata && pdata->phy_init)
24162194244cf871aec73b5854077f1c527416ccd7bJingoo Han		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
24262194244cf871aec73b5854077f1c527416ccd7bJingoo Han
24362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	/* Mark hardware accessible again as we are out of D3 state by now */
24462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
24562194244cf871aec73b5854077f1c527416ccd7bJingoo Han
24662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	ohci_finish_controller_resume(hcd);
24762194244cf871aec73b5854077f1c527416ccd7bJingoo Han
24862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	return 0;
24962194244cf871aec73b5854077f1c527416ccd7bJingoo Han}
25062194244cf871aec73b5854077f1c527416ccd7bJingoo Han#else
25162194244cf871aec73b5854077f1c527416ccd7bJingoo Han#define exynos_ohci_suspend	NULL
25262194244cf871aec73b5854077f1c527416ccd7bJingoo Han#define exynos_ohci_resume	NULL
25362194244cf871aec73b5854077f1c527416ccd7bJingoo Han#endif
25462194244cf871aec73b5854077f1c527416ccd7bJingoo Han
25562194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic const struct dev_pm_ops exynos_ohci_pm_ops = {
25662194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.suspend	= exynos_ohci_suspend,
25762194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.resume		= exynos_ohci_resume,
25862194244cf871aec73b5854077f1c527416ccd7bJingoo Han};
25962194244cf871aec73b5854077f1c527416ccd7bJingoo Han
26062194244cf871aec73b5854077f1c527416ccd7bJingoo Hanstatic struct platform_driver exynos_ohci_driver = {
26162194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.probe		= exynos_ohci_probe,
26262194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.remove		= __devexit_p(exynos_ohci_remove),
26362194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.shutdown	= exynos_ohci_shutdown,
26462194244cf871aec73b5854077f1c527416ccd7bJingoo Han	.driver = {
26562194244cf871aec73b5854077f1c527416ccd7bJingoo Han		.name	= "exynos-ohci",
26662194244cf871aec73b5854077f1c527416ccd7bJingoo Han		.owner	= THIS_MODULE,
26762194244cf871aec73b5854077f1c527416ccd7bJingoo Han		.pm	= &exynos_ohci_pm_ops,
26862194244cf871aec73b5854077f1c527416ccd7bJingoo Han	}
26962194244cf871aec73b5854077f1c527416ccd7bJingoo Han};
27062194244cf871aec73b5854077f1c527416ccd7bJingoo Han
27162194244cf871aec73b5854077f1c527416ccd7bJingoo HanMODULE_ALIAS("platform:exynos-ohci");
27262194244cf871aec73b5854077f1c527416ccd7bJingoo HanMODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
273