Some USB controllers have quirks that require additional handling when
enabling a port. One example is the Chipidea USB host found on various
i.MX SoCs, which must be forced to HS mode for HSIC interfaces.

Signed-off-by: Nora Schiffer <[email protected]>
---
 drivers/usb/host/ehci-hcd.c | 15 +++++++++++----
 drivers/usb/host/ehci.h     |  2 ++
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7d5519c65a9..2de2a5578a1 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -139,6 +139,13 @@ static void ehci_set_usbmode(struct ehci_ctrl *ctrl)
        ehci_writel(reg_ptr, tmp);
 }
 
+static void ehci_enable_port_power(struct ehci_ctrl *ctrl, uint32_t 
*status_reg,
+                                  uint32_t reg)
+{
+       if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams)))
+               ehci_writel(status_reg, reg | EHCI_PS_PP);
+}
+
 static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
                               uint32_t *reg)
 {
@@ -874,10 +881,7 @@ static int ehci_submit_root(struct usb_device *dev, 
unsigned long pipe,
                        ehci_writel(status_reg, reg);
                        break;
                case USB_PORT_FEAT_POWER:
-                       if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) {
-                               reg |= EHCI_PS_PP;
-                               ehci_writel(status_reg, reg);
-                       }
+                       ctrl->ops.enable_port_power(ctrl, status_reg, reg);
                        break;
                case USB_PORT_FEAT_RESET:
                        if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
@@ -1005,6 +1009,7 @@ unknown:
 static const struct ehci_ops default_ehci_ops = {
        .set_usb_mode           = ehci_set_usbmode,
        .get_port_speed         = ehci_get_port_speed,
+       .enable_port_power      = ehci_enable_port_power,
        .powerup_fixup          = ehci_powerup_fixup,
        .get_portsc_register    = ehci_get_portsc_register,
 };
@@ -1019,6 +1024,8 @@ static void ehci_setup_ops(struct ehci_ctrl *ctrl, const 
struct ehci_ops *ops)
                        ctrl->ops.set_usb_mode = ehci_set_usbmode;
                if (!ctrl->ops.get_port_speed)
                        ctrl->ops.get_port_speed = ehci_get_port_speed;
+               if (!ctrl->ops.enable_port_power)
+                       ctrl->ops.enable_port_power = ehci_enable_port_power;
                if (!ctrl->ops.powerup_fixup)
                        ctrl->ops.powerup_fixup = ehci_powerup_fixup;
                if (!ctrl->ops.get_portsc_register)
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 5770d35b464..78da0bc0d17 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -238,6 +238,8 @@ struct ehci_ctrl;
 struct ehci_ops {
        void (*set_usb_mode)(struct ehci_ctrl *ctrl);
        int (*get_port_speed)(struct ehci_ctrl *ctrl, uint32_t reg);
+       void (*enable_port_power)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+                                 uint32_t reg);
        void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
                              uint32_t *reg);
        uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port);
-- 
2.55.0

Reply via email to