summaryrefslogtreecommitdiffstats
path: root/drivers/usb/otg
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2013-05-01 17:47:44 +0200
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-05-01 17:47:44 +0200
commitbf61c8840efe60fd8f91446860b63338fb424158 (patch)
tree7a71832407a4f0d6346db773343f4c3ae2257b19 /drivers/usb/otg
parentInput: wacom - fix "can not retrieve extra class descriptor" for DTH2242 (diff)
parentInput: trackpoint - Optimize trackpoint init to use power-on reset (diff)
downloadlinux-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/Kconfig6
-rw-r--r--drivers/usb/otg/ab8500-usb.c6
-rw-r--r--drivers/usb/otg/fsl_otg.c6
-rw-r--r--drivers/usb/otg/gpio_vbus.c12
-rw-r--r--drivers/usb/otg/isp1301_omap.c2
-rw-r--r--drivers/usb/otg/msm_otg.c17
-rw-r--r--drivers/usb/otg/mv_otg.c102
-rw-r--r--drivers/usb/otg/mxs-phy.c77
-rw-r--r--drivers/usb/otg/nop-usb-xceiv.c6
-rw-r--r--drivers/usb/otg/otg.c243
-rw-r--r--drivers/usb/otg/twl4030-usb.c51
-rw-r--r--drivers/usb/otg/twl6030-usb.c2
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;