usb: allow to supply the PHY in the drivers when using HCD
This patch modify the generic code handling PHYs to allow them to be
supplied from the drivers. This adds checks to ensure no PHY was already
there when looking for one in the generic code. This also makes sure we
do not modify its state in the generic HCD functions, it was provided by
the driver.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index ea40626..9015139 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -161,7 +161,7 @@
* @test_mode: the selected test mode
* @platdata: platform specific information supplied by parent device
* @vbus_active: is VBUS active
- * @transceiver: pointer to USB PHY, if any
+ * @usb_phy: pointer to USB PHY, if any
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
@@ -177,6 +177,7 @@
struct ci_role_driver *roles[CI_ROLE_END];
enum ci_role role;
bool is_otg;
+ struct usb_otg otg;
struct otg_fsm fsm;
struct ci_otg_fsm_timer_list *fsm_timer;
struct work_struct work;
@@ -201,7 +202,7 @@
struct ci_hdrc_platform_data *platdata;
int vbus_active;
- struct usb_phy *transceiver;
+ struct usb_phy *usb_phy;
struct usb_hcd *hcd;
struct dentry *debugfs;
bool id_event;
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index a7ab0f1..6f8b1b1 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -147,7 +147,7 @@
goto err_clk;
}
- pdata.phy = data->phy;
+ pdata.usb_phy = data->phy;
if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX)
pdata.flags |= CI_HDRC_IMX28_WRITE_FIX;
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 4935ac3..3edf969 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -26,15 +26,15 @@
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE);
- usb_phy_init(ci->transceiver);
+ usb_phy_init(ci->usb_phy);
break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
/*
- * Put the transceiver in non-driving mode. Otherwise host
+ * Put the phy in non-driving mode. Otherwise host
* may not detect soft-disconnection.
*/
- usb_phy_notify_disconnect(ci->transceiver, USB_SPEED_UNKNOWN);
+ usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
break;
default:
dev_dbg(dev, "unknown ci_hdrc event\n");
@@ -68,7 +68,7 @@
if (IS_ERR(phy))
return PTR_ERR(phy);
- ci_hdrc_msm_platdata.phy = phy;
+ ci_hdrc_msm_platdata.usb_phy = phy;
plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 9bdc6bd..30f8942 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -312,7 +312,7 @@
case USBPHY_INTERFACE_MODE_UTMI:
case USBPHY_INTERFACE_MODE_UTMIW:
case USBPHY_INTERFACE_MODE_HSIC:
- ret = usb_phy_init(ci->transceiver);
+ ret = usb_phy_init(ci->usb_phy);
if (ret)
return ret;
hw_phymode_configure(ci);
@@ -320,12 +320,12 @@
case USBPHY_INTERFACE_MODE_ULPI:
case USBPHY_INTERFACE_MODE_SERIAL:
hw_phymode_configure(ci);
- ret = usb_phy_init(ci->transceiver);
+ ret = usb_phy_init(ci->usb_phy);
if (ret)
return ret;
break;
default:
- ret = usb_phy_init(ci->transceiver);
+ ret = usb_phy_init(ci->usb_phy);
}
return ret;
@@ -605,13 +605,13 @@
return -ENODEV;
}
- if (ci->platdata->phy)
- ci->transceiver = ci->platdata->phy;
+ if (ci->platdata->usb_phy)
+ ci->usb_phy = ci->platdata->usb_phy;
else
- ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+ ci->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (IS_ERR(ci->transceiver)) {
- ret = PTR_ERR(ci->transceiver);
+ if (IS_ERR(ci->usb_phy)) {
+ ret = PTR_ERR(ci->usb_phy);
/*
* if -ENXIO is returned, it means PHY layer wasn't
* enabled, so it makes no sense to return -EPROBE_DEFER
@@ -728,7 +728,7 @@
stop:
ci_role_destroy(ci);
deinit_phy:
- usb_phy_shutdown(ci->transceiver);
+ usb_phy_shutdown(ci->usb_phy);
return ret;
}
@@ -741,7 +741,7 @@
free_irq(ci->irq, ci);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
- usb_phy_shutdown(ci->transceiver);
+ usb_phy_shutdown(ci->usb_phy);
return 0;
}
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index f038804..268e423 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -220,7 +220,7 @@
/* ------ State ----- */
seq_printf(s, "OTG state: %s\n\n",
- usb_otg_state_string(ci->transceiver->otg->state));
+ usb_otg_state_string(ci->otg.state));
/* ------ State Machine Variables ----- */
seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index ebde7b6..789809f 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -59,7 +59,7 @@
hcd->has_tt = 1;
hcd->power_budget = ci->platdata->power_budget;
- hcd->usb_phy = ci->transceiver;
+ hcd->usb_phy = ci->usb_phy;
hcd->tpl_support = ci->platdata->tpl_support;
ehci = hcd_to_ehci(hcd);
@@ -86,10 +86,11 @@
if (ret) {
goto disable_reg;
} else {
- struct usb_otg *otg = ci->transceiver->otg;
+ struct usb_otg *otg = &ci->otg;
ci->hcd = hcd;
- if (otg) {
+
+ if (ci_otg_is_fsm_mode(ci)) {
otg->host = &hcd->self;
hcd->self.otg_port = 1;
}
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index d8490e7..862d7cb 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -778,20 +778,10 @@
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
{
int retval = 0;
- struct usb_otg *otg;
- otg = devm_kzalloc(ci->dev,
- sizeof(struct usb_otg), GFP_KERNEL);
- if (!otg) {
- dev_err(ci->dev,
- "Failed to allocate usb_otg structure for ci hdrc otg!\n");
- return -ENOMEM;
- }
-
- otg->usb_phy = ci->transceiver;
- otg->gadget = &ci->gadget;
- ci->fsm.otg = otg;
- ci->transceiver->otg = ci->fsm.otg;
+ ci->otg.usb_phy = ci->usb_phy;
+ ci->otg.gadget = &ci->gadget;
+ ci->fsm.otg = &ci->otg;
ci->fsm.power_up = 1;
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index f4397b2..a2d80ab 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1519,8 +1519,8 @@
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
- if (ci->transceiver)
- return usb_phy_set_power(ci->transceiver, ma);
+ if (ci->usb_phy)
+ return usb_phy_set_power(ci->usb_phy, ma);
return -ENOTSUPP;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index b84fb14..6a2a2fd 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2648,7 +2648,7 @@
}
}
- if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
+ if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
struct phy *phy = phy_get(hcd->self.controller, "usb");
if (IS_ERR(phy)) {
@@ -2668,6 +2668,7 @@
goto err_phy;
}
hcd->phy = phy;
+ hcd->remove_phy = 1;
}
}
@@ -2814,7 +2815,7 @@
err_register_bus:
hcd_buffer_destroy(hcd);
err_create_buf:
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) {
+ if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
phy_power_off(hcd->phy);
phy_exit(hcd->phy);
phy_put(hcd->phy);
@@ -2898,7 +2899,7 @@
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) {
+ if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
phy_power_off(hcd->phy);
phy_exit(hcd->phy);
phy_put(hcd->phy);
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index e14c09a..4fe161a 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -13,7 +13,7 @@
/* offset of the capability registers */
uintptr_t capoffset;
unsigned power_budget;
- struct usb_phy *phy;
+ struct usb_phy *usb_phy;
enum usb_phy_interface phy_mode;
unsigned long flags;
#define CI_HDRC_REGS_SHARED BIT(0)