u-boot-brain/drivers/usb/host/ehci-msm.c
Simon Glass 41575d8e4c dm: treewide: Rename auto_alloc_size members to be shorter
This construct is quite long-winded. In earlier days it made some sense
since auto-allocation was a strange concept. But with driver model now
used pretty universally, we can shorten this to 'auto'. This reduces
verbosity and makes it easier to read.

Coincidentally it also ensures that every declaration is on one line,
thus making dtoc's job easier.

Signed-off-by: Simon Glass <sjg@chromium.org>
2020-12-13 08:00:25 -07:00

151 lines
3.3 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Qualcomm EHCI driver
*
* (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
*
* Based on Linux driver
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <usb.h>
#include <usb/ehci-ci.h>
#include <usb/ulpi.h>
#include <wait_bit.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <linux/compat.h>
#include "ehci.h"
struct msm_ehci_priv {
struct ehci_ctrl ctrl; /* Needed by EHCI */
struct usb_ehci *ehci; /* Start of IP core*/
struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
struct phy phy;
};
static int msm_init_after_reset(struct ehci_ctrl *dev)
{
struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
struct usb_ehci *ehci = p->ehci;
generic_phy_reset(&p->phy);
/* set mode to host controller */
writel(CM_HOST, &ehci->usbmode);
return 0;
}
static const struct ehci_ops msm_ehci_ops = {
.init_after_reset = msm_init_after_reset
};
static int ehci_usb_probe(struct udevice *dev)
{
struct msm_ehci_priv *p = dev_get_priv(dev);
struct usb_ehci *ehci = p->ehci;
struct usb_platdata *plat = dev_get_platdata(dev);
struct ehci_hccr *hccr;
struct ehci_hcor *hcor;
int ret;
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
ret = ehci_setup_phy(dev, &p->phy, 0);
if (ret)
return ret;
ret = board_usb_init(0, plat->init_type);
if (ret < 0)
return ret;
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
plat->init_type);
}
static int ehci_usb_remove(struct udevice *dev)
{
struct msm_ehci_priv *p = dev_get_priv(dev);
struct usb_ehci *ehci = p->ehci;
int ret;
ret = ehci_deregister(dev);
if (ret)
return ret;
/* Stop controller. */
clrbits_le32(&ehci->usbcmd, CMD_RUN);
ret = ehci_shutdown_phy(dev, &p->phy);
if (ret)
return ret;
ret = board_usb_init(0, USB_INIT_DEVICE); /* Board specific hook */
if (ret < 0)
return ret;
/* Reset controller */
setbits_le32(&ehci->usbcmd, CMD_RESET);
/* Wait for reset */
if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
printf("Stuck on USB reset.\n");
return -ETIMEDOUT;
}
return 0;
}
static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
{
struct msm_ehci_priv *priv = dev_get_priv(dev);
priv->ulpi_vp.port_num = 0;
priv->ehci = dev_read_addr_ptr(dev);
if (priv->ehci == (void *)FDT_ADDR_T_NONE)
return -EINVAL;
/* Warning: this will not work if viewport address is > 64 bit due to
* ULPI design.
*/
priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
return 0;
}
#if defined(CONFIG_CI_UDC)
/* Little quirk that MSM needs with Chipidea controller
* Must reinit phy after reset
*/
void ci_init_after_reset(struct ehci_ctrl *ctrl)
{
struct msm_ehci_priv *p = ctrl->priv;
generic_phy_reset(&p->phy);
}
#endif
static const struct udevice_id ehci_usb_ids[] = {
{ .compatible = "qcom,ehci-host", },
{ }
};
U_BOOT_DRIVER(usb_ehci) = {
.name = "ehci_msm",
.id = UCLASS_USB,
.of_match = ehci_usb_ids,
.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
.probe = ehci_usb_probe,
.remove = ehci_usb_remove,
.ops = &ehci_usb_ops,
.priv_auto = sizeof(struct msm_ehci_priv),
.platdata_auto = sizeof(struct usb_platdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};