linux/drivers/usb/host/ehci-fsl.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2005-2009 MontaVista Software, Inc.
 * Copyright 2008,2012,2015      Freescale Semiconductor, Inc.
 *
 * Ported to 834x by Randy Vinson <[email protected]> using code provided
 * by Hunter Wu.
 * Power Management support by Dave Liu <[email protected]>,
 * Jerry Huang <[email protected]> and
 * Anton Vorontsov <[email protected]>.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/err.h>
#include <linux/usb.h>
#include <linux/usb/ehci_def.h>
#include <linux/usb/hcd.h>
#include <linux/usb/otg.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/of.h>
#include <linux/io.h>

#include "ehci.h"
#include "ehci-fsl.h"

#define DRIVER_DESC
#define DRV_NAME

static struct hc_driver __read_mostly fsl_ehci_hc_driver;

/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */

/*
 * fsl_ehci_drv_probe - initialize FSL-based HCDs
 * @pdev: USB Host Controller being probed
 *
 * Context: task context, might sleep
 *
 * Allocates basic resources for this USB host controller.
 */
static int fsl_ehci_drv_probe(struct platform_device *pdev)
{}

static bool usb_phy_clk_valid(struct usb_hcd *hcd)
{}

static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
			       enum fsl_usb2_phy_modes phy_mode,
			       unsigned int port_offset)
{}

static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
{}

/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
{}

/* called during probe() after chip reset completes */
static int ehci_fsl_setup(struct usb_hcd *hcd)
{}

struct ehci_fsl {};

#ifdef CONFIG_PM

#ifdef CONFIG_PPC_MPC512x
static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
	u32 tmp;

#ifdef CONFIG_DYNAMIC_DEBUG
	u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
	mode &= USBMODE_CM_MASK;
	tmp = ehci_readl(ehci, hcd->regs + 0x140);	/* usbcmd */

	dev_dbg(dev, "suspend=%d already_suspended=%d "
		"mode=%d  usbcmd %08x\n", pdata->suspended,
		pdata->already_suspended, mode, tmp);
#endif

	/*
	 * If the controller is already suspended, then this must be a
	 * PM suspend.  Remember this fact, so that we will leave the
	 * controller suspended at PM resume time.
	 */
	if (pdata->suspended) {
		dev_dbg(dev, "already suspended, leaving early\n");
		pdata->already_suspended = 1;
		return 0;
	}

	dev_dbg(dev, "suspending...\n");

	ehci->rh_state = EHCI_RH_SUSPENDED;
	dev->power.power_state = PMSG_SUSPEND;

	/* ignore non-host interrupts */
	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	/* stop the controller */
	tmp = ehci_readl(ehci, &ehci->regs->command);
	tmp &= ~CMD_RUN;
	ehci_writel(ehci, tmp, &ehci->regs->command);

	/* save EHCI registers */
	pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
	pdata->pm_command &= ~CMD_RUN;
	pdata->pm_status  = ehci_readl(ehci, &ehci->regs->status);
	pdata->pm_intr_enable  = ehci_readl(ehci, &ehci->regs->intr_enable);
	pdata->pm_frame_index  = ehci_readl(ehci, &ehci->regs->frame_index);
	pdata->pm_segment  = ehci_readl(ehci, &ehci->regs->segment);
	pdata->pm_frame_list  = ehci_readl(ehci, &ehci->regs->frame_list);
	pdata->pm_async_next  = ehci_readl(ehci, &ehci->regs->async_next);
	pdata->pm_configured_flag  =
		ehci_readl(ehci, &ehci->regs->configured_flag);
	pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
	pdata->pm_usbgenctrl = ehci_readl(ehci,
					  hcd->regs + FSL_SOC_USB_USBGENCTRL);

	/* clear the W1C bits */
	pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);

	pdata->suspended = 1;

	/* clear PP to cut power to the port */
	tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
	tmp &= ~PORT_POWER;
	ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);

	return 0;
}

static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
	u32 tmp;

	dev_dbg(dev, "suspend=%d already_suspended=%d\n",
		pdata->suspended, pdata->already_suspended);

	/*
	 * If the controller was already suspended at suspend time,
	 * then don't resume it now.
	 */
	if (pdata->already_suspended) {
		dev_dbg(dev, "already suspended, leaving early\n");
		pdata->already_suspended = 0;
		return 0;
	}

	if (!pdata->suspended) {
		dev_dbg(dev, "not suspended, leaving early\n");
		return 0;
	}

	pdata->suspended = 0;

	dev_dbg(dev, "resuming...\n");

	/* set host mode */
	tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
	ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);

	ehci_writel(ehci, pdata->pm_usbgenctrl,
		    hcd->regs + FSL_SOC_USB_USBGENCTRL);
	ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
		    hcd->regs + FSL_SOC_USB_ISIPHYCTRL);

	ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);

	/* restore EHCI registers */
	ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
	ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
	ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
	ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
	ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
	ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
	ehci_writel(ehci, pdata->pm_configured_flag,
		    &ehci->regs->configured_flag);
	ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);

	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
	ehci->rh_state = EHCI_RH_RUNNING;
	dev->power.power_state = PMSG_ON;

	tmp = ehci_readl(ehci, &ehci->regs->command);
	tmp |= CMD_RUN;
	ehci_writel(ehci, tmp, &ehci->regs->command);

	usb_hcd_resume_root_hub(hcd);

	return 0;
}
#else
static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
{}

static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
{}
#endif /* CONFIG_PPC_MPC512x */

static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
{}

static int ehci_fsl_drv_suspend(struct device *dev)
{}

static int ehci_fsl_drv_resume(struct device *dev)
{}

static int ehci_fsl_drv_restore(struct device *dev)
{}

static const struct dev_pm_ops ehci_fsl_pm_ops =;

#define EHCI_FSL_PM_OPS
#else
#define EHCI_FSL_PM_OPS
#endif /* CONFIG_PM */

#ifdef CONFIG_USB_OTG
static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
{}
#else
#define ehci_start_port_reset
#endif /* CONFIG_USB_OTG */

static const struct ehci_driver_overrides ehci_fsl_overrides __initconst =;

/**
 * fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs
 * @pdev: USB Host Controller being removed
 *
 * Context: task context, might sleep
 *
 * Reverses the effect of usb_hcd_fsl_probe().
 */
static void fsl_ehci_drv_remove(struct platform_device *pdev)
{}

static struct platform_driver ehci_fsl_driver =;

static int __init ehci_fsl_init(void)
{}
module_init();

static void __exit ehci_fsl_cleanup(void)
{}
module_exit(ehci_fsl_cleanup);

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS();