162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2005-2009 MontaVista Software, Inc.
462306a36Sopenharmony_ci * Copyright 2008,2012,2015      Freescale Semiconductor, Inc.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
762306a36Sopenharmony_ci * by Hunter Wu.
862306a36Sopenharmony_ci * Power Management support by Dave Liu <daveliu@freescale.com>,
962306a36Sopenharmony_ci * Jerry Huang <Chang-Ming.Huang@freescale.com> and
1062306a36Sopenharmony_ci * Anton Vorontsov <avorontsov@ru.mvista.com>.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/pm.h>
1862306a36Sopenharmony_ci#include <linux/err.h>
1962306a36Sopenharmony_ci#include <linux/usb.h>
2062306a36Sopenharmony_ci#include <linux/usb/ehci_def.h>
2162306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2262306a36Sopenharmony_ci#include <linux/usb/otg.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci#include <linux/fsl_devices.h>
2562306a36Sopenharmony_ci#include <linux/of.h>
2662306a36Sopenharmony_ci#include <linux/io.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "ehci.h"
2962306a36Sopenharmony_ci#include "ehci-fsl.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define DRIVER_DESC "Freescale EHCI Host controller driver"
3262306a36Sopenharmony_ci#define DRV_NAME "fsl-ehci"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic struct hc_driver __read_mostly fsl_ehci_hc_driver;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* configure so an HC device and id are always provided */
3762306a36Sopenharmony_ci/* always called with process context; sleeping is OK */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * fsl_ehci_drv_probe - initialize FSL-based HCDs
4162306a36Sopenharmony_ci * @pdev: USB Host Controller being probed
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Context: task context, might sleep
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * Allocates basic resources for this USB host controller.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic int fsl_ehci_drv_probe(struct platform_device *pdev)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata;
5062306a36Sopenharmony_ci	struct usb_hcd *hcd;
5162306a36Sopenharmony_ci	struct resource *res;
5262306a36Sopenharmony_ci	int irq;
5362306a36Sopenharmony_ci	int retval;
5462306a36Sopenharmony_ci	u32 tmp;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	pr_debug("initializing FSL-SOC USB Controller\n");
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* Need platform data for setup */
5962306a36Sopenharmony_ci	pdata = dev_get_platdata(&pdev->dev);
6062306a36Sopenharmony_ci	if (!pdata) {
6162306a36Sopenharmony_ci		dev_err(&pdev->dev,
6262306a36Sopenharmony_ci			"No platform data for %s.\n", dev_name(&pdev->dev));
6362306a36Sopenharmony_ci		return -ENODEV;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/*
6762306a36Sopenharmony_ci	 * This is a host mode driver, verify that we're supposed to be
6862306a36Sopenharmony_ci	 * in host mode.
6962306a36Sopenharmony_ci	 */
7062306a36Sopenharmony_ci	if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
7162306a36Sopenharmony_ci	      (pdata->operating_mode == FSL_USB2_MPH_HOST) ||
7262306a36Sopenharmony_ci	      (pdata->operating_mode == FSL_USB2_DR_OTG))) {
7362306a36Sopenharmony_ci		dev_err(&pdev->dev,
7462306a36Sopenharmony_ci			"Non Host Mode configured for %s. Wrong driver linked.\n",
7562306a36Sopenharmony_ci			dev_name(&pdev->dev));
7662306a36Sopenharmony_ci		return -ENODEV;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
8062306a36Sopenharmony_ci	if (irq < 0)
8162306a36Sopenharmony_ci		return irq;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	hcd = __usb_create_hcd(&fsl_ehci_hc_driver, pdev->dev.parent,
8462306a36Sopenharmony_ci			       &pdev->dev, dev_name(&pdev->dev), NULL);
8562306a36Sopenharmony_ci	if (!hcd) {
8662306a36Sopenharmony_ci		retval = -ENOMEM;
8762306a36Sopenharmony_ci		goto err1;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
9162306a36Sopenharmony_ci	if (IS_ERR(hcd->regs)) {
9262306a36Sopenharmony_ci		retval = PTR_ERR(hcd->regs);
9362306a36Sopenharmony_ci		goto err2;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	hcd->rsrc_start = res->start;
9762306a36Sopenharmony_ci	hcd->rsrc_len = resource_size(res);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	pdata->regs = hcd->regs;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (pdata->power_budget)
10262306a36Sopenharmony_ci		hcd->power_budget = pdata->power_budget;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/*
10562306a36Sopenharmony_ci	 * do platform specific init: check the clock, grab/config pins, etc.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci	if (pdata->init && pdata->init(pdev)) {
10862306a36Sopenharmony_ci		retval = -ENODEV;
10962306a36Sopenharmony_ci		goto err2;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* Enable USB controller, 83xx or 8536 */
11362306a36Sopenharmony_ci	if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) {
11462306a36Sopenharmony_ci		tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL);
11562306a36Sopenharmony_ci		tmp &= ~CONTROL_REGISTER_W1C_MASK;
11662306a36Sopenharmony_ci		tmp |= 0x4;
11762306a36Sopenharmony_ci		iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL);
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Set USB_EN bit to select ULPI phy for USB controller version 2.5 */
12162306a36Sopenharmony_ci	if (pdata->controller_ver == FSL_USB_VER_2_5 &&
12262306a36Sopenharmony_ci	    pdata->phy_mode == FSL_USB2_PHY_ULPI)
12362306a36Sopenharmony_ci		iowrite32be(USB_CTRL_USB_EN, hcd->regs + FSL_SOC_USB_CTRL);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/*
12662306a36Sopenharmony_ci	 * Enable UTMI phy and program PTS field in UTMI mode before asserting
12762306a36Sopenharmony_ci	 * controller reset for USB Controller version 2.5
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	if (pdata->has_fsl_erratum_a007792) {
13062306a36Sopenharmony_ci		tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL);
13162306a36Sopenharmony_ci		tmp &= ~CONTROL_REGISTER_W1C_MASK;
13262306a36Sopenharmony_ci		tmp |= CTRL_UTMI_PHY_EN;
13362306a36Sopenharmony_ci		iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1);
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* Don't need to set host mode here. It will be done by tdi_reset() */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
14162306a36Sopenharmony_ci	if (retval != 0)
14262306a36Sopenharmony_ci		goto err2;
14362306a36Sopenharmony_ci	device_wakeup_enable(hcd->self.controller);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#ifdef CONFIG_USB_OTG
14662306a36Sopenharmony_ci	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
14762306a36Sopenharmony_ci		struct ehci_hcd *ehci = hcd_to_ehci(hcd);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
15062306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, phy=0x%p\n",
15162306a36Sopenharmony_ci			hcd, ehci, hcd->usb_phy);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		if (!IS_ERR_OR_NULL(hcd->usb_phy)) {
15462306a36Sopenharmony_ci			retval = otg_set_host(hcd->usb_phy->otg,
15562306a36Sopenharmony_ci					      &ehci_to_hcd(ehci)->self);
15662306a36Sopenharmony_ci			if (retval) {
15762306a36Sopenharmony_ci				usb_put_phy(hcd->usb_phy);
15862306a36Sopenharmony_ci				goto err2;
15962306a36Sopenharmony_ci			}
16062306a36Sopenharmony_ci		} else {
16162306a36Sopenharmony_ci			dev_err(&pdev->dev, "can't find phy\n");
16262306a36Sopenharmony_ci			retval = -ENODEV;
16362306a36Sopenharmony_ci			goto err2;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		hcd->skip_phy_initialization = 1;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci#endif
16962306a36Sopenharmony_ci	return retval;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci      err2:
17262306a36Sopenharmony_ci	usb_put_hcd(hcd);
17362306a36Sopenharmony_ci      err1:
17462306a36Sopenharmony_ci	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
17562306a36Sopenharmony_ci	if (pdata->exit)
17662306a36Sopenharmony_ci		pdata->exit(pdev);
17762306a36Sopenharmony_ci	return retval;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic bool usb_phy_clk_valid(struct usb_hcd *hcd)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	void __iomem *non_ehci = hcd->regs;
18362306a36Sopenharmony_ci	bool ret = true;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID))
18662306a36Sopenharmony_ci		ret = false;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return ret;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int ehci_fsl_setup_phy(struct usb_hcd *hcd,
19262306a36Sopenharmony_ci			       enum fsl_usb2_phy_modes phy_mode,
19362306a36Sopenharmony_ci			       unsigned int port_offset)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	u32 portsc, tmp;
19662306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
19762306a36Sopenharmony_ci	void __iomem *non_ehci = hcd->regs;
19862306a36Sopenharmony_ci	struct device *dev = hcd->self.controller;
19962306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (pdata->controller_ver < 0) {
20262306a36Sopenharmony_ci		dev_warn(hcd->self.controller, "Could not get controller version\n");
20362306a36Sopenharmony_ci		return -ENODEV;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
20762306a36Sopenharmony_ci	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	switch (phy_mode) {
21062306a36Sopenharmony_ci	case FSL_USB2_PHY_ULPI:
21162306a36Sopenharmony_ci		if (pdata->have_sysif_regs && pdata->controller_ver) {
21262306a36Sopenharmony_ci			/* controller version 1.6 or above */
21362306a36Sopenharmony_ci			/* turn off UTMI PHY first */
21462306a36Sopenharmony_ci			tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
21562306a36Sopenharmony_ci			tmp &= ~(CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN);
21662306a36Sopenharmony_ci			iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci			/* then turn on ULPI and enable USB controller */
21962306a36Sopenharmony_ci			tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
22062306a36Sopenharmony_ci			tmp &= ~CONTROL_REGISTER_W1C_MASK;
22162306a36Sopenharmony_ci			tmp |= ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN;
22262306a36Sopenharmony_ci			iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci		portsc |= PORT_PTS_ULPI;
22562306a36Sopenharmony_ci		break;
22662306a36Sopenharmony_ci	case FSL_USB2_PHY_SERIAL:
22762306a36Sopenharmony_ci		portsc |= PORT_PTS_SERIAL;
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	case FSL_USB2_PHY_UTMI_WIDE:
23062306a36Sopenharmony_ci		portsc |= PORT_PTS_PTW;
23162306a36Sopenharmony_ci		fallthrough;
23262306a36Sopenharmony_ci	case FSL_USB2_PHY_UTMI:
23362306a36Sopenharmony_ci		/* Presence of this node "has_fsl_erratum_a006918"
23462306a36Sopenharmony_ci		 * in device-tree is used to stop USB controller
23562306a36Sopenharmony_ci		 * initialization in Linux
23662306a36Sopenharmony_ci		 */
23762306a36Sopenharmony_ci		if (pdata->has_fsl_erratum_a006918) {
23862306a36Sopenharmony_ci			dev_warn(dev, "USB PHY clock invalid\n");
23962306a36Sopenharmony_ci			return -EINVAL;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci		fallthrough;
24262306a36Sopenharmony_ci	case FSL_USB2_PHY_UTMI_DUAL:
24362306a36Sopenharmony_ci		/* PHY_CLK_VALID bit is de-featured from all controller
24462306a36Sopenharmony_ci		 * versions below 2.4 and is to be checked only for
24562306a36Sopenharmony_ci		 * internal UTMI phy
24662306a36Sopenharmony_ci		 */
24762306a36Sopenharmony_ci		if (pdata->controller_ver > FSL_USB_VER_2_4 &&
24862306a36Sopenharmony_ci		    pdata->have_sysif_regs && !usb_phy_clk_valid(hcd)) {
24962306a36Sopenharmony_ci			dev_err(dev, "USB PHY clock invalid\n");
25062306a36Sopenharmony_ci			return -EINVAL;
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		if (pdata->have_sysif_regs && pdata->controller_ver) {
25462306a36Sopenharmony_ci			/* controller version 1.6 or above */
25562306a36Sopenharmony_ci			tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
25662306a36Sopenharmony_ci			tmp &= ~CONTROL_REGISTER_W1C_MASK;
25762306a36Sopenharmony_ci			tmp |= UTMI_PHY_EN;
25862306a36Sopenharmony_ci			iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci			mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
26162306a36Sopenharmony_ci						become stable - 10ms*/
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci		/* enable UTMI PHY */
26462306a36Sopenharmony_ci		if (pdata->have_sysif_regs) {
26562306a36Sopenharmony_ci			tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
26662306a36Sopenharmony_ci			tmp &= ~CONTROL_REGISTER_W1C_MASK;
26762306a36Sopenharmony_ci			tmp |= CTRL_UTMI_PHY_EN;
26862306a36Sopenharmony_ci			iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
26962306a36Sopenharmony_ci		}
27062306a36Sopenharmony_ci		portsc |= PORT_PTS_UTMI;
27162306a36Sopenharmony_ci		break;
27262306a36Sopenharmony_ci	case FSL_USB2_PHY_NONE:
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (pdata->have_sysif_regs &&
27762306a36Sopenharmony_ci	    pdata->controller_ver > FSL_USB_VER_1_6 &&
27862306a36Sopenharmony_ci	    !usb_phy_clk_valid(hcd)) {
27962306a36Sopenharmony_ci		dev_warn(hcd->self.controller, "USB PHY clock invalid\n");
28062306a36Sopenharmony_ci		return -EINVAL;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) {
28662306a36Sopenharmony_ci		tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
28762306a36Sopenharmony_ci		tmp &= ~CONTROL_REGISTER_W1C_MASK;
28862306a36Sopenharmony_ci		tmp |= USB_CTRL_USB_EN;
28962306a36Sopenharmony_ci		iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct usb_hcd *hcd = ehci_to_hcd(ehci);
29862306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata;
29962306a36Sopenharmony_ci	void __iomem *non_ehci = hcd->regs;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	pdata = dev_get_platdata(hcd->self.controller);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (pdata->have_sysif_regs) {
30462306a36Sopenharmony_ci		/*
30562306a36Sopenharmony_ci		* Turn on cache snooping hardware, since some PowerPC platforms
30662306a36Sopenharmony_ci		* wholly rely on hardware to deal with cache coherent
30762306a36Sopenharmony_ci		*/
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		/* Setup Snooping for all the 4GB space */
31062306a36Sopenharmony_ci		/* SNOOP1 starts from 0x0, size 2G */
31162306a36Sopenharmony_ci		iowrite32be(0x0 | SNOOP_SIZE_2GB,
31262306a36Sopenharmony_ci			    non_ehci + FSL_SOC_USB_SNOOP1);
31362306a36Sopenharmony_ci		/* SNOOP2 starts from 0x80000000, size 2G */
31462306a36Sopenharmony_ci		iowrite32be(0x80000000 | SNOOP_SIZE_2GB,
31562306a36Sopenharmony_ci			    non_ehci + FSL_SOC_USB_SNOOP2);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Deal with USB erratum A-005275 */
31962306a36Sopenharmony_ci	if (pdata->has_fsl_erratum_a005275 == 1)
32062306a36Sopenharmony_ci		ehci->has_fsl_hs_errata = 1;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (pdata->has_fsl_erratum_a005697 == 1)
32362306a36Sopenharmony_ci		ehci->has_fsl_susp_errata = 1;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
32662306a36Sopenharmony_ci			(pdata->operating_mode == FSL_USB2_DR_OTG))
32762306a36Sopenharmony_ci		if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
32862306a36Sopenharmony_ci			return -EINVAL;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
33362306a36Sopenharmony_ci		if (pdata->has_fsl_erratum_14 == 1)
33462306a36Sopenharmony_ci			ehci->has_fsl_port_bug = 1;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
33762306a36Sopenharmony_ci			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
33862306a36Sopenharmony_ci				return -EINVAL;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
34162306a36Sopenharmony_ci			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1))
34262306a36Sopenharmony_ci				return -EINVAL;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (pdata->have_sysif_regs) {
34662306a36Sopenharmony_ci#ifdef CONFIG_FSL_SOC_BOOKE
34762306a36Sopenharmony_ci		iowrite32be(0x00000008, non_ehci + FSL_SOC_USB_PRICTRL);
34862306a36Sopenharmony_ci		iowrite32be(0x00000080, non_ehci + FSL_SOC_USB_AGECNTTHRSH);
34962306a36Sopenharmony_ci#else
35062306a36Sopenharmony_ci		iowrite32be(0x0000000c, non_ehci + FSL_SOC_USB_PRICTRL);
35162306a36Sopenharmony_ci		iowrite32be(0x00000040, non_ehci + FSL_SOC_USB_AGECNTTHRSH);
35262306a36Sopenharmony_ci#endif
35362306a36Sopenharmony_ci		iowrite32be(0x00000001, non_ehci + FSL_SOC_USB_SICTRL);
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/* called after powerup, by probe or system-pm "wakeup" */
36062306a36Sopenharmony_cistatic int ehci_fsl_reinit(struct ehci_hcd *ehci)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	if (ehci_fsl_usb_setup(ehci))
36362306a36Sopenharmony_ci		return -EINVAL;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/* called during probe() after chip reset completes */
36962306a36Sopenharmony_cistatic int ehci_fsl_setup(struct usb_hcd *hcd)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
37262306a36Sopenharmony_ci	int retval;
37362306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata;
37462306a36Sopenharmony_ci	struct device *dev;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	dev = hcd->self.controller;
37762306a36Sopenharmony_ci	pdata = dev_get_platdata(hcd->self.controller);
37862306a36Sopenharmony_ci	ehci->big_endian_desc = pdata->big_endian_desc;
37962306a36Sopenharmony_ci	ehci->big_endian_mmio = pdata->big_endian_mmio;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* EHCI registers start at offset 0x100 */
38262306a36Sopenharmony_ci	ehci->caps = hcd->regs + 0x100;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_85xx)
38562306a36Sopenharmony_ci	/*
38662306a36Sopenharmony_ci	 * Deal with MPC834X/85XX that need port power to be cycled
38762306a36Sopenharmony_ci	 * after the power fault condition is removed. Otherwise the
38862306a36Sopenharmony_ci	 * state machine does not reflect PORTSC[CSC] correctly.
38962306a36Sopenharmony_ci	 */
39062306a36Sopenharmony_ci	ehci->need_oc_pp_cycle = 1;
39162306a36Sopenharmony_ci#endif
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	hcd->has_tt = 1;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	retval = ehci_setup(hcd);
39662306a36Sopenharmony_ci	if (retval)
39762306a36Sopenharmony_ci		return retval;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (of_device_is_compatible(dev->parent->of_node,
40062306a36Sopenharmony_ci				    "fsl,mpc5121-usb2-dr")) {
40162306a36Sopenharmony_ci		/*
40262306a36Sopenharmony_ci		 * set SBUSCFG:AHBBRST so that control msgs don't
40362306a36Sopenharmony_ci		 * fail when doing heavy PATA writes.
40462306a36Sopenharmony_ci		 */
40562306a36Sopenharmony_ci		ehci_writel(ehci, SBUSCFG_INCR8,
40662306a36Sopenharmony_ci			    hcd->regs + FSL_SOC_USB_SBUSCFG);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	retval = ehci_fsl_reinit(ehci);
41062306a36Sopenharmony_ci	return retval;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistruct ehci_fsl {
41462306a36Sopenharmony_ci	struct ehci_hcd	ehci;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci#ifdef CONFIG_PM
41762306a36Sopenharmony_ci	/* Saved USB PHY settings, need to restore after deep sleep. */
41862306a36Sopenharmony_ci	u32 usb_ctrl;
41962306a36Sopenharmony_ci#endif
42062306a36Sopenharmony_ci};
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci#ifdef CONFIG_PM
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci#ifdef CONFIG_PPC_MPC512x
42562306a36Sopenharmony_cistatic int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
42862306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
42962306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
43062306a36Sopenharmony_ci	u32 tmp;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci#ifdef CONFIG_DYNAMIC_DEBUG
43362306a36Sopenharmony_ci	u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
43462306a36Sopenharmony_ci	mode &= USBMODE_CM_MASK;
43562306a36Sopenharmony_ci	tmp = ehci_readl(ehci, hcd->regs + 0x140);	/* usbcmd */
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	dev_dbg(dev, "suspend=%d already_suspended=%d "
43862306a36Sopenharmony_ci		"mode=%d  usbcmd %08x\n", pdata->suspended,
43962306a36Sopenharmony_ci		pdata->already_suspended, mode, tmp);
44062306a36Sopenharmony_ci#endif
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	/*
44362306a36Sopenharmony_ci	 * If the controller is already suspended, then this must be a
44462306a36Sopenharmony_ci	 * PM suspend.  Remember this fact, so that we will leave the
44562306a36Sopenharmony_ci	 * controller suspended at PM resume time.
44662306a36Sopenharmony_ci	 */
44762306a36Sopenharmony_ci	if (pdata->suspended) {
44862306a36Sopenharmony_ci		dev_dbg(dev, "already suspended, leaving early\n");
44962306a36Sopenharmony_ci		pdata->already_suspended = 1;
45062306a36Sopenharmony_ci		return 0;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	dev_dbg(dev, "suspending...\n");
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	ehci->rh_state = EHCI_RH_SUSPENDED;
45662306a36Sopenharmony_ci	dev->power.power_state = PMSG_SUSPEND;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* ignore non-host interrupts */
45962306a36Sopenharmony_ci	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* stop the controller */
46262306a36Sopenharmony_ci	tmp = ehci_readl(ehci, &ehci->regs->command);
46362306a36Sopenharmony_ci	tmp &= ~CMD_RUN;
46462306a36Sopenharmony_ci	ehci_writel(ehci, tmp, &ehci->regs->command);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* save EHCI registers */
46762306a36Sopenharmony_ci	pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
46862306a36Sopenharmony_ci	pdata->pm_command &= ~CMD_RUN;
46962306a36Sopenharmony_ci	pdata->pm_status  = ehci_readl(ehci, &ehci->regs->status);
47062306a36Sopenharmony_ci	pdata->pm_intr_enable  = ehci_readl(ehci, &ehci->regs->intr_enable);
47162306a36Sopenharmony_ci	pdata->pm_frame_index  = ehci_readl(ehci, &ehci->regs->frame_index);
47262306a36Sopenharmony_ci	pdata->pm_segment  = ehci_readl(ehci, &ehci->regs->segment);
47362306a36Sopenharmony_ci	pdata->pm_frame_list  = ehci_readl(ehci, &ehci->regs->frame_list);
47462306a36Sopenharmony_ci	pdata->pm_async_next  = ehci_readl(ehci, &ehci->regs->async_next);
47562306a36Sopenharmony_ci	pdata->pm_configured_flag  =
47662306a36Sopenharmony_ci		ehci_readl(ehci, &ehci->regs->configured_flag);
47762306a36Sopenharmony_ci	pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
47862306a36Sopenharmony_ci	pdata->pm_usbgenctrl = ehci_readl(ehci,
47962306a36Sopenharmony_ci					  hcd->regs + FSL_SOC_USB_USBGENCTRL);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/* clear the W1C bits */
48262306a36Sopenharmony_ci	pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	pdata->suspended = 1;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* clear PP to cut power to the port */
48762306a36Sopenharmony_ci	tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
48862306a36Sopenharmony_ci	tmp &= ~PORT_POWER;
48962306a36Sopenharmony_ci	ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int ehci_fsl_mpc512x_drv_resume(struct device *dev)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
49762306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
49862306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
49962306a36Sopenharmony_ci	u32 tmp;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	dev_dbg(dev, "suspend=%d already_suspended=%d\n",
50262306a36Sopenharmony_ci		pdata->suspended, pdata->already_suspended);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/*
50562306a36Sopenharmony_ci	 * If the controller was already suspended at suspend time,
50662306a36Sopenharmony_ci	 * then don't resume it now.
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	if (pdata->already_suspended) {
50962306a36Sopenharmony_ci		dev_dbg(dev, "already suspended, leaving early\n");
51062306a36Sopenharmony_ci		pdata->already_suspended = 0;
51162306a36Sopenharmony_ci		return 0;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (!pdata->suspended) {
51562306a36Sopenharmony_ci		dev_dbg(dev, "not suspended, leaving early\n");
51662306a36Sopenharmony_ci		return 0;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	pdata->suspended = 0;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	dev_dbg(dev, "resuming...\n");
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* set host mode */
52462306a36Sopenharmony_ci	tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
52562306a36Sopenharmony_ci	ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_usbgenctrl,
52862306a36Sopenharmony_ci		    hcd->regs + FSL_SOC_USB_USBGENCTRL);
52962306a36Sopenharmony_ci	ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
53062306a36Sopenharmony_ci		    hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	/* restore EHCI registers */
53562306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
53662306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
53762306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
53862306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
53962306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
54062306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
54162306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_configured_flag,
54262306a36Sopenharmony_ci		    &ehci->regs->configured_flag);
54362306a36Sopenharmony_ci	ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
54662306a36Sopenharmony_ci	ehci->rh_state = EHCI_RH_RUNNING;
54762306a36Sopenharmony_ci	dev->power.power_state = PMSG_ON;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	tmp = ehci_readl(ehci, &ehci->regs->command);
55062306a36Sopenharmony_ci	tmp |= CMD_RUN;
55162306a36Sopenharmony_ci	ehci_writel(ehci, tmp, &ehci->regs->command);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	usb_hcd_resume_root_hub(hcd);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	return 0;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci#else
55862306a36Sopenharmony_cistatic inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	return 0;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	return 0;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci#endif /* CONFIG_PPC_MPC512x */
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return container_of(ehci, struct ehci_fsl, ehci);
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int ehci_fsl_drv_suspend(struct device *dev)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
57962306a36Sopenharmony_ci	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
58062306a36Sopenharmony_ci	void __iomem *non_ehci = hcd->regs;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (of_device_is_compatible(dev->parent->of_node,
58362306a36Sopenharmony_ci				    "fsl,mpc5121-usb2-dr")) {
58462306a36Sopenharmony_ci		return ehci_fsl_mpc512x_drv_suspend(dev);
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
58862306a36Sopenharmony_ci			device_may_wakeup(dev));
58962306a36Sopenharmony_ci	if (!fsl_deep_sleep())
59062306a36Sopenharmony_ci		return 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	ehci_fsl->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
59362306a36Sopenharmony_ci	return 0;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int ehci_fsl_drv_resume(struct device *dev)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
59962306a36Sopenharmony_ci	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
60062306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
60162306a36Sopenharmony_ci	void __iomem *non_ehci = hcd->regs;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (of_device_is_compatible(dev->parent->of_node,
60462306a36Sopenharmony_ci				    "fsl,mpc5121-usb2-dr")) {
60562306a36Sopenharmony_ci		return ehci_fsl_mpc512x_drv_resume(dev);
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	ehci_prepare_ports_for_controller_resume(ehci);
60962306a36Sopenharmony_ci	if (!fsl_deep_sleep())
61062306a36Sopenharmony_ci		return 0;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	usb_root_hub_lost_power(hcd->self.root_hub);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* Restore USB PHY settings and enable the controller. */
61562306a36Sopenharmony_ci	iowrite32be(ehci_fsl->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	ehci_reset(ehci);
61862306a36Sopenharmony_ci	ehci_fsl_reinit(ehci);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int ehci_fsl_drv_restore(struct device *dev)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	usb_root_hub_lost_power(hcd->self.root_hub);
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic const struct dev_pm_ops ehci_fsl_pm_ops = {
63262306a36Sopenharmony_ci	.suspend = ehci_fsl_drv_suspend,
63362306a36Sopenharmony_ci	.resume = ehci_fsl_drv_resume,
63462306a36Sopenharmony_ci	.restore = ehci_fsl_drv_restore,
63562306a36Sopenharmony_ci};
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci#define EHCI_FSL_PM_OPS		(&ehci_fsl_pm_ops)
63862306a36Sopenharmony_ci#else
63962306a36Sopenharmony_ci#define EHCI_FSL_PM_OPS		NULL
64062306a36Sopenharmony_ci#endif /* CONFIG_PM */
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci#ifdef CONFIG_USB_OTG
64362306a36Sopenharmony_cistatic int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
64662306a36Sopenharmony_ci	u32 status;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (!port)
64962306a36Sopenharmony_ci		return -EINVAL;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	port--;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* start port reset before HNP protocol time out */
65462306a36Sopenharmony_ci	status = readl(&ehci->regs->port_status[port]);
65562306a36Sopenharmony_ci	if (!(status & PORT_CONNECT))
65662306a36Sopenharmony_ci		return -ENODEV;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/* hub_wq will finish the reset later */
65962306a36Sopenharmony_ci	if (ehci_is_TDI(ehci)) {
66062306a36Sopenharmony_ci		writel(PORT_RESET |
66162306a36Sopenharmony_ci		       (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)),
66262306a36Sopenharmony_ci		       &ehci->regs->port_status[port]);
66362306a36Sopenharmony_ci	} else {
66462306a36Sopenharmony_ci		writel(PORT_RESET, &ehci->regs->port_status[port]);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return 0;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci#else
67062306a36Sopenharmony_ci#define ehci_start_port_reset	NULL
67162306a36Sopenharmony_ci#endif /* CONFIG_USB_OTG */
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic const struct ehci_driver_overrides ehci_fsl_overrides __initconst = {
67462306a36Sopenharmony_ci	.extra_priv_size = sizeof(struct ehci_fsl),
67562306a36Sopenharmony_ci	.reset = ehci_fsl_setup,
67662306a36Sopenharmony_ci};
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/**
67962306a36Sopenharmony_ci * fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs
68062306a36Sopenharmony_ci * @pdev: USB Host Controller being removed
68162306a36Sopenharmony_ci *
68262306a36Sopenharmony_ci * Context: task context, might sleep
68362306a36Sopenharmony_ci *
68462306a36Sopenharmony_ci * Reverses the effect of usb_hcd_fsl_probe().
68562306a36Sopenharmony_ci */
68662306a36Sopenharmony_cistatic void fsl_ehci_drv_remove(struct platform_device *pdev)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
68962306a36Sopenharmony_ci	struct usb_hcd *hcd = platform_get_drvdata(pdev);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hcd->usb_phy)) {
69262306a36Sopenharmony_ci		otg_set_host(hcd->usb_phy->otg, NULL);
69362306a36Sopenharmony_ci		usb_put_phy(hcd->usb_phy);
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	usb_remove_hcd(hcd);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/*
69962306a36Sopenharmony_ci	 * do platform specific un-initialization:
70062306a36Sopenharmony_ci	 * release iomux pins, disable clock, etc.
70162306a36Sopenharmony_ci	 */
70262306a36Sopenharmony_ci	if (pdata->exit)
70362306a36Sopenharmony_ci		pdata->exit(pdev);
70462306a36Sopenharmony_ci	usb_put_hcd(hcd);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic struct platform_driver ehci_fsl_driver = {
70862306a36Sopenharmony_ci	.probe = fsl_ehci_drv_probe,
70962306a36Sopenharmony_ci	.remove_new = fsl_ehci_drv_remove,
71062306a36Sopenharmony_ci	.shutdown = usb_hcd_platform_shutdown,
71162306a36Sopenharmony_ci	.driver = {
71262306a36Sopenharmony_ci		.name = DRV_NAME,
71362306a36Sopenharmony_ci		.pm = EHCI_FSL_PM_OPS,
71462306a36Sopenharmony_ci	},
71562306a36Sopenharmony_ci};
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic int __init ehci_fsl_init(void)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	if (usb_disabled())
72062306a36Sopenharmony_ci		return -ENODEV;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	ehci_init_driver(&fsl_ehci_hc_driver, &ehci_fsl_overrides);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	fsl_ehci_hc_driver.product_desc =
72562306a36Sopenharmony_ci			"Freescale On-Chip EHCI Host Controller";
72662306a36Sopenharmony_ci	fsl_ehci_hc_driver.start_port_reset = ehci_start_port_reset;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return platform_driver_register(&ehci_fsl_driver);
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_cimodule_init(ehci_fsl_init);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic void __exit ehci_fsl_cleanup(void)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	platform_driver_unregister(&ehci_fsl_driver);
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_cimodule_exit(ehci_fsl_cleanup);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
74062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
74162306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME);
742