Commit ef44cb42 authored by Antoine Tenart's avatar Antoine Tenart Committed by Felipe Balbi

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: default avatarAntoine Tenart <antoine.tenart@free-electrons.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 48bcc180
...@@ -161,7 +161,7 @@ struct hw_bank { ...@@ -161,7 +161,7 @@ struct hw_bank {
* @test_mode: the selected test mode * @test_mode: the selected test mode
* @platdata: platform specific information supplied by parent device * @platdata: platform specific information supplied by parent device
* @vbus_active: is VBUS active * @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 * @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs * @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work * @id_event: indicates there is an id event, and handled at ci_otg_work
...@@ -177,6 +177,7 @@ struct ci_hdrc { ...@@ -177,6 +177,7 @@ struct ci_hdrc {
struct ci_role_driver *roles[CI_ROLE_END]; struct ci_role_driver *roles[CI_ROLE_END];
enum ci_role role; enum ci_role role;
bool is_otg; bool is_otg;
struct usb_otg otg;
struct otg_fsm fsm; struct otg_fsm fsm;
struct ci_otg_fsm_timer_list *fsm_timer; struct ci_otg_fsm_timer_list *fsm_timer;
struct work_struct work; struct work_struct work;
...@@ -201,7 +202,7 @@ struct ci_hdrc { ...@@ -201,7 +202,7 @@ struct ci_hdrc {
struct ci_hdrc_platform_data *platdata; struct ci_hdrc_platform_data *platdata;
int vbus_active; int vbus_active;
struct usb_phy *transceiver; struct usb_phy *usb_phy;
struct usb_hcd *hcd; struct usb_hcd *hcd;
struct dentry *debugfs; struct dentry *debugfs;
bool id_event; bool id_event;
......
...@@ -147,7 +147,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ...@@ -147,7 +147,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto err_clk; goto err_clk;
} }
pdata.phy = data->phy; pdata.usb_phy = data->phy;
if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX) if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX)
pdata.flags |= CI_HDRC_IMX28_WRITE_FIX; pdata.flags |= CI_HDRC_IMX28_WRITE_FIX;
......
...@@ -26,15 +26,15 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) ...@@ -26,15 +26,15 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n"); dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST); writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE); writel(0, USB_AHBMODE);
usb_phy_init(ci->transceiver); usb_phy_init(ci->usb_phy);
break; break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT: case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n"); 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. * 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; break;
default: default:
dev_dbg(dev, "unknown ci_hdrc event\n"); dev_dbg(dev, "unknown ci_hdrc event\n");
...@@ -68,7 +68,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev) ...@@ -68,7 +68,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
if (IS_ERR(phy)) if (IS_ERR(phy))
return PTR_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, plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources, pdev->resource, pdev->num_resources,
......
...@@ -312,7 +312,7 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) ...@@ -312,7 +312,7 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
case USBPHY_INTERFACE_MODE_UTMI: case USBPHY_INTERFACE_MODE_UTMI:
case USBPHY_INTERFACE_MODE_UTMIW: case USBPHY_INTERFACE_MODE_UTMIW:
case USBPHY_INTERFACE_MODE_HSIC: case USBPHY_INTERFACE_MODE_HSIC:
ret = usb_phy_init(ci->transceiver); ret = usb_phy_init(ci->usb_phy);
if (ret) if (ret)
return ret; return ret;
hw_phymode_configure(ci); hw_phymode_configure(ci);
...@@ -320,12 +320,12 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) ...@@ -320,12 +320,12 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
case USBPHY_INTERFACE_MODE_ULPI: case USBPHY_INTERFACE_MODE_ULPI:
case USBPHY_INTERFACE_MODE_SERIAL: case USBPHY_INTERFACE_MODE_SERIAL:
hw_phymode_configure(ci); hw_phymode_configure(ci);
ret = usb_phy_init(ci->transceiver); ret = usb_phy_init(ci->usb_phy);
if (ret) if (ret)
return ret; return ret;
break; break;
default: default:
ret = usb_phy_init(ci->transceiver); ret = usb_phy_init(ci->usb_phy);
} }
return ret; return ret;
...@@ -605,13 +605,13 @@ static int ci_hdrc_probe(struct platform_device *pdev) ...@@ -605,13 +605,13 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
if (ci->platdata->phy) if (ci->platdata->usb_phy)
ci->transceiver = ci->platdata->phy; ci->usb_phy = ci->platdata->usb_phy;
else 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)) { if (IS_ERR(ci->usb_phy)) {
ret = PTR_ERR(ci->transceiver); ret = PTR_ERR(ci->usb_phy);
/* /*
* if -ENXIO is returned, it means PHY layer wasn't * if -ENXIO is returned, it means PHY layer wasn't
* enabled, so it makes no sense to return -EPROBE_DEFER * enabled, so it makes no sense to return -EPROBE_DEFER
...@@ -728,7 +728,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) ...@@ -728,7 +728,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
stop: stop:
ci_role_destroy(ci); ci_role_destroy(ci);
deinit_phy: deinit_phy:
usb_phy_shutdown(ci->transceiver); usb_phy_shutdown(ci->usb_phy);
return ret; return ret;
} }
...@@ -741,7 +741,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) ...@@ -741,7 +741,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
free_irq(ci->irq, ci); free_irq(ci->irq, ci);
ci_role_destroy(ci); ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true); ci_hdrc_enter_lpm(ci, true);
usb_phy_shutdown(ci->transceiver); usb_phy_shutdown(ci->usb_phy);
return 0; return 0;
} }
......
...@@ -220,7 +220,7 @@ static int ci_otg_show(struct seq_file *s, void *unused) ...@@ -220,7 +220,7 @@ static int ci_otg_show(struct seq_file *s, void *unused)
/* ------ State ----- */ /* ------ State ----- */
seq_printf(s, "OTG state: %s\n\n", 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 ----- */ /* ------ State Machine Variables ----- */
seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
......
...@@ -59,7 +59,7 @@ static int host_start(struct ci_hdrc *ci) ...@@ -59,7 +59,7 @@ static int host_start(struct ci_hdrc *ci)
hcd->has_tt = 1; hcd->has_tt = 1;
hcd->power_budget = ci->platdata->power_budget; 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; hcd->tpl_support = ci->platdata->tpl_support;
ehci = hcd_to_ehci(hcd); ehci = hcd_to_ehci(hcd);
...@@ -86,10 +86,11 @@ static int host_start(struct ci_hdrc *ci) ...@@ -86,10 +86,11 @@ static int host_start(struct ci_hdrc *ci)
if (ret) { if (ret) {
goto disable_reg; goto disable_reg;
} else { } else {
struct usb_otg *otg = ci->transceiver->otg; struct usb_otg *otg = &ci->otg;
ci->hcd = hcd; ci->hcd = hcd;
if (otg) {
if (ci_otg_is_fsm_mode(ci)) {
otg->host = &hcd->self; otg->host = &hcd->self;
hcd->self.otg_port = 1; hcd->self.otg_port = 1;
} }
......
...@@ -778,20 +778,10 @@ void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) ...@@ -778,20 +778,10 @@ void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci)
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
{ {
int retval = 0; int retval = 0;
struct usb_otg *otg;
otg = devm_kzalloc(ci->dev, ci->otg.usb_phy = ci->usb_phy;
sizeof(struct usb_otg), GFP_KERNEL); ci->otg.gadget = &ci->gadget;
if (!otg) { ci->fsm.otg = &ci->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->fsm.power_up = 1; ci->fsm.power_up = 1;
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
ci->fsm.otg->state = OTG_STATE_UNDEFINED; ci->fsm.otg->state = OTG_STATE_UNDEFINED;
......
...@@ -1519,8 +1519,8 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma) ...@@ -1519,8 +1519,8 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
{ {
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
if (ci->transceiver) if (ci->usb_phy)
return usb_phy_set_power(ci->transceiver, ma); return usb_phy_set_power(ci->usb_phy, ma);
return -ENOTSUPP; return -ENOTSUPP;
} }
......
...@@ -2648,7 +2648,7 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -2648,7 +2648,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
} }
} }
if (IS_ENABLED(CONFIG_GENERIC_PHY)) { if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
struct phy *phy = phy_get(hcd->self.controller, "usb"); struct phy *phy = phy_get(hcd->self.controller, "usb");
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
...@@ -2668,6 +2668,7 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -2668,6 +2668,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
goto err_phy; goto err_phy;
} }
hcd->phy = phy; hcd->phy = phy;
hcd->remove_phy = 1;
} }
} }
...@@ -2814,7 +2815,7 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -2814,7 +2815,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
err_register_bus: err_register_bus:
hcd_buffer_destroy(hcd); hcd_buffer_destroy(hcd);
err_create_buf: 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_power_off(hcd->phy);
phy_exit(hcd->phy); phy_exit(hcd->phy);
phy_put(hcd->phy); phy_put(hcd->phy);
...@@ -2898,7 +2899,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) ...@@ -2898,7 +2899,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_deregister_bus(&hcd->self); usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd); 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_power_off(hcd->phy);
phy_exit(hcd->phy); phy_exit(hcd->phy);
phy_put(hcd->phy); phy_put(hcd->phy);
......
...@@ -13,7 +13,7 @@ struct ci_hdrc_platform_data { ...@@ -13,7 +13,7 @@ struct ci_hdrc_platform_data {
/* offset of the capability registers */ /* offset of the capability registers */
uintptr_t capoffset; uintptr_t capoffset;
unsigned power_budget; unsigned power_budget;
struct usb_phy *phy; struct usb_phy *usb_phy;
enum usb_phy_interface phy_mode; enum usb_phy_interface phy_mode;
unsigned long flags; unsigned long flags;
#define CI_HDRC_REGS_SHARED BIT(0) #define CI_HDRC_REGS_SHARED BIT(0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment