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;
if (!isp)
return -ENOMEM;
- isp->phy = usb_get_phy();
+ isp->phy = usb_get_phy(USB_PHY_TYPE_USB2);
if (!isp->phy)
goto fail0;
}
#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;
}
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);
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) {
#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;
#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;
* 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) {
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,
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)) {
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];
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);
* 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;
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");
#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);
}
#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);
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;
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;
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;
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;
/* 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;
* 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;
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;
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;
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;
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);
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;
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;
{
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);
}
/* 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);
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))
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);
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);
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;
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
- usb_add_phy(NULL);
+ usb_remove_phy(phy);
free_irq(motg->irq, motg);
/*
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);
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);
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:
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);
{
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);
#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
*
* 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().
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) {
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))
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))
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
const char *label;
unsigned int flags;
+ enum usb_phy_type type;
enum usb_otg_state state;
enum usb_phy_events last_event;
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);
/* 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 */
/* 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;
}
/* 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 */