Lines Matching +full:usb +full:- +full:ehci

1 // SPDX-License-Identifier: GPL-2.0-only
3 * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
5 * Copyright (C) 2011-2013 Texas Instruments Incorporated - https://www.ti.com
15 #include <linux/dma-mapping.h>
17 #include <linux/platform_data/usb-omap.h>
23 #include "omap-usb.h"
26 #define OMAP_EHCI_DEVICE "ehci-omap"
27 #define OMAP_OHCI_DEVICE "ohci-omap3"
56 /* OMAP4-specific defines */
72 /* Values of UHH_REVISION - Note: these are not given in the TRM */
76 #define is_omap_usbhs_rev1(x) (x->usbhs_rev == OMAP_USBHS_REV1)
77 #define is_omap_usbhs_rev2(x) (x->usbhs_rev == OMAP_USBHS_REV2)
103 /*-------------------------------------------------------------------------*/
108 /*-------------------------------------------------------------------------*/
120 /*-------------------------------------------------------------------------*/
123 * Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h>
124 * to the device tree binding portN-mode found in
125 * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt'
129 [OMAP_EHCI_PORT_MODE_PHY] = "ehci-phy",
130 [OMAP_EHCI_PORT_MODE_TLL] = "ehci-tll",
131 [OMAP_EHCI_PORT_MODE_HSIC] = "ehci-hsic",
132 [OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0] = "ohci-phy-6pin-datse0",
133 [OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM] = "ohci-phy-6pin-dpdm",
134 [OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0] = "ohci-phy-3pin-datse0",
135 [OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM] = "ohci-phy-4pin-dpdm",
136 [OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0] = "ohci-tll-6pin-datse0",
137 [OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM] = "ohci-tll-6pin-dpdm",
138 [OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0] = "ohci-tll-3pin-datse0",
139 [OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM] = "ohci-tll-4pin-dpdm",
140 [OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0] = "ohci-tll-2pin-datse0",
141 [OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM] = "ohci-tll-2pin-dpdm",
170 child->dev.dma_mask = &usbhs_dmamask; in omap_usbhs_alloc_child()
171 dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32)); in omap_usbhs_alloc_child()
172 child->dev.parent = dev; in omap_usbhs_alloc_child()
191 struct device *dev = &pdev->dev; in omap_usbhs_alloc_children()
193 struct platform_device *ehci; in omap_usbhs_alloc_children() local
199 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); in omap_usbhs_alloc_children()
201 dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n"); in omap_usbhs_alloc_children()
202 ret = -ENODEV; in omap_usbhs_alloc_children()
207 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq"); in omap_usbhs_alloc_children()
209 dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n"); in omap_usbhs_alloc_children()
210 ret = -ENODEV; in omap_usbhs_alloc_children()
215 ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata, in omap_usbhs_alloc_children()
218 if (!ehci) { in omap_usbhs_alloc_children()
220 ret = -ENOMEM; in omap_usbhs_alloc_children()
227 ret = -ENODEV; in omap_usbhs_alloc_children()
232 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq"); in omap_usbhs_alloc_children()
235 ret = -ENODEV; in omap_usbhs_alloc_children()
244 ret = -ENOMEM; in omap_usbhs_alloc_children()
251 platform_device_unregister(ehci); in omap_usbhs_alloc_children()
280 struct usbhs_omap_platform_data *pdata = omap->pdata; in usbhs_runtime_resume()
287 if (!IS_ERR(omap->ehci_logic_fck)) in usbhs_runtime_resume()
288 clk_prepare_enable(omap->ehci_logic_fck); in usbhs_runtime_resume()
290 for (i = 0; i < omap->nports; i++) { in usbhs_runtime_resume()
291 switch (pdata->port_mode[i]) { in usbhs_runtime_resume()
293 if (!IS_ERR(omap->hsic60m_clk[i])) { in usbhs_runtime_resume()
294 r = clk_prepare_enable(omap->hsic60m_clk[i]); in usbhs_runtime_resume()
302 if (!IS_ERR(omap->hsic480m_clk[i])) { in usbhs_runtime_resume()
303 r = clk_prepare_enable(omap->hsic480m_clk[i]); in usbhs_runtime_resume()
313 if (!IS_ERR(omap->utmi_clk[i])) { in usbhs_runtime_resume()
314 r = clk_prepare_enable(omap->utmi_clk[i]); in usbhs_runtime_resume()
333 struct usbhs_omap_platform_data *pdata = omap->pdata; in usbhs_runtime_suspend()
338 for (i = 0; i < omap->nports; i++) { in usbhs_runtime_suspend()
339 switch (pdata->port_mode[i]) { in usbhs_runtime_suspend()
341 if (!IS_ERR(omap->hsic60m_clk[i])) in usbhs_runtime_suspend()
342 clk_disable_unprepare(omap->hsic60m_clk[i]); in usbhs_runtime_suspend()
344 if (!IS_ERR(omap->hsic480m_clk[i])) in usbhs_runtime_suspend()
345 clk_disable_unprepare(omap->hsic480m_clk[i]); in usbhs_runtime_suspend()
349 if (!IS_ERR(omap->utmi_clk[i])) in usbhs_runtime_suspend()
350 clk_disable_unprepare(omap->utmi_clk[i]); in usbhs_runtime_suspend()
357 if (!IS_ERR(omap->ehci_logic_fck)) in usbhs_runtime_suspend()
358 clk_disable_unprepare(omap->ehci_logic_fck); in usbhs_runtime_suspend()
368 struct usbhs_omap_platform_data *pdata = omap->pdata; in omap_usbhs_rev1_hostconfig()
371 for (i = 0; i < omap->nports; i++) { in omap_usbhs_rev1_hostconfig()
372 switch (pdata->port_mode[i]) { in omap_usbhs_rev1_hostconfig()
377 if (pdata->single_ulpi_bypass) in omap_usbhs_rev1_hostconfig()
384 << (i-1)); in omap_usbhs_rev1_hostconfig()
387 if (pdata->single_ulpi_bypass) in omap_usbhs_rev1_hostconfig()
394 << (i-1); in omap_usbhs_rev1_hostconfig()
399 if (pdata->single_ulpi_bypass) { in omap_usbhs_rev1_hostconfig()
403 for (i = 0; i < omap->nports; i++) { in omap_usbhs_rev1_hostconfig()
404 if (is_ehci_phy_mode(pdata->port_mode[i])) { in omap_usbhs_rev1_hostconfig()
417 struct usbhs_omap_platform_data *pdata = omap->pdata; in omap_usbhs_rev2_hostconfig()
420 for (i = 0; i < omap->nports; i++) { in omap_usbhs_rev2_hostconfig()
424 if (is_ehci_tll_mode(pdata->port_mode[i]) || in omap_usbhs_rev2_hostconfig()
425 (is_ohci_port(pdata->port_mode[i]))) in omap_usbhs_rev2_hostconfig()
427 else if (is_ehci_hsic_mode(pdata->port_mode[i])) in omap_usbhs_rev2_hostconfig()
443 reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); in omap_usbhs_init()
451 switch (omap->usbhs_rev) { in omap_usbhs_init()
465 usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); in omap_usbhs_init()
475 struct device_node *node = dev->of_node; in usbhs_omap_get_dt_pdata()
477 ret = of_property_read_u32(node, "num-ports", &pdata->nports); in usbhs_omap_get_dt_pdata()
479 pdata->nports = 0; in usbhs_omap_get_dt_pdata()
481 if (pdata->nports > OMAP3_HS_USB_PORTS) { in usbhs_omap_get_dt_pdata()
483 pdata->nports, OMAP3_HS_USB_PORTS); in usbhs_omap_get_dt_pdata()
484 return -ENODEV; in usbhs_omap_get_dt_pdata()
492 pdata->port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED; in usbhs_omap_get_dt_pdata()
494 snprintf(prop, sizeof(prop), "port%d-mode", i + 1); in usbhs_omap_get_dt_pdata()
502 dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n", in usbhs_omap_get_dt_pdata()
504 return -ENODEV; in usbhs_omap_get_dt_pdata()
507 dev_dbg(dev, "port%d-mode: %s -> %d\n", i, mode, ret); in usbhs_omap_get_dt_pdata()
508 pdata->port_mode[i] = ret; in usbhs_omap_get_dt_pdata()
512 pdata->single_ulpi_bypass = of_property_read_bool(node, in usbhs_omap_get_dt_pdata()
513 "single-ulpi-bypass"); in usbhs_omap_get_dt_pdata()
519 { .compatible = "ti,ehci-omap", },
520 { .compatible = "ti,ohci-omap3", },
525 * usbhs_omap_probe - initialize TI-based HCDs
527 * Allocates basic resources for this USB host controller.
533 struct device *dev = &pdev->dev; in usbhs_omap_probe()
540 if (dev->of_node) { in usbhs_omap_probe()
544 return -ENOMEM; in usbhs_omap_probe()
550 dev->platform_data = pdata; in usbhs_omap_probe()
555 return -ENODEV; in usbhs_omap_probe()
558 if (pdata->nports > OMAP3_HS_USB_PORTS) { in usbhs_omap_probe()
560 pdata->nports, OMAP3_HS_USB_PORTS); in usbhs_omap_probe()
561 return -ENODEV; in usbhs_omap_probe()
567 return -ENOMEM; in usbhs_omap_probe()
570 omap->uhh_base = devm_platform_ioremap_resource(pdev, 0); in usbhs_omap_probe()
571 if (IS_ERR(omap->uhh_base)) in usbhs_omap_probe()
572 return PTR_ERR(omap->uhh_base); in usbhs_omap_probe()
574 omap->pdata = pdata; in usbhs_omap_probe()
584 omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); in usbhs_omap_probe()
586 /* we need to call runtime suspend before we update omap->nports in usbhs_omap_probe()
595 if (pdata->nports) { in usbhs_omap_probe()
596 omap->nports = pdata->nports; in usbhs_omap_probe()
598 switch (omap->usbhs_rev) { in usbhs_omap_probe()
600 omap->nports = 3; in usbhs_omap_probe()
603 omap->nports = 2; in usbhs_omap_probe()
606 omap->nports = OMAP3_HS_USB_PORTS; in usbhs_omap_probe()
608 "USB HOST Rev:0x%x not recognized, assuming %d ports\n", in usbhs_omap_probe()
609 omap->usbhs_rev, omap->nports); in usbhs_omap_probe()
612 pdata->nports = omap->nports; in usbhs_omap_probe()
615 i = sizeof(struct clk *) * omap->nports; in usbhs_omap_probe()
616 omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL); in usbhs_omap_probe()
617 omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL); in usbhs_omap_probe()
618 omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL); in usbhs_omap_probe()
620 if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) { in usbhs_omap_probe()
622 ret = -ENOMEM; in usbhs_omap_probe()
627 omap->ehci_logic_fck = ERR_PTR(-ENODEV); in usbhs_omap_probe()
628 omap->init_60m_fclk = ERR_PTR(-ENODEV); in usbhs_omap_probe()
629 omap->utmi_p1_gfclk = ERR_PTR(-ENODEV); in usbhs_omap_probe()
630 omap->utmi_p2_gfclk = ERR_PTR(-ENODEV); in usbhs_omap_probe()
631 omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV); in usbhs_omap_probe()
632 omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV); in usbhs_omap_probe()
634 for (i = 0; i < omap->nports; i++) { in usbhs_omap_probe()
635 omap->utmi_clk[i] = ERR_PTR(-ENODEV); in usbhs_omap_probe()
636 omap->hsic480m_clk[i] = ERR_PTR(-ENODEV); in usbhs_omap_probe()
637 omap->hsic60m_clk[i] = ERR_PTR(-ENODEV); in usbhs_omap_probe()
641 if (omap->usbhs_rev == OMAP_USBHS_REV1) { in usbhs_omap_probe()
643 for (i = 0; i < omap->nports; i++) { in usbhs_omap_probe()
644 if (is_ehci_phy_mode(pdata->port_mode[i]) || in usbhs_omap_probe()
645 is_ehci_tll_mode(pdata->port_mode[i]) || in usbhs_omap_probe()
646 is_ehci_hsic_mode(pdata->port_mode[i])) in usbhs_omap_probe()
652 omap->ehci_logic_fck = devm_clk_get(dev, in usbhs_omap_probe()
654 if (IS_ERR(omap->ehci_logic_fck)) { in usbhs_omap_probe()
655 ret = PTR_ERR(omap->ehci_logic_fck); in usbhs_omap_probe()
665 omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk"); in usbhs_omap_probe()
666 if (IS_ERR(omap->utmi_p1_gfclk)) { in usbhs_omap_probe()
667 ret = PTR_ERR(omap->utmi_p1_gfclk); in usbhs_omap_probe()
672 omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk"); in usbhs_omap_probe()
673 if (IS_ERR(omap->utmi_p2_gfclk)) { in usbhs_omap_probe()
674 ret = PTR_ERR(omap->utmi_p2_gfclk); in usbhs_omap_probe()
679 omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1"); in usbhs_omap_probe()
680 if (IS_ERR(omap->xclk60mhsp1_ck)) { in usbhs_omap_probe()
681 ret = PTR_ERR(omap->xclk60mhsp1_ck); in usbhs_omap_probe()
686 omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2"); in usbhs_omap_probe()
687 if (IS_ERR(omap->xclk60mhsp2_ck)) { in usbhs_omap_probe()
688 ret = PTR_ERR(omap->xclk60mhsp2_ck); in usbhs_omap_probe()
693 omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int"); in usbhs_omap_probe()
694 if (IS_ERR(omap->init_60m_fclk)) { in usbhs_omap_probe()
695 ret = PTR_ERR(omap->init_60m_fclk); in usbhs_omap_probe()
700 for (i = 0; i < omap->nports; i++) { in usbhs_omap_probe()
711 omap->utmi_clk[i] = devm_clk_get(dev, clkname); in usbhs_omap_probe()
712 if (IS_ERR(omap->utmi_clk[i])) { in usbhs_omap_probe()
713 ret = PTR_ERR(omap->utmi_clk[i]); in usbhs_omap_probe()
721 omap->hsic480m_clk[i] = devm_clk_get(dev, clkname); in usbhs_omap_probe()
722 if (IS_ERR(omap->hsic480m_clk[i])) { in usbhs_omap_probe()
723 ret = PTR_ERR(omap->hsic480m_clk[i]); in usbhs_omap_probe()
731 omap->hsic60m_clk[i] = devm_clk_get(dev, clkname); in usbhs_omap_probe()
732 if (IS_ERR(omap->hsic60m_clk[i])) { in usbhs_omap_probe()
733 ret = PTR_ERR(omap->hsic60m_clk[i]); in usbhs_omap_probe()
740 if (is_ehci_phy_mode(pdata->port_mode[0])) { in usbhs_omap_probe()
741 ret = clk_set_parent(omap->utmi_p1_gfclk, in usbhs_omap_probe()
742 omap->xclk60mhsp1_ck); in usbhs_omap_probe()
748 } else if (is_ehci_tll_mode(pdata->port_mode[0])) { in usbhs_omap_probe()
749 ret = clk_set_parent(omap->utmi_p1_gfclk, in usbhs_omap_probe()
750 omap->init_60m_fclk); in usbhs_omap_probe()
758 if (is_ehci_phy_mode(pdata->port_mode[1])) { in usbhs_omap_probe()
759 ret = clk_set_parent(omap->utmi_p2_gfclk, in usbhs_omap_probe()
760 omap->xclk60mhsp2_ck); in usbhs_omap_probe()
766 } else if (is_ehci_tll_mode(pdata->port_mode[1])) { in usbhs_omap_probe()
767 ret = clk_set_parent(omap->utmi_p2_gfclk, in usbhs_omap_probe()
768 omap->init_60m_fclk); in usbhs_omap_probe()
779 if (dev->of_node) { in usbhs_omap_probe()
780 ret = of_platform_populate(dev->of_node, in usbhs_omap_probe()
813 * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
814 * @pdev: USB Host Controller being removed
820 pm_runtime_disable(&pdev->dev); in usbhs_omap_remove()
823 device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child); in usbhs_omap_remove()
832 { .compatible = "ti,usbhs-host" },
852 MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
860 * init before ehci and ohci drivers;
862 * the omap ehci and ohci probe functions are called.
864 * usb tll driver