@@ -399,7 +399,7 @@ static int am35x_musb_exit(struct musb *musb)
data->set_phy_power(0);
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return 0;
}
@@ -427,7 +427,7 @@ static int bfin_musb_exit(struct musb *musb)
gpio_free(musb->config->gpio_vrsel);
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return 0;
}
@@ -451,7 +451,7 @@ static int da8xx_musb_exit(struct musb *musb)
phy_off();
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return 0;
}
@@ -437,7 +437,7 @@ static int davinci_musb_init(struct musb *musb)
fail:
usb_put_phy(musb->xceiv);
unregister:
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return -ENODEV;
}
@@ -485,7 +485,7 @@ static int davinci_musb_exit(struct musb *musb)
phy_off();
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return 0;
}
@@ -413,7 +413,7 @@ static int dsps_musb_init(struct musb *musb)
/* mentor core register starts at offset of 0x400 from musb base */
musb->mregs += wrp->musb_core_offset;
- /* NOP driver needs change if supporting dual instance */
+ /* Register NOP driver */
usb_nop_xceiv_register();
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(musb->xceiv))
@@ -447,7 +447,7 @@ static int dsps_musb_init(struct musb *musb)
return 0;
err0:
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return status;
}
@@ -462,9 +462,9 @@ static int dsps_musb_exit(struct musb *musb)
/* Shutdown the on-chip PHY and its PLL. */
musb_dsps_phy_control(glue, pdev->id, 0);
- /* NOP driver needs change if supporting dual instance */
+ /* Unregister NOP driver */
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return 0;
}
@@ -1117,7 +1117,7 @@ done:
iounmap(sync);
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
}
return ret;
}
@@ -1133,7 +1133,7 @@ static int tusb_musb_exit(struct musb *musb)
iounmap(musb->sync_va);
usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_nop_xceiv_unregister(musb->xceiv);
return 0;
}
@@ -32,30 +32,69 @@
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/slab.h>
+#include <linux/idr.h>
struct nop_usb_xceiv {
struct usb_phy phy;
struct device *dev;
+ struct platform_device *pd;
};
-static struct platform_device *pd;
+static DEFINE_IDA(nop_ida);
-void usb_nop_xceiv_register(void)
+static int nop_get_id(gfp_t gfp_mask)
{
- if (pd)
+ int ret, id;
+
+ ret = ida_pre_get(&nop_ida, gfp_mask);
+ if (!ret) {
+ pr_err("failed to reserve resource for id\n");
+ return -ENOMEM;
+ }
+
+ ret = ida_get_new(&nop_ida, &id);
+ if (ret < 0) {
+ pr_err("failed to allocate a new id\n");
+ return ret;
+ }
+
+ return id;
+}
+
+static void nop_put_id(int id)
+{
+
+ pr_debug("removing id %d\n", id);
+ ida_remove(&nop_ida, id);
+}
+
+void usb_nop_xceiv_register()
+{
+ struct platform_device *pd;
+ int id;
+
+ id = nop_get_id(GFP_KERNEL);
+ if (id < 0) {
+ pr_err("failed to allocate a new id\n");
return;
- pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
+ }
+
+ pd = platform_device_register_simple("nop_usb_xceiv", id, NULL, 0);
if (!pd) {
- printk(KERN_ERR "Unable to register usb nop transceiver\n");
+ pr_err("Unable to register usb nop transceiver\n");
return;
}
}
EXPORT_SYMBOL(usb_nop_xceiv_register);
-void usb_nop_xceiv_unregister(void)
+void usb_nop_xceiv_unregister(struct usb_phy *phy)
{
+ struct nop_usb_xceiv *nop = container_of(phy,
+ struct nop_usb_xceiv, phy);
+ struct platform_device *pd = nop->pd;
+
platform_device_unregister(pd);
- pd = NULL;
+ nop_put_id(pd->id);
}
EXPORT_SYMBOL(usb_nop_xceiv_unregister);
@@ -113,6 +152,7 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
if (pdata)
type = pdata->type;
+ nop->pd = pdev;
nop->dev = &pdev->dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
@@ -10,13 +10,13 @@ struct nop_usb_xceiv_platform_data {
#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
/* sometimes transceivers are accessed only through e.g. ULPI */
extern void usb_nop_xceiv_register(void);
-extern void usb_nop_xceiv_unregister(void);
+extern void usb_nop_xceiv_unregister(struct usb_phy *);
#else
static inline void usb_nop_xceiv_register(void)
{
}
-static inline void usb_nop_xceiv_unregister(void)
+static inline void usb_nop_xceiv_unregister(struct usb_phy *phy)
{
}
#endif