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>
This commit is contained in:
		
					parent
					
						
							
								721002ec1d
							
						
					
				
			
			
				commit
				
					
						662dca54ca
					
				
			
		
					 35 changed files with 152 additions and 57 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
	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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue