|
@@ -34,6 +34,44 @@
|
|
|
|
|
|
static struct hc_driver __read_mostly ci_ehci_hc_driver;
|
|
|
|
|
|
+struct ehci_ci_priv {
|
|
|
+ struct regulator *reg_vbus;
|
|
|
+};
|
|
|
+
|
|
|
+static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
|
|
|
+{
|
|
|
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
|
|
+ struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
|
|
|
+ struct device *dev = hcd->self.controller;
|
|
|
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
|
|
|
+ int ret = 0;
|
|
|
+ int port = HCS_N_PORTS(ehci->hcs_params);
|
|
|
+
|
|
|
+ if (priv->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
|
|
|
+ if (port > 1) {
|
|
|
+ dev_warn(dev,
|
|
|
+ "Not support multi-port regulator control\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (enable)
|
|
|
+ ret = regulator_enable(priv->reg_vbus);
|
|
|
+ else
|
|
|
+ ret = regulator_disable(priv->reg_vbus);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev,
|
|
|
+ "Failed to %s vbus regulator, ret=%d\n",
|
|
|
+ enable ? "enable" : "disable", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct ehci_driver_overrides ehci_ci_overrides = {
|
|
|
+ .extra_priv_size = sizeof(struct ehci_ci_priv),
|
|
|
+ .port_power = ehci_ci_portpower,
|
|
|
+};
|
|
|
+
|
|
|
static irqreturn_t host_irq(struct ci_hdrc *ci)
|
|
|
{
|
|
|
return usb_hcd_irq(ci->irq, ci->hcd);
|
|
@@ -43,6 +81,7 @@ static int host_start(struct ci_hdrc *ci)
|
|
|
{
|
|
|
struct usb_hcd *hcd;
|
|
|
struct ehci_hcd *ehci;
|
|
|
+ struct ehci_ci_priv *priv;
|
|
|
int ret;
|
|
|
|
|
|
if (usb_disabled())
|
|
@@ -68,23 +107,15 @@ static int host_start(struct ci_hdrc *ci)
|
|
|
ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
|
|
|
ehci->imx28_write_fix = ci->imx28_write_fix;
|
|
|
|
|
|
- /*
|
|
|
- * vbus is always on if host is not in OTG FSM mode,
|
|
|
- * otherwise should be controlled by OTG FSM
|
|
|
- */
|
|
|
- if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
|
|
|
- ret = regulator_enable(ci->platdata->reg_vbus);
|
|
|
- if (ret) {
|
|
|
- dev_err(ci->dev,
|
|
|
- "Failed to enable vbus regulator, ret=%d\n",
|
|
|
- ret);
|
|
|
- goto put_hcd;
|
|
|
- }
|
|
|
- }
|
|
|
+ priv = (struct ehci_ci_priv *)ehci->priv;
|
|
|
+ priv->reg_vbus = NULL;
|
|
|
+
|
|
|
+ if (ci->platdata->reg_vbus)
|
|
|
+ priv->reg_vbus = ci->platdata->reg_vbus;
|
|
|
|
|
|
ret = usb_add_hcd(hcd, 0, 0);
|
|
|
if (ret) {
|
|
|
- goto disable_reg;
|
|
|
+ goto put_hcd;
|
|
|
} else {
|
|
|
struct usb_otg *otg = ci->transceiver->otg;
|
|
|
|
|
@@ -100,10 +131,6 @@ static int host_start(struct ci_hdrc *ci)
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
-disable_reg:
|
|
|
- if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci))
|
|
|
- regulator_disable(ci->platdata->reg_vbus);
|
|
|
-
|
|
|
put_hcd:
|
|
|
usb_put_hcd(hcd);
|
|
|
|
|
@@ -117,8 +144,6 @@ static void host_stop(struct ci_hdrc *ci)
|
|
|
if (hcd) {
|
|
|
usb_remove_hcd(hcd);
|
|
|
usb_put_hcd(hcd);
|
|
|
- if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci))
|
|
|
- regulator_disable(ci->platdata->reg_vbus);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -146,7 +171,7 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
|
|
|
rdrv->name = "host";
|
|
|
ci->roles[CI_ROLE_HOST] = rdrv;
|
|
|
|
|
|
- ehci_init_driver(&ci_ehci_hc_driver, NULL);
|
|
|
+ ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
|
|
|
|
|
|
return 0;
|
|
|
}
|