/* Values of UHH_REVISION - Note: these are not given in the TRM */ #define OMAP_USBHS_REV1 0x00000010 /* OMAP3 */ #define OMAP_USBHS_REV2 0x50700100 /* OMAP4 */
if (!ehci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
ret = -ENOMEM; goto err_end;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci"); if (!res) {
dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n");
ret = -ENODEV; goto err_ehci;
}
resources[0] = *res;
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq"); if (!res) {
dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n");
ret = -ENODEV; goto err_ehci;
}
resources[1] = *res;
ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata, sizeof(*pdata), dev); if (!ohci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
ret = -ENOMEM; goto err_ehci;
}
return0;
err_ehci:
platform_device_unregister(ehci);
err_end: return ret;
}
staticbool is_ohci_port(enum usbhs_omap_port_mode pmode)
{ switch (pmode) { case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: returntrue;
default: returnfalse;
}
}
staticint usbhs_runtime_resume(struct device *dev)
{ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = omap->pdata; int i, r;
dev_dbg(dev, "usbhs_runtime_resume\n");
omap_tll_enable(pdata);
if (!IS_ERR(omap->ehci_logic_fck))
clk_prepare_enable(omap->ehci_logic_fck);
for (i = 0; i < omap->nports; i++) { switch (pdata->port_mode[i]) { case OMAP_EHCI_PORT_MODE_HSIC: if (!IS_ERR(omap->hsic60m_clk[i])) {
r = clk_prepare_enable(omap->hsic60m_clk[i]); if (r) {
dev_err(dev, "Can't enable port %d hsic60m clk:%d\n",
i, r);
}
}
if (!IS_ERR(omap->hsic480m_clk[i])) {
r = clk_prepare_enable(omap->hsic480m_clk[i]); if (r) {
dev_err(dev, "Can't enable port %d hsic480m clk:%d\n",
i, r);
}
}
fallthrough; /* as HSIC mode needs utmi_clk */
case OMAP_EHCI_PORT_MODE_TLL: if (!IS_ERR(omap->utmi_clk[i])) {
r = clk_prepare_enable(omap->utmi_clk[i]); if (r) {
dev_err(dev, "Can't enable port %d clk : %d\n",
i, r);
}
} break; default: break;
}
}
for (i = 0; i < omap->nports; i++) { switch (pdata->port_mode[i]) { case OMAP_EHCI_PORT_MODE_HSIC: if (!IS_ERR(omap->hsic60m_clk[i]))
clk_disable_unprepare(omap->hsic60m_clk[i]);
if (!IS_ERR(omap->hsic480m_clk[i]))
clk_disable_unprepare(omap->hsic480m_clk[i]);
fallthrough; /* as utmi_clks were used in HSIC mode */
case OMAP_EHCI_PORT_MODE_TLL: if (!IS_ERR(omap->utmi_clk[i]))
clk_disable_unprepare(omap->utmi_clk[i]); break; default: break;
}
}
if (!IS_ERR(omap->ehci_logic_fck))
clk_disable_unprepare(omap->ehci_logic_fck);
for (i = 0; i < omap->nports; i++) { switch (pdata->port_mode[i]) { case OMAP_USBHS_PORT_MODE_UNUSED:
reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i); break; case OMAP_EHCI_PORT_MODE_PHY: if (pdata->single_ulpi_bypass) break;
if (i == 0)
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else
reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
<< (i-1)); break; default: if (pdata->single_ulpi_bypass) break;
if (i == 0)
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
<< (i-1); break;
}
}
if (pdata->single_ulpi_bypass) { /* bypass ULPI only if none of the ports use PHY mode */
reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
for (i = 0; i < omap->nports; i++) { if (is_ehci_phy_mode(pdata->port_mode[i])) {
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; break;
}
}
}
ret = of_property_read_u32(node, "num-ports", &pdata->nports); if (ret)
pdata->nports = 0;
if (pdata->nports > OMAP3_HS_USB_PORTS) {
dev_warn(dev, "Too many num_ports <%d> in device tree. Max %d\n",
pdata->nports, OMAP3_HS_USB_PORTS); return -ENODEV;
}
/* get port modes */ for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { char prop[11]; constchar *mode;
snprintf(prop, sizeof(prop), "port%d-mode", i + 1);
ret = of_property_read_string(node, prop, &mode); if (ret < 0) continue;
/* get 'enum usbhs_omap_port_mode' from port mode string */
ret = match_string(port_modes, ARRAY_SIZE(port_modes), mode); if (ret < 0) {
dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n",
i, mode); return -ENODEV;
}
if (dev->of_node) { /* For DT boot we populate platform data from OF node */
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM;
ret = usbhs_omap_get_dt_pdata(dev, pdata); if (ret) return ret;
dev->platform_data = pdata;
}
if (!pdata) {
dev_err(dev, "Missing platform data\n"); return -ENODEV;
}
if (pdata->nports > OMAP3_HS_USB_PORTS) {
dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d\n",
pdata->nports, OMAP3_HS_USB_PORTS); return -ENODEV;
}
i = sizeof(struct clk *) * omap->nports;
omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
dev_err(dev, "Memory allocation failed\n");
ret = -ENOMEM; goto err_mem;
}
/* Set all clocks as invalid to begin with */
omap->ehci_logic_fck = ERR_PTR(-ENODEV);
omap->init_60m_fclk = ERR_PTR(-ENODEV);
omap->utmi_p1_gfclk = ERR_PTR(-ENODEV);
omap->utmi_p2_gfclk = ERR_PTR(-ENODEV);
omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV);
omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV);
for (i = 0; i < omap->nports; i++) {
omap->utmi_clk[i] = ERR_PTR(-ENODEV);
omap->hsic480m_clk[i] = ERR_PTR(-ENODEV);
omap->hsic60m_clk[i] = ERR_PTR(-ENODEV);
}
/* for OMAP3 i.e. USBHS REV1 */ if (omap->usbhs_rev == OMAP_USBHS_REV1) {
need_logic_fck = false; for (i = 0; i < omap->nports; i++) { if (is_ehci_phy_mode(pdata->port_mode[i]) ||
is_ehci_tll_mode(pdata->port_mode[i]) ||
is_ehci_hsic_mode(pdata->port_mode[i]))
need_logic_fck |= true;
}
if (need_logic_fck) {
omap->ehci_logic_fck = devm_clk_get(dev, "usbhost_120m_fck"); if (IS_ERR(omap->ehci_logic_fck)) {
ret = PTR_ERR(omap->ehci_logic_fck);
dev_err(dev, "usbhost_120m_fck failed:%d\n",
ret); goto err_mem;
}
} goto initialize;
}
/* for OMAP4+ i.e. USBHS REV2+ */
omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_gfclk)) {
ret = PTR_ERR(omap->utmi_p1_gfclk);
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); goto err_mem;
}
omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk"); if (IS_ERR(omap->utmi_p2_gfclk)) {
ret = PTR_ERR(omap->utmi_p2_gfclk);
dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); goto err_mem;
}
omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1"); if (IS_ERR(omap->xclk60mhsp1_ck)) {
ret = PTR_ERR(omap->xclk60mhsp1_ck);
dev_err(dev, "refclk_60m_ext_p1 failed error:%d\n", ret); goto err_mem;
}
omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2"); if (IS_ERR(omap->xclk60mhsp2_ck)) {
ret = PTR_ERR(omap->xclk60mhsp2_ck);
dev_err(dev, "refclk_60m_ext_p2 failed error:%d\n", ret); goto err_mem;
}
omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int"); if (IS_ERR(omap->init_60m_fclk)) {
ret = PTR_ERR(omap->init_60m_fclk);
dev_err(dev, "refclk_60m_int failed error:%d\n", ret); goto err_mem;
}
for (i = 0; i < omap->nports; i++) { char clkname[40];
/* clock names are indexed from 1*/
snprintf(clkname, sizeof(clkname), "usb_host_hs_utmi_p%d_clk", i + 1);
/* If a clock is not found we won't bail out as not all *platformshaveallclocksandwecanfunctionwithout *them
*/
omap->utmi_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->utmi_clk[i])) {
ret = PTR_ERR(omap->utmi_clk[i]);
dev_err(dev, "Failed to get clock : %s : %d\n",
clkname, ret); goto err_mem;
}
snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic480m_p%d_clk", i + 1);
omap->hsic480m_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->hsic480m_clk[i])) {
ret = PTR_ERR(omap->hsic480m_clk[i]);
dev_err(dev, "Failed to get clock : %s : %d\n",
clkname, ret); goto err_mem;
}
snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic60m_p%d_clk", i + 1);
omap->hsic60m_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->hsic60m_clk[i])) {
ret = PTR_ERR(omap->hsic60m_clk[i]);
dev_err(dev, "Failed to get clock : %s : %d\n",
clkname, ret); goto err_mem;
}
}
if (is_ehci_phy_mode(pdata->port_mode[0])) {
ret = clk_set_parent(omap->utmi_p1_gfclk,
omap->xclk60mhsp1_ck); if (ret != 0) {
dev_err(dev, "xclk60mhsp1_ck set parent failed: %d\n",
ret); goto err_mem;
}
} elseif (is_ehci_tll_mode(pdata->port_mode[0])) {
ret = clk_set_parent(omap->utmi_p1_gfclk,
omap->init_60m_fclk); if (ret != 0) {
dev_err(dev, "P0 init_60m_fclk set parent failed: %d\n",
ret); goto err_mem;
}
}
if (is_ehci_phy_mode(pdata->port_mode[1])) {
ret = clk_set_parent(omap->utmi_p2_gfclk,
omap->xclk60mhsp2_ck); if (ret != 0) {
dev_err(dev, "xclk60mhsp2_ck set parent failed: %d\n",
ret); goto err_mem;
}
} elseif (is_ehci_tll_mode(pdata->port_mode[1])) {
ret = clk_set_parent(omap->utmi_p2_gfclk,
omap->init_60m_fclk); if (ret != 0) {
dev_err(dev, "P1 init_60m_fclk set parent failed: %d\n",
ret); goto err_mem;
}
}
initialize:
omap_usbhs_init(dev);
if (dev->of_node) {
ret = of_platform_populate(dev->of_node,
usbhs_child_match_table, NULL, dev);
if (ret) {
dev_err(dev, "Failed to create DT children: %d\n", ret); goto err_mem;
}
} else {
ret = omap_usbhs_alloc_children(pdev); if (ret) {
dev_err(dev, "omap_usbhs_alloc_children failed: %d\n",
ret); goto err_mem;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.