summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKishon Vijay Abraham I <kishon@ti.com>2012-06-22 17:02:46 +0530
committerFelipe Balbi <balbi@ti.com>2012-06-25 14:05:35 +0300
commit662dca54ca67c92b7aa14b9a2ec54acacf33ce45 (patch)
tree80c77434b1c4d33ce4e7db56f284c9ae65e16a8d
parent721002ec1dd55a52425455826af49cf8853b2d4f (diff)
downloadlinux-662dca54ca67c92b7aa14b9a2ec54acacf33ce45.tar.gz
linux-662dca54ca67c92b7aa14b9a2ec54acacf33ce45.tar.bz2
linux-662dca54ca67c92b7aa14b9a2ec54acacf33ce45.zip
usb: otg: support for multiple transceivers by a single controller
Add a linked list for keeping multiple PHY instances with different types so that we can have separate USB2 and USB3 PHYs on one single board. _get_phy_ has been changed so that the controller gets the transceiver by type. _remove_phy_ has been added to let the phy be removed from the phy list. Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/power/ab8500_charger.c2
-rw-r--r--drivers/power/isp1704_charger.c2
-rw-r--r--drivers/power/pda_power.c2
-rw-r--r--drivers/power/twl4030_charger.c2
-rw-r--r--drivers/usb/chipidea/udc.c2
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c2
-rw-r--r--drivers/usb/gadget/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c2
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c2
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c2
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-msm.c2
-rw-r--r--drivers/usb/host/ehci-mv.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c2
-rw-r--r--drivers/usb/host/ohci-omap.c2
-rw-r--r--drivers/usb/musb/am35x.c2
-rw-r--r--drivers/usb/musb/blackfin.c2
-rw-r--r--drivers/usb/musb/da8xx.c2
-rw-r--r--drivers/usb/musb/davinci.c2
-rw-r--r--drivers/usb/musb/musb_dsps.c2
-rw-r--r--drivers/usb/musb/omap2430.c2
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/musb/ux500.c2
-rw-r--r--drivers/usb/otg/ab8500-usb.c4
-rw-r--r--drivers/usb/otg/fsl_otg.c6
-rw-r--r--drivers/usb/otg/gpio_vbus.c4
-rw-r--r--drivers/usb/otg/isp1301_omap.c4
-rw-r--r--drivers/usb/otg/msm_otg.c4
-rw-r--r--drivers/usb/otg/mv_otg.c6
-rw-r--r--drivers/usb/otg/nop-usb-xceiv.c4
-rw-r--r--drivers/usb/otg/otg.c96
-rw-r--r--drivers/usb/otg/twl4030-usb.c2
-rw-r--r--drivers/usb/otg/twl6030-usb.c2
-rw-r--r--include/linux/usb/otg.h29
35 files changed, 152 insertions, 57 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index cf5ffc4d1048..6bd6f1c41967 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2688,7 +2688,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
goto free_ac;
}
- di->usb_phy = usb_get_phy();
+ di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
if (!di->usb_phy) {
dev_err(di->dev, "failed to get usb transceiver\n");
ret = -EINVAL;
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 50773ae6f72e..090e5f9e72c9 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -415,7 +415,7 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
if (!isp)
return -ENOMEM;
- isp->phy = usb_get_phy();
+ isp->phy = usb_get_phy(USB_PHY_TYPE_USB2);
if (!isp->phy)
goto fail0;
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index e0f206b0775b..7602d49e4d81 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -321,7 +321,7 @@ static int pda_power_probe(struct platform_device *pdev)
}
#ifdef CONFIG_USB_OTG_UTILS
- transceiver = usb_get_phy();
+ transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (transceiver && !pdata->is_usb_online) {
pdata->is_usb_online = otg_is_usb_online;
}
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index fcddd115cc08..13f9db2e8538 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -479,7 +479,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
INIT_WORK(&bci->work, twl4030_bci_usb_work);
- bci->transceiver = usb_get_phy();
+ bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (bci->transceiver != NULL) {
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
usb_register_notifier(bci->transceiver, &bci->usb_nb);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 4468f2c2dddd..a06d28b119f5 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1687,7 +1687,7 @@ static int udc_start(struct ci13xxx *udc)
udc->gadget.ep0 = &udc->ep0in->ep;
- udc->transceiver = usb_get_phy();
+ udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
if (udc->transceiver == NULL) {
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index d7038509b956..0808820ba495 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -2455,7 +2455,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
- udc_controller->transceiver = usb_get_phy();
+ udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (!udc_controller->transceiver) {
ERR("Can't find OTG driver!\n");
ret = -ENODEV;
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 5d779955d5a6..75ff41a5c959 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -2180,7 +2180,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG)
- udc->transceiver = usb_get_phy();
+ udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
#endif
udc->clknum = pdata->clknum;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 74b9bb8099e7..cf8bf26f12ed 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2865,7 +2865,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
* use it. Except for OTG, we don't _need_ to talk to one;
* but not having one probably means no VBUS detection.
*/
- xceiv = usb_get_phy();
+ xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (xceiv)
type = xceiv->label;
else if (config->otg) {
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index a658e446caba..cc0b1e63dcab 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -2159,7 +2159,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
- dev->transceiver = usb_get_phy();
+ dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (gpio_is_valid(dev->mach->gpio_pullup)) {
if ((retval = gpio_request(dev->mach->gpio_pullup,
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index b982304a49c1..8f744aab9628 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -2464,7 +2464,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
udc->dev = &pdev->dev;
udc->mach = pdev->dev.platform_data;
- udc->transceiver = usb_get_phy();
+ udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
gpio = udc->mach->gpio_pullup;
if (gpio_is_valid(gpio)) {
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index 9ad33395f564..22326f274466 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -1282,7 +1282,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
hsudc->dev = dev;
hsudc->pd = pdev->dev.platform_data;
- hsudc->transceiver = usb_get_phy();
+ hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 0e8976a0ed51..ba290589d858 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -142,7 +142,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- ehci->transceiver = usb_get_phy();
+ ehci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
hcd, ehci, ehci->transceiver);
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 7badd5db398c..c7615fb93dbb 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -145,7 +145,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
* powering up VBUS, mapping of registers address space and power
* management.
*/
- phy = usb_get_phy();
+ phy = usb_get_phy(USB_PHY_TYPE_USB2);
if (!phy) {
dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV;
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 24f838fe25ac..ef7aa0df40a6 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -253,7 +253,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
#ifdef CONFIG_USB_OTG_UTILS
- ehci_mv->otg = usb_get_phy();
+ ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
if (!ehci_mv->otg) {
dev_err(&pdev->dev,
"unable to find transceiver\n");
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index ee17d19b1b82..14df2f5cf6ae 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -749,7 +749,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) {
- tegra->transceiver = usb_get_phy();
+ tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (tegra->transceiver)
otg_set_host(tegra->transceiver->otg, &hcd->self);
}
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index c2c1f55889a4..92a77dfd1930 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -211,7 +211,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
#ifdef CONFIG_USB_OTG
if (need_transceiver) {
- ohci->transceiver = usb_get_phy();
+ ohci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (ohci->transceiver) {
int status = otg_set_host(ohci->transceiver->otg,
&ohci_to_hcd(ohci)->self);
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index a75989bbb3d4..4a8cbf0e8d51 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -364,7 +364,7 @@ static int am35x_musb_init(struct musb *musb)
return -ENODEV;
usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv)
return -ENODEV;
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 522a4a263df8..452940986d6d 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -415,7 +415,7 @@ static int bfin_musb_init(struct musb *musb)
gpio_direction_output(musb->config->gpio_vrsel, 0);
usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv) {
gpio_free(musb->config->gpio_vrsel);
return -ENODEV;
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 61868d604b28..d731c80c4fef 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -425,7 +425,7 @@ static int da8xx_musb_init(struct musb *musb)
goto fail;
usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv)
goto fail;
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 441f776366f3..582268de3fa2 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -384,7 +384,7 @@ static int davinci_musb_init(struct musb *musb)
u32 revision;
usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv)
goto unregister;
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 716c113608f4..92603e498e61 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -376,7 +376,7 @@ static int dsps_musb_init(struct musb *musb)
/* NOP driver needs change if supporting dual instance */
usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv)
return -ENODEV;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index e16dbbf7f305..e279cf32772e 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -292,7 +292,7 @@ static int omap2430_musb_init(struct musb *musb)
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv) {
pr_err("HS USB OTG: no transceiver configured\n");
return -ENODEV;
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index a004736186f1..8ddf3d5f7cdc 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1078,7 +1078,7 @@ static int tusb_musb_init(struct musb *musb)
int ret;
usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv)
return -ENODEV;
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index 53006b113b12..46cf80a8cacd 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -37,7 +37,7 @@ struct ux500_glue {
static int ux500_musb_init(struct musb *musb)
{
- musb->xceiv = usb_get_phy();
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (!musb->xceiv) {
pr_err("HS USB OTG: no transceiver configured\n");
return -ENODEV;
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
index 672e28c81437..ae8ad561f083 100644
--- a/drivers/usb/otg/ab8500-usb.c
+++ b/drivers/usb/otg/ab8500-usb.c
@@ -529,7 +529,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev)
if (err < 0)
goto fail0;
- err = usb_add_phy(&ab->phy);
+ err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
if (err) {
dev_err(&pdev->dev, "Can't register transceiver\n");
goto fail1;
@@ -556,7 +556,7 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev)
cancel_work_sync(&ab->phy_dis_work);
- usb_add_phy(NULL);
+ usb_remove_phy(&ab->phy);
ab8500_usb_host_phy_dis(ab);
ab8500_usb_peri_phy_dis(ab);
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index 73561edd81de..23c798cb2d7f 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -806,7 +806,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
fsl_otg_dev = fsl_otg_tc;
/* Store the otg transceiver */
- status = usb_add_phy(&fsl_otg_tc->phy);
+ status = usb_add_phy(&fsl_otg_tc->phy, USB_PHY_TYPE_USB2);
if (status) {
pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
goto err;
@@ -824,7 +824,7 @@ err:
int usb_otg_start(struct platform_device *pdev)
{
struct fsl_otg *p_otg;
- struct usb_phy *otg_trans = usb_get_phy();
+ struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
struct otg_fsm *fsm;
int status;
struct resource *res;
@@ -1134,7 +1134,7 @@ static int __devexit fsl_otg_remove(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- usb_add_phy(NULL);
+ usb_remove_phy(&fsl_otg_dev->phy);
free_irq(fsl_otg_dev->irq, fsl_otg_dev);
iounmap((void *)usb_dr_regs);
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index 9b3c264cdb56..a67ffe22179a 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -320,7 +320,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
}
/* only active when a gadget is registered */
- err = usb_add_phy(&gpio_vbus->phy);
+ err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
@@ -354,7 +354,7 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&gpio_vbus->work);
regulator_put(gpio_vbus->vbus_draw);
- usb_add_phy(NULL);
+ usb_remove_phy(&gpio_vbus->phy);
free_irq(gpio_vbus->irq, pdev);
if (gpio_is_valid(pdata->gpio_pullup))
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index b74df3fec56f..75cea4ab0985 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -1611,7 +1611,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
#endif
- status = usb_add_phy(&isp->phy);
+ status = usb_add_phy(&isp->phy, USB_PHY_TYPE_USB2);
if (status < 0)
dev_err(&i2c->dev, "can't register transceiver, %d\n",
status);
@@ -1650,7 +1650,7 @@ subsys_initcall(isp_init);
static void __exit isp_exit(void)
{
if (the_transceiver)
- usb_add_phy(NULL);
+ usb_remove_phy(&the_transceiver->phy);
i2c_del_driver(&isp1301_driver);
}
module_exit(isp_exit);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index dd606c010035..9f5fc906041a 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1555,7 +1555,7 @@ static int __init msm_otg_probe(struct platform_device *pdev)
phy->otg->set_host = msm_otg_set_host;
phy->otg->set_peripheral = msm_otg_set_peripheral;
- ret = usb_add_phy(&motg->phy);
+ ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
if (ret) {
dev_err(&pdev->dev, "usb_add_phy failed\n");
goto free_irq;
@@ -1624,7 +1624,7 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
- usb_add_phy(NULL);
+ usb_remove_phy(phy);
free_irq(motg->irq, motg);
/*
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
index 18e90fe1fbd1..3f124e8f5792 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/otg/mv_otg.c
@@ -690,7 +690,7 @@ int mv_otg_remove(struct platform_device *pdev)
for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++)
clk_put(mvotg->clk[clk_i]);
- usb_add_phy(NULL);
+ usb_remove_phy(&mvotg->phy);
platform_set_drvdata(pdev, NULL);
kfree(mvotg->phy.otg);
@@ -853,7 +853,7 @@ static int mv_otg_probe(struct platform_device *pdev)
goto err_disable_clk;
}
- retval = usb_add_phy(&mvotg->phy);
+ retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2);
if (retval < 0) {
dev_err(&pdev->dev, "can't register transceiver, %d\n",
retval);
@@ -880,7 +880,7 @@ static int mv_otg_probe(struct platform_device *pdev)
return 0;
err_set_transceiver:
- usb_add_phy(NULL);
+ usb_remove_phy(&mvotg->phy);
err_free_irq:
free_irq(mvotg->irq, mvotg);
err_disable_clk:
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
index 33000dae7200..803f958f4133 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/otg/nop-usb-xceiv.c
@@ -117,7 +117,7 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
nop->phy.otg->set_host = nop_set_host;
nop->phy.otg->set_peripheral = nop_set_peripheral;
- err = usb_add_phy(&nop->phy);
+ err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
@@ -139,7 +139,7 @@ static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev)
{
struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
- usb_add_phy(NULL);
+ usb_remove_phy(&nop->phy);
platform_set_drvdata(pdev, NULL);
kfree(nop->phy.otg);
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 300a995cfdbe..a23065820ead 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -11,14 +11,32 @@
#include <linux/kernel.h>
#include <linux/export.h>
+#include <linux/err.h>
#include <linux/device.h>
#include <linux/usb/otg.h>
-static struct usb_phy *phy;
+static LIST_HEAD(phy_list);
+static DEFINE_SPINLOCK(phy_lock);
+
+static struct usb_phy *__usb_find_phy(struct list_head *list,
+ enum usb_phy_type type)
+{
+ struct usb_phy *phy = NULL;
+
+ list_for_each_entry(phy, list, head) {
+ if (phy->type != type)
+ continue;
+
+ return phy;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
/**
- * usb_get_phy - find the (single) USB PHY
+ * usb_get_phy - find the USB PHY
+ * @type - the type of the phy the controller requires
*
* Returns the phy driver, after getting a refcount to it; or
* null if there is no such phy. The caller is responsible for
@@ -26,16 +44,30 @@ static struct usb_phy *phy;
*
* For use by USB host and peripheral drivers.
*/
-struct usb_phy *usb_get_phy(void)
+struct usb_phy *usb_get_phy(enum usb_phy_type type)
{
- if (phy)
- get_device(phy->dev);
+ struct usb_phy *phy = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&phy_lock, flags);
+
+ phy = __usb_find_phy(&phy_list, type);
+ if (IS_ERR(phy)) {
+ pr_err("unable to find transceiver of type %s\n",
+ usb_phy_type_string(type));
+ return phy;
+ }
+
+ get_device(phy->dev);
+
+ spin_unlock_irqrestore(&phy_lock, flags);
+
return phy;
}
EXPORT_SYMBOL(usb_get_phy);
/**
- * usb_put_phy - release the (single) USB PHY
+ * usb_put_phy - release the USB PHY
* @x: the phy returned by usb_get_phy()
*
* Releases a refcount the caller received from usb_get_phy().
@@ -50,22 +82,62 @@ void usb_put_phy(struct usb_phy *x)
EXPORT_SYMBOL(usb_put_phy);
/**
- * usb_add_phy - declare the (single) USB PHY
+ * usb_add_phy - declare the USB PHY
* @x: the USB phy to be used; or NULL
+ * @type - the type of this PHY
*
* 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(struct usb_phy *x)
+int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
{
- if (phy && x)
- return -EBUSY;
- phy = x;
- return 0;
+ int ret = 0;
+ unsigned long flags;
+ struct usb_phy *phy;
+
+ if (x && x->type != USB_PHY_TYPE_UNDEFINED) {
+ dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&phy_lock, flags);
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->type == type) {
+ ret = -EBUSY;
+ dev_err(x->dev, "transceiver type %s already exists\n",
+ usb_phy_type_string(type));
+ goto out;
+ }
+ }
+
+ x->type = type;
+ list_add_tail(&x->head, &phy_list);
+
+out:
+ spin_unlock_irqrestore(&phy_lock, flags);
+ return ret;
}
EXPORT_SYMBOL(usb_add_phy);
+/**
+ * usb_remove_phy - remove the OTG PHY
+ * @x: the USB OTG PHY to be removed;
+ *
+ * This reverts the effects of usb_add_phy
+ */
+void usb_remove_phy(struct usb_phy *x)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&phy_lock, flags);
+ if (x)
+ list_del(&x->head);
+ spin_unlock_irqrestore(&phy_lock, flags);
+}
+EXPORT_SYMBOL(usb_remove_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 01022c891e26..25a09fabbe35 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -633,7 +633,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
kfree(twl);
return err;
}
- usb_add_phy(&twl->phy);
+ usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
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 a8be20878eb9..dbee00aea755 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -443,7 +443,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
kfree(twl);
return err;
}
- usb_add_phy(&twl->phy);
+ usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
platform_set_drvdata(pdev, twl);
if (device_create_file(&pdev->dev, &dev_attr_vbus))
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 0e739c810525..1def65fb57d0 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -43,6 +43,13 @@ enum usb_phy_events {
USB_EVENT_ENUMERATED, /* gadget driver enumerated */
};
+/* associate a type with PHY */
+enum usb_phy_type {
+ USB_PHY_TYPE_UNDEFINED,
+ USB_PHY_TYPE_USB2,
+ USB_PHY_TYPE_USB3,
+};
+
struct usb_phy;
/* for transceivers connected thru an ULPI interface, the user must
@@ -89,6 +96,7 @@ struct usb_phy {
const char *label;
unsigned int flags;
+ enum usb_phy_type type;
enum usb_otg_state state;
enum usb_phy_events last_event;
@@ -105,6 +113,9 @@ struct usb_phy {
u16 port_status;
u16 port_change;
+ /* to support controllers that have multiple transceivers */
+ struct list_head head;
+
/* initialize/shutdown the OTG controller */
int (*init)(struct usb_phy *x);
void (*shutdown)(struct usb_phy *x);
@@ -121,7 +132,8 @@ struct usb_phy {
/* for board-specific init logic */
-extern int usb_add_phy(struct usb_phy *);
+extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
+extern void usb_remove_phy(struct usb_phy *);
#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
/* sometimes transceivers are accessed only through e.g. ULPI */
@@ -172,11 +184,11 @@ usb_phy_shutdown(struct usb_phy *x)
/* for usb host and peripheral controller drivers */
#ifdef CONFIG_USB_OTG_UTILS
-extern struct usb_phy *usb_get_phy(void);
+extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
extern void usb_put_phy(struct usb_phy *);
extern const char *otg_state_string(enum usb_otg_state state);
#else
-static inline struct usb_phy *usb_get_phy(void)
+static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
{
return NULL;
}
@@ -276,4 +288,15 @@ usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
/* for OTG controller drivers (and maybe other stuff) */
extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
+static inline const char *usb_phy_type_string(enum usb_phy_type type)
+{
+ switch (type) {
+ case USB_PHY_TYPE_USB2:
+ return "USB2 PHY";
+ case USB_PHY_TYPE_USB3:
+ return "USB3 PHY";
+ default:
+ return "UNKNOWN PHY TYPE";
+ }
+}
#endif /* __LINUX_USB_OTG_H */