Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 954ccd32 authored by Ajay Agarwal's avatar Ajay Agarwal
Browse files

usb: ehci: Add snapshot of EHCI msm driver



This change adds support for EHCI compliant HSUSB Host
Controller. This driver depends on OTG driver for PHY
initialization, clock management and powering up VBUS.

This snapshot is taken as of msm-3.18 'commit 4a06b0168aeb ("ANDROID:
sdcardfs: Make WARN_RATELIMIT to pr_debug")'.

This change also fixes the coding style and compilation issues.

Change-Id: I5b4b399453a069a8494b2832ebe04a22c0cf8e2a
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent e3fae817
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1267,7 +1267,7 @@ int ehci_hub_control(
			spin_lock_irqsave(&ehci->lock, flags);

			/* Put all enabled ports into suspend */
			while (ports--) {
			while (!ehci->no_testmode_suspend && ports--) {
				u32 __iomem *sreg =
						&ehci->regs->port_status[ports];

+61 −82
Original line number Diff line number Diff line
/* ehci-msm.c - HSUSB Host Controller Driver Implementation
 *
 * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
 * Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
 *
 * Partly derived from ehci-fsl.c and ehci-hcd.c
 * Copyright (c) 2000-2004 by David Brownell
@@ -29,11 +29,13 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>

#include <linux/usb/otg.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/acpi.h>

#include "ehci.h"

@@ -51,25 +53,32 @@ static int ehci_msm_reset(struct usb_hcd *hcd)

	ehci->caps = USB_CAPLENGTH;
	hcd->has_tt = 1;
	ehci->no_testmode_suspend = true;

	retval = ehci_setup(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);
	writel_relaxed(0, USB_AHBBURST);
	/* Use the AHB transactor */
	writel_relaxed(0x08, 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);
	writel_relaxed(0x13, USB_USBMODE);

	if (hcd->usb_phy->flags & ENABLE_SECONDARY_PHY) {
		ehci_dbg(ehci, "using secondary hsphy\n");
		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
							USB_PHY_CTRL2);
	}

	/* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
	writel_relaxed(readl_relaxed(USB_GENCONFIG_2) & ~(1<<19),
					USB_GENCONFIG_2);
	return 0;
}

static u64 msm_ehci_dma_mask = DMA_BIT_MASK(32);
static int ehci_msm_probe(struct platform_device *pdev)
{
	struct usb_hcd *hcd;
@@ -79,12 +88,20 @@ static int ehci_msm_probe(struct platform_device *pdev)

	dev_dbg(&pdev->dev, "ehci_msm proble\n");

	hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
	if (!pdev->dev.dma_mask)
		pdev->dev.dma_mask = &msm_ehci_dma_mask;
	if (!pdev->dev.coherent_dma_mask)
		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);

	hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev,
			     dev_name(&pdev->dev));
	if (!hcd) {
		dev_err(&pdev->dev, "Unable to create HCD\n");
		return  -ENOMEM;
	}

	hcd_to_bus(hcd)->skip_resume = true;

	ret = platform_get_irq(pdev, 0);
	if (ret < 0) {
		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
@@ -93,61 +110,43 @@ static int ehci_msm_probe(struct platform_device *pdev)
	hcd->irq = ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "Unable to get memory resource\n");
		ret = -ENODEV;
	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(hcd->regs)) {
		dev_err(&pdev->dev, "ioremap failed\n");
		ret = PTR_ERR(hcd->regs);
		goto put_hcd;
	}

	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);
	hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
	if (!hcd->regs) {
		dev_err(&pdev->dev, "ioremap failed\n");
		ret = -ENOMEM;
		goto put_hcd;
	}

	/*
	 * 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.
	 * OTG driver takes 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);
	else
		phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);

	if (IS_ERR(phy)) {
		if (PTR_ERR(phy) == -EPROBE_DEFER) {
	if (IS_ERR_OR_NULL(phy)) {
		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);

	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);
	hcd->usb_phy = phy;
	device_init_wakeup(&pdev->dev, 1);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);
	} else {
		ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
		if (ret)
			goto put_hcd;
	}

	msm_bam_set_usb_host_dev(&pdev->dev);

	return 0;

@@ -165,10 +164,8 @@ static int ehci_msm_remove(struct platform_device *pdev)
	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);

	if (hcd->usb_phy && hcd->usb_phy->otg)
	otg_set_host(hcd->usb_phy->otg, NULL);
	else
		usb_remove_hcd(hcd);
	hcd->usb_phy = NULL;

	usb_put_hcd(hcd);

@@ -176,50 +173,33 @@ static int ehci_msm_remove(struct platform_device *pdev)
}

#ifdef CONFIG_PM
static int ehci_msm_pm_suspend(struct device *dev)
static int ehci_msm_runtime_suspend(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	bool do_wakeup = device_may_wakeup(dev);

	dev_dbg(dev, "ehci-msm PM suspend\n");

	/* Only call ehci_suspend if ehci_setup has been done */
	if (ehci->sbrn)
		return ehci_suspend(hcd, do_wakeup);
	dev_dbg(dev, "ehci runtime suspend\n");

	return 0;
}

static int ehci_msm_pm_resume(struct device *dev)
static int ehci_msm_runtime_resume(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	u32 portsc;

	dev_dbg(dev, "ehci-msm PM resume\n");
	dev_dbg(dev, "ehci runtime resume\n");

	/* Only call ehci_resume if ehci_setup has been done */
	if (ehci->sbrn)
		ehci_resume(hcd, false);
	portsc = readl_relaxed(USB_PORTSC);
	portsc &= ~PORT_RWC_BITS;
	portsc |= PORT_RESUME;
	writel_relaxed(portsc, USB_PORTSC);

	return 0;
}

#else
#define ehci_msm_pm_suspend	NULL
#define ehci_msm_pm_resume	NULL
#endif

static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
	.suspend         = ehci_msm_pm_suspend,
	.resume          = ehci_msm_pm_resume,
};

static const struct acpi_device_id msm_ehci_acpi_ids[] = {
	{ "QCOM8040", 0 },
	{ }
	SET_RUNTIME_PM_OPS(ehci_msm_runtime_suspend, ehci_msm_runtime_resume,
			   NULL)
};
MODULE_DEVICE_TABLE(acpi, msm_ehci_acpi_ids);

static const struct of_device_id msm_ehci_dt_match[] = {
	{ .compatible = "qcom,ehci-host", },
@@ -235,7 +215,6 @@ static struct platform_driver ehci_msm_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),
	},
};

+1 −0
Original line number Diff line number Diff line
@@ -229,6 +229,7 @@ struct ehci_hcd { /* one per controller */
	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */
	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
	bool			no_testmode_suspend; /* MSM Chipidea HC */
	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */

	/* required for usb32 quirk */