Skip to content

Commit

Permalink
usb: chipidea: host: add portpower override
Browse files Browse the repository at this point in the history
This patch adds an external portpower override callback, only single
port regulator control is supported now.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Michael Grzeschik authored and Greg Kroah-Hartman committed Nov 3, 2014
1 parent 11a7e59 commit c8679a2
Showing 1 changed file with 46 additions and 21 deletions.
67 changes: 46 additions & 21 deletions drivers/usb/chipidea/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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())
Expand All @@ -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;

Expand All @@ -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);

Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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;
}

0 comments on commit c8679a2

Please sign in to comment.