aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/ohci-s3c2410.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ohci-s3c2410.c')
-rw-r--r--drivers/usb/host/ohci-s3c2410.c242
1 files changed, 122 insertions, 120 deletions
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index a68af2dd55c..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 <plat/usb-control.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;
@@ -38,33 +51,32 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd)
{
- return hcd->self.controller->platform_data;
+ return dev_get_platdata(hcd->self.controller);
}
static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
{
- struct s3c2410_hcd_info *info = dev->dev.platform_data;
+ struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
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;
info->report_oc = s3c2410_hcd_oc;
- if (info->enable_oc != NULL) {
+ if (info->enable_oc != NULL)
(info->enable_oc)(info, 1);
- }
}
}
static void s3c2410_stop_hc(struct platform_device *dev)
{
- struct s3c2410_hcd_info *info = dev->dev.platform_data;
+ struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
dev_dbg(&dev->dev, "s3c2410_stop_hc:\n");
@@ -72,13 +84,12 @@ static void s3c2410_stop_hc(struct platform_device *dev)
info->report_oc = NULL;
info->hcd = NULL;
- if (info->enable_oc != NULL) {
+ if (info->enable_oc != NULL)
(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
@@ -88,14 +99,14 @@ static void s3c2410_stop_hc(struct platform_device *dev)
*/
static int
-ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf)
+ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
struct s3c2410_hcd_port *port;
int orig;
int portno;
- orig = ohci_hub_status_data (hcd, buf);
+ orig = ohci_hub_status_data(hcd, buf);
if (info == NULL)
return orig;
@@ -145,7 +156,7 @@ static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
* request.
*/
-static int ohci_s3c2410_hub_control (
+static int ohci_s3c2410_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
@@ -199,9 +210,8 @@ static int ohci_s3c2410_hub_control (
dev_dbg(hcd->self.controller,
"ClearPortFeature: OVER_CURRENT\n");
- if (valid_port(wIndex)) {
+ if (valid_port(wIndex))
info->port[wIndex-1].oc_status = 0;
- }
goto out;
@@ -242,8 +252,11 @@ static int ohci_s3c2410_hub_control (
desc->wHubCharacteristics |= cpu_to_le16(0x0001);
if (info->enable_oc) {
- desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
+ desc->wHubCharacteristics &= ~cpu_to_le16(
+ HUB_CHAR_OCPM);
+ desc->wHubCharacteristics |= cpu_to_le16(
+ 0x0008 |
+ 0x0001);
}
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
@@ -257,13 +270,11 @@ static int ohci_s3c2410_hub_control (
dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
if (valid_port(wIndex)) {
- if (info->port[wIndex-1].oc_changed) {
+ if (info->port[wIndex-1].oc_changed)
*data |= cpu_to_le32(RH_PS_OCIC);
- }
- if (info->port[wIndex-1].oc_status) {
+ if (info->port[wIndex-1].oc_status)
*data |= cpu_to_le32(RH_PS_POCI);
- }
}
}
@@ -321,12 +332,10 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
*/
static void
-usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
+usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev)
{
usb_remove_hcd(hcd);
s3c2410_stop_hc(dev);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
}
@@ -339,69 +348,54 @@ usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
* through the hotplug entry's driver_data.
*
*/
-static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
+static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
struct platform_device *dev)
{
struct usb_hcd *hcd = NULL;
+ struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
int retval;
- s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
- s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
+ s3c2410_usb_set_power(info, 1, 1);
+ s3c2410_usb_set_power(info, 2, 1);
hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
if (hcd == NULL)
return -ENOMEM;
hcd->rsrc_start = dev->resource[0].start;
- hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+ hcd->rsrc_len = resource_size(&dev->resource[0]);
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_err(&dev->dev, "request_mem_region failed\n");
- retval = -EBUSY;
+ hcd->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]);
+ if (IS_ERR(hcd->regs)) {
+ retval = PTR_ERR(hcd->regs);
goto err_put;
}
- clk = clk_get(&dev->dev, "usb-host");
+ clk = devm_clk_get(&dev->dev, "usb-host");
if (IS_ERR(clk)) {
dev_err(&dev->dev, "cannot get usb-host clock\n");
- retval = -ENOENT;
- goto err_mem;
+ retval = PTR_ERR(clk);
+ goto err_put;
}
- usb_clk = clk_get(&dev->dev, "usb-bus-host");
+ usb_clk = devm_clk_get(&dev->dev, "usb-bus-host");
if (IS_ERR(usb_clk)) {
dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
- retval = -ENOENT;
- goto err_clk;
+ retval = PTR_ERR(usb_clk);
+ goto err_put;
}
s3c2410_start_hc(dev, hcd);
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- dev_err(&dev->dev, "ioremap failed\n");
- retval = -ENOMEM;
- goto err_ioremap;
- }
-
- ohci_hcd_init(hcd_to_ohci(hcd));
-
- retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
+ 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:
s3c2410_stop_hc(dev);
- iounmap(hcd->regs);
- clk_put(usb_clk);
-
- err_clk:
- clk_put(clk);
-
- err_mem:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_put:
usb_put_hcd(hcd);
@@ -410,92 +404,100 @@ 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;
+static struct hc_driver __read_mostly ohci_s3c2410_hc_driver;
- if ((ret = ohci_init(ohci)) < 0)
- return ret;
+static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
+{
+ return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
+}
- if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
- ohci_stop (hcd);
- return ret;
- }
+static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ usb_hcd_s3c2410_remove(hcd, pdev);
return 0;
}
+#ifdef CONFIG_PM
+static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ bool do_wakeup = device_may_wakeup(dev);
+ int rc = 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,
+ rc = ohci_suspend(hcd, do_wakeup);
+ if (rc)
+ return rc;
- /*
- * scheduling support
- */
- .get_frame_number = ohci_get_frame,
+ s3c2410_stop_hc(pdev);
- /*
- * 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 int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
-{
- return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
+ return rc;
}
-static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
+static int ohci_hcd_s3c2410_drv_resume(struct device *dev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+
+ s3c2410_start_hc(pdev, hcd);
+
+ ohci_resume(hcd, false);
- usb_hcd_s3c2410_remove(hcd, pdev);
return 0;
}
+#else
+#define ohci_hcd_s3c2410_drv_suspend NULL
+#define ohci_hcd_s3c2410_drv_resume NULL
+#endif
+
+static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = {
+ .suspend = ohci_hcd_s3c2410_drv_suspend,
+ .resume = ohci_hcd_s3c2410_drv_resume,
+};
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
- /*.suspend = ohci_hcd_s3c2410_drv_suspend, */
- /*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-ohci",
+ .pm = &ohci_hcd_s3c2410_pm_ops,
},
};
+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");