diff options
Diffstat (limited to 'drivers/usb/host/ohci-s3c2410.c')
| -rw-r--r-- | drivers/usb/host/ohci-s3c2410.c | 147 | 
1 files changed, 57 insertions, 90 deletions
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 4919afa4125..3d753a9d314 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -19,14 +19,27 @@   * This file is licenced under the GPL.  */ -#include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h>  #include <linux/platform_data/usb-ohci-s3c2410.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" +  #define valid_port(idx) ((idx) == 1 || (idx) == 2)  /* clock device associated with the hcd */ + +#define DRIVER_DESC "OHCI S3C2410 driver" + +static const char hcd_name[] = "ohci-s3c2410"; +  static struct clk *clk;  static struct clk *usb_clk; @@ -47,10 +60,10 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)  	dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); -	clk_enable(usb_clk); +	clk_prepare_enable(usb_clk);  	mdelay(2);			/* let the bus clock stabilise */ -	clk_enable(clk); +	clk_prepare_enable(clk);  	if (info != NULL) {  		info->hcd	= hcd; @@ -75,8 +88,8 @@ static void s3c2410_stop_hc(struct platform_device *dev)  			(info->enable_oc)(info, 0);  	} -	clk_disable(clk); -	clk_disable(usb_clk); +	clk_disable_unprepare(clk); +	clk_disable_unprepare(usb_clk);  }  /* ohci_s3c2410_hub_status_data @@ -93,7 +106,7 @@ ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf)  	int orig;  	int portno; -	orig  = ohci_hub_status_data(hcd, buf); +	orig = ohci_hub_status_data(hcd, buf);  	if (info == NULL)  		return orig; @@ -374,12 +387,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,  	s3c2410_start_hc(dev, hcd); -	ohci_hcd_init(hcd_to_ohci(hcd)); -  	retval = usb_add_hcd(hcd, dev->resource[1].start, 0);  	if (retval != 0)  		goto err_ioremap; +	device_wakeup_enable(hcd->self.controller);  	return 0;   err_ioremap: @@ -392,71 +404,7 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,  /*-------------------------------------------------------------------------*/ -static int -ohci_s3c2410_start(struct usb_hcd *hcd) -{ -	struct ohci_hcd	*ohci = hcd_to_ohci(hcd); -	int ret; - -	ret = ohci_init(ohci); -	if (ret < 0) -		return ret; - -	ret = ohci_run(ohci); -	if (ret < 0) { -		dev_err(hcd->self.controller, "can't start %s\n", -			hcd->self.bus_name); -		ohci_stop(hcd); -		return ret; -	} - -	return 0; -} - - -static const struct hc_driver ohci_s3c2410_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"S3C24XX OHCI", -	.hcd_priv_size =	sizeof(struct ohci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.start =		ohci_s3c2410_start, -	.stop =			ohci_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_s3c2410_hub_status_data, -	.hub_control =		ohci_s3c2410_hub_control, -#ifdef	CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; - -/* device driver */ +static struct hc_driver __read_mostly ohci_s3c2410_hc_driver;  static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)  { @@ -475,28 +423,15 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)  static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct ohci_hcd *ohci = hcd_to_ohci(hcd);  	struct platform_device *pdev = to_platform_device(dev); -	unsigned long flags; +	bool do_wakeup = device_may_wakeup(dev);  	int rc = 0; -	/* -	 * Root hub was already suspended. Disable irq emission and -	 * mark HW unaccessible, bail out if RH has been resumed. Use -	 * the spinlock to properly synchronize with possible pending -	 * RH suspend or resume activity. -	 */ -	spin_lock_irqsave(&ohci->lock, flags); -	if (ohci->rh_state != OHCI_RH_SUSPENDED) { -		rc = -EINVAL; -		goto bail; -	} - -	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +	rc = ohci_suspend(hcd, do_wakeup); +	if (rc) +		return rc;  	s3c2410_stop_hc(pdev); -bail: -	spin_unlock_irqrestore(&ohci->lock, flags);  	return rc;  } @@ -533,4 +468,36 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {  	},  }; +static int __init ohci_s3c2410_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); +	ohci_init_driver(&ohci_s3c2410_hc_driver, NULL); + +	/* +	 * The Samsung HW has some unusual quirks, which require +	 * Sumsung-specific workarounds. We override certain hc_driver +	 * functions here to achieve that. We explicitly do not enhance +	 * ohci_driver_overrides to allow this more easily, since this +	 * is an unusual case, and we don't want to encourage others to +	 * override these functions by making it too easy. +	 */ + +	ohci_s3c2410_hc_driver.hub_status_data	= ohci_s3c2410_hub_status_data; +	ohci_s3c2410_hc_driver.hub_control	= ohci_s3c2410_hub_control; + +	return platform_driver_register(&ohci_hcd_s3c2410_driver); +} +module_init(ohci_s3c2410_init); + +static void __exit ohci_s3c2410_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_s3c2410_driver); +} +module_exit(ohci_s3c2410_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:s3c2410-ohci");  | 
