diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-05-01 17:47:44 +0200 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-05-01 17:47:44 +0200 |
commit | bf61c8840efe60fd8f91446860b63338fb424158 (patch) | |
tree | 7a71832407a4f0d6346db773343f4c3ae2257b19 /drivers/usb/otg | |
parent | Input: wacom - fix "can not retrieve extra class descriptor" for DTH2242 (diff) | |
parent | Input: trackpoint - Optimize trackpoint init to use power-on reset (diff) | |
download | linux-bf61c8840efe60fd8f91446860b63338fb424158.tar.xz linux-bf61c8840efe60fd8f91446860b63338fb424158.zip |
Merge branch 'next' into for-linus
Prepare first set of updates for 3.10 merge window.
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/Kconfig | 6 | ||||
-rw-r--r-- | drivers/usb/otg/ab8500-usb.c | 6 | ||||
-rw-r--r-- | drivers/usb/otg/fsl_otg.c | 6 | ||||
-rw-r--r-- | drivers/usb/otg/gpio_vbus.c | 12 | ||||
-rw-r--r-- | drivers/usb/otg/isp1301_omap.c | 2 | ||||
-rw-r--r-- | drivers/usb/otg/msm_otg.c | 17 | ||||
-rw-r--r-- | drivers/usb/otg/mv_otg.c | 102 | ||||
-rw-r--r-- | drivers/usb/otg/mxs-phy.c | 77 | ||||
-rw-r--r-- | drivers/usb/otg/nop-usb-xceiv.c | 6 | ||||
-rw-r--r-- | drivers/usb/otg/otg.c | 243 | ||||
-rw-r--r-- | drivers/usb/otg/twl4030-usb.c | 51 | ||||
-rw-r--r-- | drivers/usb/otg/twl6030-usb.c | 2 |
12 files changed, 343 insertions, 187 deletions
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index d8c8a42bff3e..37962c99ff1e 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -58,7 +58,7 @@ config USB_ULPI_VIEWPORT config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" - depends on TWL4030_CORE && REGULATOR_TWL4030 + depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS select USB_OTG_UTILS help Enable this to support the USB OTG transceiver on TWL4030 @@ -68,7 +68,7 @@ config TWL4030_USB config TWL6030_USB tristate "TWL6030 USB Transceiver Driver" - depends on TWL4030_CORE && OMAP_USB2 + depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS select USB_OTG_UTILS help Enable this to support the USB OTG transceiver on TWL6030 @@ -110,7 +110,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND + depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND select USB_OTG select USB_OTG_UTILS help diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index ae8ad561f083..2d86f26a0183 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -468,7 +468,7 @@ static int ab8500_usb_v2_res_setup(struct platform_device *pdev, return 0; } -static int __devinit ab8500_usb_probe(struct platform_device *pdev) +static int ab8500_usb_probe(struct platform_device *pdev) { struct ab8500_usb *ab; struct usb_otg *otg; @@ -546,7 +546,7 @@ fail0: return err; } -static int __devexit ab8500_usb_remove(struct platform_device *pdev) +static int ab8500_usb_remove(struct platform_device *pdev) { struct ab8500_usb *ab = platform_get_drvdata(pdev); @@ -571,7 +571,7 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev) static struct platform_driver ab8500_usb_driver = { .probe = ab8500_usb_probe, - .remove = __devexit_p(ab8500_usb_remove), + .remove = ab8500_usb_remove, .driver = { .name = "ab8500-usb", .owner = THIS_MODULE, diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index c19d1d7173a9..d16adb41eb21 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -1110,7 +1110,7 @@ static const struct file_operations otg_fops = { .release = fsl_otg_release, }; -static int __devinit fsl_otg_probe(struct platform_device *pdev) +static int fsl_otg_probe(struct platform_device *pdev) { int ret; @@ -1144,7 +1144,7 @@ static int __devinit fsl_otg_probe(struct platform_device *pdev) return ret; } -static int __devexit fsl_otg_remove(struct platform_device *pdev) +static int fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; @@ -1169,7 +1169,7 @@ static int __devexit fsl_otg_remove(struct platform_device *pdev) struct platform_driver fsl_otg_driver = { .probe = fsl_otg_probe, - .remove = __devexit_p(fsl_otg_remove), + .remove = fsl_otg_remove, .driver = { .name = driver_name, .owner = THIS_MODULE, diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index a67ffe22179a..a7d4ac591982 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c @@ -409,17 +409,7 @@ static struct platform_driver gpio_vbus_driver = { .remove = __exit_p(gpio_vbus_remove), }; -static int __init gpio_vbus_init(void) -{ - return platform_driver_probe(&gpio_vbus_driver, gpio_vbus_probe); -} -module_init(gpio_vbus_init); - -static void __exit gpio_vbus_exit(void) -{ - platform_driver_unregister(&gpio_vbus_driver); -} -module_exit(gpio_vbus_exit); +module_platform_driver_probe(gpio_vbus_driver, gpio_vbus_probe); MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver"); MODULE_AUTHOR("Philipp Zabel"); diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c index ceee2119bffa..af9cb11626b2 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/otg/isp1301_omap.c @@ -1493,7 +1493,7 @@ isp1301_start_hnp(struct usb_otg *otg) /*-------------------------------------------------------------------------*/ -static int __devinit +static int isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { int status; diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c index 9f5fc906041a..749fbf41fb6f 100644 --- a/drivers/usb/otg/msm_otg.c +++ b/drivers/usb/otg/msm_otg.c @@ -1606,7 +1606,7 @@ free_motg: return ret; } -static int __devexit msm_otg_remove(struct platform_device *pdev) +static int msm_otg_remove(struct platform_device *pdev) { struct msm_otg *motg = platform_get_drvdata(pdev); struct usb_phy *phy = &motg->phy; @@ -1746,7 +1746,7 @@ static const struct dev_pm_ops msm_otg_dev_pm_ops = { #endif static struct platform_driver msm_otg_driver = { - .remove = __devexit_p(msm_otg_remove), + .remove = msm_otg_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, @@ -1756,18 +1756,7 @@ static struct platform_driver msm_otg_driver = { }, }; -static int __init msm_otg_init(void) -{ - return platform_driver_probe(&msm_otg_driver, msm_otg_probe); -} - -static void __exit msm_otg_exit(void) -{ - platform_driver_unregister(&msm_otg_driver); -} - -module_init(msm_otg_init); -module_exit(msm_otg_exit); +module_platform_driver_probe(msm_otg_driver, msm_otg_probe); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MSM USB transceiver driver"); diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index 3f124e8f5792..b6a9be31133b 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c @@ -240,7 +240,7 @@ static void otg_clock_enable(struct mv_otg *mvotg) unsigned int i; for (i = 0; i < mvotg->clknum; i++) - clk_enable(mvotg->clk[i]); + clk_prepare_enable(mvotg->clk[i]); } static void otg_clock_disable(struct mv_otg *mvotg) @@ -248,7 +248,7 @@ static void otg_clock_disable(struct mv_otg *mvotg) unsigned int i; for (i = 0; i < mvotg->clknum; i++) - clk_disable(mvotg->clk[i]); + clk_disable_unprepare(mvotg->clk[i]); } static int mv_otg_enable_internal(struct mv_otg *mvotg) @@ -420,7 +420,7 @@ static void mv_otg_work(struct work_struct *work) struct usb_otg *otg; int old_state; - mvotg = container_of((struct delayed_work *)work, struct mv_otg, work); + mvotg = container_of(to_delayed_work(work), struct mv_otg, work); run: /* work queue is single thread, or we need spin_lock to protect */ @@ -662,18 +662,9 @@ static struct attribute_group inputs_attr_group = { int mv_otg_remove(struct platform_device *pdev) { struct mv_otg *mvotg = platform_get_drvdata(pdev); - int clk_i; sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group); - if (mvotg->irq) - free_irq(mvotg->irq, mvotg); - - if (mvotg->pdata->vbus) - free_irq(mvotg->pdata->vbus->irq, mvotg); - if (mvotg->pdata->id) - free_irq(mvotg->pdata->id->irq, mvotg); - if (mvotg->qwork) { flush_workqueue(mvotg->qwork); destroy_workqueue(mvotg->qwork); @@ -681,21 +672,9 @@ int mv_otg_remove(struct platform_device *pdev) mv_otg_disable(mvotg); - if (mvotg->cap_regs) - iounmap(mvotg->cap_regs); - - if (mvotg->phy_regs) - iounmap(mvotg->phy_regs); - - for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++) - clk_put(mvotg->clk[clk_i]); - usb_remove_phy(&mvotg->phy); platform_set_drvdata(pdev, NULL); - kfree(mvotg->phy.otg); - kfree(mvotg); - return 0; } @@ -714,17 +693,15 @@ static int mv_otg_probe(struct platform_device *pdev) } size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum; - mvotg = kzalloc(size, GFP_KERNEL); + mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (!mvotg) { dev_err(&pdev->dev, "failed to allocate memory!\n"); return -ENOMEM; } - otg = kzalloc(sizeof *otg, GFP_KERNEL); - if (!otg) { - kfree(mvotg); + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) return -ENOMEM; - } platform_set_drvdata(pdev, mvotg); @@ -733,18 +710,18 @@ static int mv_otg_probe(struct platform_device *pdev) mvotg->clknum = pdata->clknum; for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) { - mvotg->clk[clk_i] = clk_get(&pdev->dev, pdata->clkname[clk_i]); + mvotg->clk[clk_i] = devm_clk_get(&pdev->dev, + pdata->clkname[clk_i]); if (IS_ERR(mvotg->clk[clk_i])) { retval = PTR_ERR(mvotg->clk[clk_i]); - goto err_put_clk; + return retval; } } mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); if (!mvotg->qwork) { dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); - retval = -ENOMEM; - goto err_put_clk; + return -ENOMEM; } INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); @@ -772,7 +749,7 @@ static int mv_otg_probe(struct platform_device *pdev) goto err_destroy_workqueue; } - mvotg->phy_regs = ioremap(r->start, resource_size(r)); + mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (mvotg->phy_regs == NULL) { dev_err(&pdev->dev, "failed to map phy I/O memory\n"); retval = -EFAULT; @@ -784,21 +761,21 @@ static int mv_otg_probe(struct platform_device *pdev) if (r == NULL) { dev_err(&pdev->dev, "no I/O memory resource defined\n"); retval = -ENODEV; - goto err_unmap_phyreg; + goto err_destroy_workqueue; } - mvotg->cap_regs = ioremap(r->start, resource_size(r)); + mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (mvotg->cap_regs == NULL) { dev_err(&pdev->dev, "failed to map I/O memory\n"); retval = -EFAULT; - goto err_unmap_phyreg; + goto err_destroy_workqueue; } /* we will acces controller register, so enable the udc controller */ retval = mv_otg_enable_internal(mvotg); if (retval) { dev_err(&pdev->dev, "mv otg enable error %d\n", retval); - goto err_unmap_capreg; + goto err_destroy_workqueue; } mvotg->op_regs = @@ -806,9 +783,9 @@ static int mv_otg_probe(struct platform_device *pdev) + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); if (pdata->id) { - retval = request_threaded_irq(pdata->id->irq, NULL, - mv_otg_inputs_irq, - IRQF_ONESHOT, "id", mvotg); + retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq, + NULL, mv_otg_inputs_irq, + IRQF_ONESHOT, "id", mvotg); if (retval) { dev_info(&pdev->dev, "Failed to request irq for ID\n"); @@ -818,9 +795,9 @@ static int mv_otg_probe(struct platform_device *pdev) if (pdata->vbus) { mvotg->clock_gating = 1; - retval = request_threaded_irq(pdata->vbus->irq, NULL, - mv_otg_inputs_irq, - IRQF_ONESHOT, "vbus", mvotg); + retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq, + NULL, mv_otg_inputs_irq, + IRQF_ONESHOT, "vbus", mvotg); if (retval) { dev_info(&pdev->dev, "Failed to request irq for VBUS, " @@ -844,7 +821,7 @@ static int mv_otg_probe(struct platform_device *pdev) } mvotg->irq = r->start; - if (request_irq(mvotg->irq, mv_otg_irq, IRQF_SHARED, + if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED, driver_name, mvotg)) { dev_err(&pdev->dev, "Request irq %d for OTG failed\n", mvotg->irq); @@ -857,14 +834,14 @@ static int mv_otg_probe(struct platform_device *pdev) if (retval < 0) { dev_err(&pdev->dev, "can't register transceiver, %d\n", retval); - goto err_free_irq; + goto err_disable_clk; } retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); if (retval < 0) { dev_dbg(&pdev->dev, "Can't register sysfs attr group: %d\n", retval); - goto err_set_transceiver; + goto err_remove_phy; } spin_lock_init(&mvotg->wq_lock); @@ -879,30 +856,15 @@ static int mv_otg_probe(struct platform_device *pdev) return 0; -err_set_transceiver: +err_remove_phy: usb_remove_phy(&mvotg->phy); -err_free_irq: - free_irq(mvotg->irq, mvotg); err_disable_clk: - if (pdata->vbus) - free_irq(pdata->vbus->irq, mvotg); - if (pdata->id) - free_irq(pdata->id->irq, mvotg); mv_otg_disable_internal(mvotg); -err_unmap_capreg: - iounmap(mvotg->cap_regs); -err_unmap_phyreg: - iounmap(mvotg->phy_regs); err_destroy_workqueue: flush_workqueue(mvotg->qwork); destroy_workqueue(mvotg->qwork); -err_put_clk: - for (clk_i--; clk_i >= 0; clk_i--) - clk_put(mvotg->clk[clk_i]); platform_set_drvdata(pdev, NULL); - kfree(otg); - kfree(mvotg); return retval; } @@ -958,16 +920,4 @@ static struct platform_driver mv_otg_driver = { .resume = mv_otg_resume, #endif }; - -static int __init mv_otg_init(void) -{ - return platform_driver_register(&mv_otg_driver); -} - -static void __exit mv_otg_exit(void) -{ - platform_driver_unregister(&mv_otg_driver); -} - -module_init(mv_otg_init); -module_exit(mv_otg_exit); +module_platform_driver(mv_otg_driver); diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c index 88db976647cf..b0d9f119c749 100644 --- a/drivers/usb/otg/mxs-phy.c +++ b/drivers/usb/otg/mxs-phy.c @@ -20,7 +20,6 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> -#include <linux/workqueue.h> #define DRIVER_NAME "mxs_phy" @@ -35,16 +34,9 @@ #define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14) #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1) -/* - * Amount of delay in miliseconds to safely enable ENHOSTDISCONDETECT bit - * so that connection and reset processing can be completed for the root hub. - */ -#define MXY_PHY_ENHOSTDISCONDETECT_DELAY 250 - struct mxs_phy { struct usb_phy phy; struct clk *clk; - struct delayed_work enhostdiscondetect_work; }; #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) @@ -70,7 +62,6 @@ static int mxs_phy_init(struct usb_phy *phy) clk_prepare_enable(mxs_phy->clk); mxs_phy_hw_init(mxs_phy); - INIT_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, NULL); return 0; } @@ -85,46 +76,47 @@ static void mxs_phy_shutdown(struct usb_phy *phy) clk_disable_unprepare(mxs_phy->clk); } -static void mxs_phy_enhostdiscondetect_delay(struct work_struct *ws) +static int mxs_phy_suspend(struct usb_phy *x, int suspend) { - struct mxs_phy *mxs_phy = container_of(ws, struct mxs_phy, - enhostdiscondetect_work.work); + struct mxs_phy *mxs_phy = to_mxs_phy(x); + + if (suspend) { + writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD); + writel_relaxed(BM_USBPHY_CTRL_CLKGATE, + x->io_priv + HW_USBPHY_CTRL_SET); + clk_disable_unprepare(mxs_phy->clk); + } else { + clk_prepare_enable(mxs_phy->clk); + writel_relaxed(BM_USBPHY_CTRL_CLKGATE, + x->io_priv + HW_USBPHY_CTRL_CLR); + writel_relaxed(0, x->io_priv + HW_USBPHY_PWD); + } - /* Enable HOSTDISCONDETECT after delay. */ - dev_dbg(mxs_phy->phy.dev, "Setting ENHOSTDISCONDETECT\n"); - writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, - mxs_phy->phy.io_priv + HW_USBPHY_CTRL_SET); + return 0; } -static int mxs_phy_on_connect(struct usb_phy *phy, int port) +static int mxs_phy_on_connect(struct usb_phy *phy, + enum usb_device_speed speed) { - struct mxs_phy *mxs_phy = to_mxs_phy(phy); - - dev_dbg(phy->dev, "Connect on port %d\n", port); - - mxs_phy_hw_init(mxs_phy); + dev_dbg(phy->dev, "%s speed device has connected\n", + (speed == USB_SPEED_HIGH) ? "high" : "non-high"); - /* - * Delay enabling ENHOSTDISCONDETECT so that connection and - * reset processing can be completed for the root hub. - */ - dev_dbg(phy->dev, "Delaying setting ENHOSTDISCONDETECT\n"); - PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, - mxs_phy_enhostdiscondetect_delay); - schedule_delayed_work(&mxs_phy->enhostdiscondetect_work, - msecs_to_jiffies(MXY_PHY_ENHOSTDISCONDETECT_DELAY)); + if (speed == USB_SPEED_HIGH) + writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + phy->io_priv + HW_USBPHY_CTRL_SET); return 0; } -static int mxs_phy_on_disconnect(struct usb_phy *phy, int port) +static int mxs_phy_on_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) { - dev_dbg(phy->dev, "Disconnect on port %d\n", port); + dev_dbg(phy->dev, "%s speed device has disconnected\n", + (speed == USB_SPEED_HIGH) ? "high" : "non-high"); - /* No need to delay before clearing ENHOSTDISCONDETECT. */ - dev_dbg(phy->dev, "Clearing ENHOSTDISCONDETECT\n"); - writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, - phy->io_priv + HW_USBPHY_CTRL_CLR); + if (speed == USB_SPEED_HIGH) + writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + phy->io_priv + HW_USBPHY_CTRL_CLR); return 0; } @@ -142,9 +134,9 @@ static int mxs_phy_probe(struct platform_device *pdev) return -ENOENT; } - base = devm_request_and_ioremap(&pdev->dev, res); - if (!base) - return -EBUSY; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { @@ -164,6 +156,7 @@ static int mxs_phy_probe(struct platform_device *pdev) mxs_phy->phy.label = DRIVER_NAME; mxs_phy->phy.init = mxs_phy_init; mxs_phy->phy.shutdown = mxs_phy_shutdown; + mxs_phy->phy.set_suspend = mxs_phy_suspend; mxs_phy->phy.notify_connect = mxs_phy_on_connect; mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; @@ -176,7 +169,7 @@ static int mxs_phy_probe(struct platform_device *pdev) return 0; } -static int __devexit mxs_phy_remove(struct platform_device *pdev) +static int mxs_phy_remove(struct platform_device *pdev) { platform_set_drvdata(pdev, NULL); @@ -191,7 +184,7 @@ MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); static struct platform_driver mxs_phy_driver = { .probe = mxs_phy_probe, - .remove = __devexit_p(mxs_phy_remove), + .remove = mxs_phy_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index e52e35e7adaf..a3ce24b94a73 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c @@ -93,7 +93,7 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) +static int nop_usb_xceiv_probe(struct platform_device *pdev) { struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; struct nop_usb_xceiv *nop; @@ -141,7 +141,7 @@ exit: return err; } -static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev) +static int nop_usb_xceiv_remove(struct platform_device *pdev) { struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); @@ -156,7 +156,7 @@ static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev) static struct platform_driver nop_usb_xceiv_driver = { .probe = nop_usb_xceiv_probe, - .remove = __devexit_p(nop_usb_xceiv_remove), + .remove = nop_usb_xceiv_remove, .driver = { .name = "nop_usb_xceiv", .owner = THIS_MODULE, diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index a30c04115115..2bd03d261a50 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -13,11 +13,14 @@ #include <linux/export.h> #include <linux/err.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/slab.h> +#include <linux/of.h> #include <linux/usb/otg.h> static LIST_HEAD(phy_list); +static LIST_HEAD(phy_bind_list); static DEFINE_SPINLOCK(phy_lock); static struct usb_phy *__usb_find_phy(struct list_head *list, @@ -35,6 +38,38 @@ static struct usb_phy *__usb_find_phy(struct list_head *list, return ERR_PTR(-ENODEV); } +static struct usb_phy *__usb_find_phy_dev(struct device *dev, + struct list_head *list, u8 index) +{ + struct usb_phy_bind *phy_bind = NULL; + + list_for_each_entry(phy_bind, list, list) { + if (!(strcmp(phy_bind->dev_name, dev_name(dev))) && + phy_bind->index == index) { + if (phy_bind->phy) + return phy_bind->phy; + else + return ERR_PTR(-EPROBE_DEFER); + } + } + + return ERR_PTR(-ENODEV); +} + +static struct usb_phy *__of_usb_find_phy(struct device_node *node) +{ + struct usb_phy *phy; + + list_for_each_entry(phy, &phy_list, head) { + if (node != phy->dev->of_node) + continue; + + return phy; + } + + return ERR_PTR(-ENODEV); +} + static void devm_usb_phy_release(struct device *dev, void *res) { struct usb_phy *phy = *(struct usb_phy **)res; @@ -95,7 +130,7 @@ struct usb_phy *usb_get_phy(enum usb_phy_type type) spin_lock_irqsave(&phy_lock, flags); phy = __usb_find_phy(&phy_list, type); - if (IS_ERR(phy)) { + if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { pr_err("unable to find transceiver of type %s\n", usb_phy_type_string(type)); goto err0; @@ -110,6 +145,133 @@ err0: } EXPORT_SYMBOL(usb_get_phy); + /** + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle + * @dev - device that requests this phy + * @phandle - name of the property holding the phy phandle value + * @index - the index of the phy + * + * Returns the phy driver associated with the given phandle value, + * after getting a refcount to it, -ENODEV if there is no such phy or + * -EPROBE_DEFER if there is a phandle to the phy, but the device is + * not yet loaded. While at that, it also associates the device with + * the phy using devres. On driver detach, release function is invoked + * on the devres data, then, devres data is freed. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle, u8 index) +{ + struct usb_phy *phy = ERR_PTR(-ENOMEM), **ptr; + unsigned long flags; + struct device_node *node; + + if (!dev->of_node) { + dev_dbg(dev, "device does not have a device node entry\n"); + return ERR_PTR(-EINVAL); + } + + node = of_parse_phandle(dev->of_node, phandle, index); + if (!node) { + dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, + dev->of_node->full_name); + return ERR_PTR(-ENODEV); + } + + ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) { + dev_dbg(dev, "failed to allocate memory for devres\n"); + goto err0; + } + + spin_lock_irqsave(&phy_lock, flags); + + phy = __of_usb_find_phy(node); + if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { + phy = ERR_PTR(-EPROBE_DEFER); + devres_free(ptr); + goto err1; + } + + *ptr = phy; + devres_add(dev, ptr); + + get_device(phy->dev); + +err1: + spin_unlock_irqrestore(&phy_lock, flags); + +err0: + of_node_put(node); + + return phy; +} +EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); + +/** + * usb_get_phy_dev - find the USB PHY + * @dev - device that requests this phy + * @index - the index of the phy + * + * Returns the phy driver, after getting a refcount to it; or + * -ENODEV if there is no such phy. The caller is responsible for + * calling usb_put_phy() to release that count. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) +{ + struct usb_phy *phy = NULL; + unsigned long flags; + + spin_lock_irqsave(&phy_lock, flags); + + phy = __usb_find_phy_dev(dev, &phy_bind_list, index); + if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { + pr_err("unable to find transceiver\n"); + goto err0; + } + + get_device(phy->dev); + +err0: + spin_unlock_irqrestore(&phy_lock, flags); + + return phy; +} +EXPORT_SYMBOL(usb_get_phy_dev); + +/** + * devm_usb_get_phy_dev - find the USB PHY using device ptr and index + * @dev - device that requests this phy + * @index - the index of the phy + * + * Gets the phy using usb_get_phy_dev(), and associates a device with it using + * devres. On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) +{ + struct usb_phy **ptr, *phy; + + ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + phy = usb_get_phy_dev(dev, index); + if (!IS_ERR(phy)) { + *ptr = phy; + devres_add(dev, ptr); + } else + devres_free(ptr); + + return phy; +} +EXPORT_SYMBOL(devm_usb_get_phy_dev); + /** * devm_usb_put_phy - release the USB PHY * @dev - device that wants to release this phy @@ -139,8 +301,12 @@ EXPORT_SYMBOL(devm_usb_put_phy); */ void usb_put_phy(struct usb_phy *x) { - if (x) + if (x) { + struct module *owner = x->dev->driver->owner; + put_device(x->dev); + module_put(owner); + } } EXPORT_SYMBOL(usb_put_phy); @@ -185,6 +351,36 @@ out: EXPORT_SYMBOL(usb_add_phy); /** + * usb_add_phy_dev - declare the USB PHY + * @x: the USB phy to be used; or NULL + * + * This call is exclusively for use by phy drivers, which + * coordinate the activities of drivers for host and peripheral + * controllers, and in some cases for VBUS current regulation. + */ +int usb_add_phy_dev(struct usb_phy *x) +{ + struct usb_phy_bind *phy_bind; + unsigned long flags; + + if (!x->dev) { + dev_err(x->dev, "no device provided for PHY\n"); + return -EINVAL; + } + + spin_lock_irqsave(&phy_lock, flags); + list_for_each_entry(phy_bind, &phy_bind_list, list) + if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev)))) + phy_bind->phy = x; + + list_add_tail(&x->head, &phy_list); + + spin_unlock_irqrestore(&phy_lock, flags); + return 0; +} +EXPORT_SYMBOL(usb_add_phy_dev); + +/** * usb_remove_phy - remove the OTG PHY * @x: the USB OTG PHY to be removed; * @@ -193,14 +389,55 @@ EXPORT_SYMBOL(usb_add_phy); void usb_remove_phy(struct usb_phy *x) { unsigned long flags; + struct usb_phy_bind *phy_bind; spin_lock_irqsave(&phy_lock, flags); - if (x) + if (x) { + list_for_each_entry(phy_bind, &phy_bind_list, list) + if (phy_bind->phy == x) + phy_bind->phy = NULL; list_del(&x->head); + } spin_unlock_irqrestore(&phy_lock, flags); } EXPORT_SYMBOL(usb_remove_phy); +/** + * usb_bind_phy - bind the phy and the controller that uses the phy + * @dev_name: the device name of the device that will bind to the phy + * @index: index to specify the port number + * @phy_dev_name: the device name of the phy + * + * Fills the phy_bind structure with the dev_name and phy_dev_name. This will + * be used when the phy driver registers the phy and when the controller + * requests this phy. + * + * To be used by platform specific initialization code. + */ +int __init usb_bind_phy(const char *dev_name, u8 index, + const char *phy_dev_name) +{ + struct usb_phy_bind *phy_bind; + unsigned long flags; + + phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL); + if (!phy_bind) { + pr_err("phy_bind(): No memory for phy_bind"); + return -ENOMEM; + } + + phy_bind->dev_name = dev_name; + phy_bind->phy_dev_name = phy_dev_name; + phy_bind->index = index; + + spin_lock_irqsave(&phy_lock, flags); + list_add_tail(&phy_bind->list, &phy_bind_list); + spin_unlock_irqrestore(&phy_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_bind_phy); + const char *otg_state_string(enum usb_otg_state state) { switch (state) { diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index f0d2e7530cfe..a994715a3101 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -123,10 +123,10 @@ #define PHY_CLK_CTRL_STS 0xFF #define PHY_DPLL_CLK (1 << 0) -/* In module TWL4030_MODULE_PM_MASTER */ +/* In module TWL_MODULE_PM_MASTER */ #define STS_HW_CONDITIONS 0x0F -/* In module TWL4030_MODULE_PM_RECEIVER */ +/* In module TWL_MODULE_PM_RECEIVER */ #define VUSB_DEDICATED1 0x7D #define VUSB_DEDICATED2 0x7E #define VUSB1V5_DEV_GRP 0x71 @@ -195,14 +195,14 @@ static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl, } #define twl4030_usb_write_verify(twl, address, data) \ - twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_USB, (data), (address)) + twl4030_i2c_write_u8_verify(twl, TWL_MODULE_USB, (data), (address)) static inline int twl4030_usb_write(struct twl4030_usb *twl, u8 address, u8 data) { int ret = 0; - ret = twl_i2c_write_u8(TWL4030_MODULE_USB, data, address); + ret = twl_i2c_write_u8(TWL_MODULE_USB, data, address); if (ret < 0) dev_dbg(twl->dev, "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); @@ -227,7 +227,7 @@ static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address) static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address) { - return twl4030_readb(twl, TWL4030_MODULE_USB, address); + return twl4030_readb(twl, TWL_MODULE_USB, address); } /*-------------------------------------------------------------------------*/ @@ -264,8 +264,7 @@ static enum omap_musb_vbus_id_status * signal is active, the OTG module is activated, and * its interrupt may be raised (may wake the system). */ - status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, - STS_HW_CONDITIONS); + status = twl4030_readb(twl, TWL_MODULE_PM_MASTER, STS_HW_CONDITIONS); if (status < 0) dev_err(twl->dev, "USB link status err %d\n", status); else if (status & (BIT(7) | BIT(2))) { @@ -372,8 +371,7 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) * SLEEP. We work around this by clearing the bit after usv3v1 * is re-activated. This ensures that VUSB3V1 is really active. */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, - VUSB_DEDICATED2); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); regulator_enable(twl->usb1v5); __twl4030_phy_power(twl, 1); twl4030_usb_write(twl, PHY_CLK_CTRL, @@ -419,50 +417,48 @@ static void twl4030_phy_resume(struct twl4030_usb *twl) static int twl4030_usb_ldo_init(struct twl4030_usb *twl) { /* Enable writing to power configuration registers */ - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, - TWL4030_PM_MASTER_KEY_CFG1, - TWL4030_PM_MASTER_PROTECT_KEY); + twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, + TWL4030_PM_MASTER_PROTECT_KEY); - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, - TWL4030_PM_MASTER_KEY_CFG2, - TWL4030_PM_MASTER_PROTECT_KEY); + twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, + TWL4030_PM_MASTER_PROTECT_KEY); /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/ - /*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/ + /*twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/ /* input to VUSB3V1 LDO is from VBAT, not VBUS */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); /* Initialize 3.1V regulator */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); if (IS_ERR(twl->usb3v1)) return -ENODEV; - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); /* Initialize 1.5V regulator */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); if (IS_ERR(twl->usb1v5)) goto fail1; - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); /* Initialize 1.8V regulator */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); if (IS_ERR(twl->usb1v8)) goto fail2; - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); /* disable access to power configuration registers */ - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, - TWL4030_PM_MASTER_PROTECT_KEY); + twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, + TWL4030_PM_MASTER_PROTECT_KEY); return 0; @@ -579,7 +575,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -static int __devinit twl4030_usb_probe(struct platform_device *pdev) +static int twl4030_usb_probe(struct platform_device *pdev) { struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; @@ -614,6 +610,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) twl->phy.dev = twl->dev; twl->phy.label = "twl4030"; twl->phy.otg = otg; + twl->phy.type = USB_PHY_TYPE_USB2; twl->phy.set_suspend = twl4030_set_suspend; otg->phy = &twl->phy; @@ -628,7 +625,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) dev_err(&pdev->dev, "ldo init failed\n"); return err; } - usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2); + usb_add_phy_dev(&twl->phy); platform_set_drvdata(pdev, twl); if (device_create_file(&pdev->dev, &dev_attr_vbus)) diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index fcadef7864f1..8cd6cf49bdbd 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c @@ -310,7 +310,7 @@ static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled) return 0; } -static int __devinit twl6030_usb_probe(struct platform_device *pdev) +static int twl6030_usb_probe(struct platform_device *pdev) { u32 ret; struct twl6030_usb *twl; |