summaryrefslogtreecommitdiff
path: root/drivers/usb/host/ehci-msm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-msm.c')
-rw-r--r--drivers/usb/host/ehci-msm.c66
1 files changed, 44 insertions, 22 deletions
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index c23e2858c815..3e226ef6ca62 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -33,6 +33,7 @@
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/acpi.h>
#include "ehci.h"
@@ -55,12 +56,16 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
if (retval)
return retval;
+ /* select ULPI phy and clear other status/control bits in PORTSC */
+ writel(PORTSC_PTS_ULPI, USB_PORTSC);
/* bursts of unspecified length. */
writel(0, USB_AHBBURST);
/* Use the AHB transactor, allow posted data writes */
writel(0x8, USB_AHBMODE);
/* Disable streaming mode and select host mode */
writel(0x13, USB_USBMODE);
+ /* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
+ writel(readl(USB_GENCONFIG_2) & ~ULPI_TX_PKT_EN_CLR_FIX, USB_GENCONFIG_2);
return 0;
}
@@ -104,9 +109,9 @@ static int ehci_msm_probe(struct platform_device *pdev)
}
/*
- * OTG driver takes care of PHY initialization, clock management,
- * powering up VBUS, mapping of registers address space and power
- * management.
+ * If there is an OTG driver, let it take care of PHY initialization,
+ * clock management, powering up VBUS, mapping of registers address
+ * space and power management.
*/
if (pdev->dev.of_node)
phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
@@ -114,27 +119,35 @@ static int ehci_msm_probe(struct platform_device *pdev)
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(phy)) {
- dev_err(&pdev->dev, "unable to find transceiver\n");
- ret = -EPROBE_DEFER;
- goto put_hcd;
- }
-
- ret = otg_set_host(phy->otg, &hcd->self);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to register with transceiver\n");
- goto put_hcd;
+ if (PTR_ERR(phy) == -EPROBE_DEFER) {
+ dev_err(&pdev->dev, "unable to find transceiver\n");
+ ret = -EPROBE_DEFER;
+ goto put_hcd;
+ }
+ phy = NULL;
}
hcd->usb_phy = phy;
device_init_wakeup(&pdev->dev, 1);
- /*
- * OTG device parent of HCD takes care of putting
- * hardware into low power mode.
- */
- pm_runtime_no_callbacks(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- /* FIXME: need to call usb_add_hcd() here? */
+ if (phy && phy->otg) {
+ /*
+ * MSM OTG driver takes care of adding the HCD and
+ * placing hardware into low power mode via runtime PM.
+ */
+ ret = otg_set_host(phy->otg, &hcd->self);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register with transceiver\n");
+ goto put_hcd;
+ }
+
+ pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ } else {
+ ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+ if (ret)
+ goto put_hcd;
+ }
return 0;
@@ -152,9 +165,10 @@ static int ehci_msm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- otg_set_host(hcd->usb_phy->otg, NULL);
-
- /* FIXME: need to call usb_remove_hcd() here? */
+ if (hcd->usb_phy && hcd->usb_phy->otg)
+ otg_set_host(hcd->usb_phy->otg, NULL);
+ else
+ usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -191,6 +205,12 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
.resume = ehci_msm_pm_resume,
};
+static const struct acpi_device_id msm_ehci_acpi_ids[] = {
+ { "QCOM8040", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, msm_ehci_acpi_ids);
+
static const struct of_device_id msm_ehci_dt_match[] = {
{ .compatible = "qcom,ehci-host", },
{}
@@ -200,10 +220,12 @@ MODULE_DEVICE_TABLE(of, msm_ehci_dt_match);
static struct platform_driver ehci_msm_driver = {
.probe = ehci_msm_probe,
.remove = ehci_msm_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "msm_hsusb_host",
.pm = &ehci_msm_dev_pm_ops,
.of_match_table = msm_ehci_dt_match,
+ .acpi_match_table = ACPI_PTR(msm_ehci_acpi_ids),
},
};