usb: otg: support for multiple transceivers by a single controller
authorKishon Vijay Abraham I <kishon@ti.com>
Fri, 22 Jun 2012 11:32:46 +0000 (17:02 +0530)
committerFelipe Balbi <balbi@ti.com>
Mon, 25 Jun 2012 11:05:35 +0000 (14:05 +0300)
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>
35 files changed:
drivers/power/ab8500_charger.c
drivers/power/isp1704_charger.c
drivers/power/pda_power.c
drivers/power/twl4030_charger.c
drivers/usb/chipidea/udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ohci-omap.c
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/ux500.c
drivers/usb/otg/ab8500-usb.c
drivers/usb/otg/fsl_otg.c
drivers/usb/otg/gpio_vbus.c
drivers/usb/otg/isp1301_omap.c
drivers/usb/otg/msm_otg.c
drivers/usb/otg/mv_otg.c
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/otg/otg.c
drivers/usb/otg/twl4030-usb.c
drivers/usb/otg/twl6030-usb.c
include/linux/usb/otg.h

index cf5ffc4d104855f3c55918f0233c0f514f433f94..6bd6f1c419677e5a4abbedf0f90889b88c424caa 100644 (file)
@@ -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;
index 50773ae6f72ed99e73641986dc98c1071c5448e1..090e5f9e72c9e1878b03ef5f3c2216c907584f70 100644 (file)
@@ -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;
 
index e0f206b0775b2a09cf24caed61ae08d5098af940..7602d49e4d81adfa5a024b20858a7ab85be0b836 100644 (file)
@@ -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;
        }
index fcddd115cc084dc16bd98edf77e2845c84b008bd..13f9db2e85384f5a69326b627545082bdb7d429d 100644 (file)
@@ -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);
index 4468f2c2dddd421d6a8c00ac6845055e8d1715c1..a06d28b119f5f04614b848c93291005f27df4c46 100644 (file)
@@ -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) {
index d7038509b95656eb5990b518799094742a6a7649..0808820ba49591ecd5d50d4685ba20f552d9df4b 100644 (file)
@@ -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;
index 5d779955d5a610b03f06871f65514688e3e6024a..75ff41a5c959ae786e9b4af4d8758e8ba1ca5fc9 100644 (file)
@@ -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;
index 74b9bb8099e7246da5fb931706b568aee17d1dbe..cf8bf26f12edb6a2f2b50d834c2dfbd797d61cf1 100644 (file)
@@ -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) {
index a658e446caba4cab334dbdda1af8f6c08f248790..cc0b1e63dcabc32ff891b093d10d1ec1dab5d1f4 100644 (file)
@@ -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,
index b982304a49c168be7ed126ce606d701316ff8d8c..8f744aab9628f9d5ffb8425b4a9270ebce3e140e 100644 (file)
@@ -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)) {
index 9ad33395f564416c85f0585577345cb5d917725b..22326f274466f39215e2cb2155ad377f2d940970 100644 (file)
@@ -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];
index 0e8976a0ed517ee1beabea805850ee95a06e1934..ba290589d8586885dd87c7186eeb35b1b4b88870 100644 (file)
@@ -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);
 
index 7badd5db398ce2c84319e80a1102acedb6be84f9..c7615fb93dbbdefa6637f8ef4f8d011b4d0789ca 100644 (file)
@@ -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;
index 24f838fe25ac1a8a62dfa9e13cd02ffac2dae15d..ef7aa0df40a6978cef0c049dd55600cd9e4be3fd 100644 (file)
@@ -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");
index ee17d19b1b824f23957357e3c5c17ee5dba9cdf8..14df2f5cf6ae2583a02bf6377dbab9e5e2d1760c 100644 (file)
@@ -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);
        }
index c2c1f55889a4a6e18e5605a24f0cef432d9408ed..92a77dfd1930150f46d91763c5fd29e0429e5b75 100644 (file)
@@ -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);
index a75989bbb3d48e8e2a25175d425d6a8290a08282..4a8cbf0e8d51c7083b4348d4b726e50140648fec 100644 (file)
@@ -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;
 
index 522a4a263df80c98a40a6c3e443d2d74215880b1..452940986d6d9791fefdcf5ece6dd2ef2069178e 100644 (file)
@@ -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;
index 61868d604b2812f6212eb883d571b087658247d8..d731c80c4fef2e7002e6f492ae47ddd966d6003f 100644 (file)
@@ -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;
 
index 441f776366f34c30f7cfcd038574ab58c273a0b3..582268de3fa276717497592e6055e521a6b76c17 100644 (file)
@@ -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;
 
index 716c113608f40dd22180f2ac7410d8600ea0a3d2..92603e498e613914985c7cdba18f3447ac6c2ad2 100644 (file)
@@ -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;
 
index e16dbbf7f30536a143de71f6f290f378ebcd32d5..e279cf32772e147e1cf847d03e19656093ca9a3e 100644 (file)
@@ -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;
index a004736186f1764062af1b36160262492ac12540..8ddf3d5f7cdc39324f732470e626646b8029c44d 100644 (file)
@@ -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;
 
index 53006b113b12c64166bb93c1606f8e65d225904b..46cf80a8cacdf148d6131680af8b33756f939863 100644 (file)
@@ -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;
index 672e28c8143769a3c95f6c3b48ca6ad9a74f3d92..ae8ad561f08326144fe51d97bde495ad603611f0 100644 (file)
@@ -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);
index 73561edd81dea431a6ad470793af14045636849a..23c798cb2d7f23e9ce83ace89265b576fe816152 100644 (file)
@@ -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);
index 9b3c264cdb567c1e099272b79168e882fa285195..a67ffe22179a5719674e236cbe322260da1e43e9 100644 (file)
@@ -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))
index b74df3fec56f863990ef8dd44a2d25bd4083d539..75cea4ab0985c024410f914fdf7e5c9f0cbcd63e 100644 (file)
@@ -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);
index dd606c0100356f923e90ecd17290a3b34fab24a9..9f5fc906041a201e3cac694027fe8bd506c9441d 100644 (file)
@@ -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);
 
        /*
index 18e90fe1fbd162f2516ae64337320fbbdc141f99..3f124e8f5792957585494cf91234dad6d6e62888 100644 (file)
@@ -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:
index 33000dae7200d339b7904a4651188ea5d64d1c1d..803f958f413398400346977ae76c417c64302206 100644 (file)
@@ -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);
index 300a995cfdbec36398b7de7eda545ae32aa9c55e..a23065820eadbc918f923fb684c5c1abc870d36c 100644 (file)
 
 #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) {
index 01022c891e2600eb08dc0289abf8d26a3521d2c8..25a09fabbe357080466575d12689385c05e421d2 100644 (file)
@@ -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))
index a8be20878eb9796c8dadf5b106bb68258e5dab34..dbee00aea755e0f121997d2c0bb54cc09464121e 100644 (file)
@@ -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))
index 0e739c8105258d6383ce4c24d504d40bdadaf29a..1def65fb57d0b2d87d31b59069d85ca4e231fcb0 100644 (file)
@@ -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 */