diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/ehci-exynos.c | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index f3c077d82e..86cf6312fe 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> #include <libfdt.h> #include <malloc.h> @@ -24,19 +25,73 @@ /* Declare global data pointer */ DECLARE_GLOBAL_DATA_PTR; +#ifdef CONFIG_DM_USB +struct exynos_ehci_platdata { + struct usb_platdata usb_plat; + fdt_addr_t hcd_base; + fdt_addr_t phy_base; + struct gpio_desc vbus_gpio; +}; +#endif + /** * Contains pointers to register base addresses * for the usb controller. */ struct exynos_ehci { + struct ehci_ctrl ctrl; struct exynos_usb_phy *usb; struct ehci_hccr *hcd; +#ifndef CONFIG_DM_USB struct gpio_desc vbus_gpio; +#endif }; +#ifndef CONFIG_DM_USB static struct exynos_ehci exynos; +#endif -#ifdef CONFIG_OF_CONTROL +#ifdef CONFIG_DM_USB +static int ehci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct exynos_ehci_platdata *plat = dev_get_platdata(dev); + const void *blob = gd->fdt_blob; + unsigned int node; + int depth; + + /* + * Get the base address for XHCI controller from the device node + */ + plat->hcd_base = dev_get_addr(dev); + if (plat->hcd_base == FDT_ADDR_T_NONE) { + debug("Can't get the XHCI register base address\n"); + return -ENXIO; + } + + depth = 0; + node = fdtdec_next_compatible_subnode(blob, dev->of_offset, + COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth); + if (node <= 0) { + debug("XHCI: Can't get device node for usb3-phy controller\n"); + return -ENODEV; + } + + /* + * Get the base address for usbphy from the device node + */ + plat->phy_base = fdtdec_get_addr(blob, node, "reg"); + if (plat->phy_base == FDT_ADDR_T_NONE) { + debug("Can't get the usbphy register address\n"); + return -ENXIO; + } + + /* Vbus gpio */ + gpio_request_by_name(dev, "samsung,vbus-gpio", 0, + &plat->vbus_gpio, GPIOD_IS_OUT); + + return 0; +} +#else static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos) { fdt_addr_t addr; @@ -215,6 +270,7 @@ static void reset_usb_phy(struct exynos_usb_phy *usb) set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE); } +#ifndef CONFIG_DM_USB /* * EHCI-initialization * Create the appropriate control structures to manage @@ -268,3 +324,57 @@ int ehci_hcd_stop(int index) return 0; } +#endif + +#ifdef CONFIG_DM_USB +static int ehci_usb_probe(struct udevice *dev) +{ + struct exynos_ehci_platdata *plat = dev_get_platdata(dev); + struct exynos_ehci *ctx = dev_get_priv(dev); + struct ehci_hcor *hcor; + + ctx->hcd = (struct ehci_hccr *)plat->hcd_base; + ctx->usb = (struct exynos_usb_phy *)plat->phy_base; + hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd + + HC_LENGTH(ehci_readl(&ctx->hcd->cr_capbase))); + + /* setup the Vbus gpio here */ + if (dm_gpio_is_valid(&plat->vbus_gpio)) + dm_gpio_set_value(&plat->vbus_gpio, 1); + + setup_usb_phy(ctx->usb); + + return ehci_register(dev, ctx->hcd, hcor, NULL, 0, USB_INIT_HOST); +} + +static int ehci_usb_remove(struct udevice *dev) +{ + struct exynos_ehci *ctx = dev_get_priv(dev); + int ret; + + ret = ehci_deregister(dev); + if (ret) + return ret; + reset_usb_phy(ctx->usb); + + return 0; +} + +static const struct udevice_id ehci_usb_ids[] = { + { .compatible = "samsung,exynos-ehci" }, + { } +}; + +U_BOOT_DRIVER(usb_ehci) = { + .name = "ehci_exynos", + .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_alloc_size = sizeof(struct exynos_ehci), + .platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif |