Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: xhci: tegra: Support USB wakeup function for Tegra234

When the system is suspended, USB hot-plugging/unplugging can trigger
wake events of the Tegra USB host controller.
Enable support for USB wake-up events by parsing device-tree to see if
the interrupts for the wake-up events are present and if so configure
those interrupts. Note that if wake-up events are not present, still
allow the USB host controller to probe as normal.

Signed-off-by: Haotien Hsu <haotienh@nvidia.com>
Link: https://lore.kernel.org/r/20250811074558.1062048-5-haotienh@nvidia.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Haotien Hsu and committed by
Greg Kroah-Hartman
5df186e2 7bf11585

+80 -2
+80 -2
drivers/usb/host/xhci-tegra.c
··· 155 155 #define FW_IOCTL_TYPE_SHIFT 24 156 156 #define FW_IOCTL_CFGTBL_READ 17 157 157 158 + #define WAKE_IRQ_START_INDEX 2 159 + 158 160 struct tegra_xusb_fw_header { 159 161 __le32 boot_loadaddr_in_imem; 160 162 __le32 boot_codedfi_offset; ··· 230 228 unsigned int num_supplies; 231 229 const struct tegra_xusb_phy_type *phy_types; 232 230 unsigned int num_types; 231 + unsigned int max_num_wakes; 233 232 const struct tegra_xusb_context_soc *context; 234 233 235 234 struct { ··· 266 263 int xhci_irq; 267 264 int mbox_irq; 268 265 int padctl_irq; 266 + int *wake_irqs; 269 267 270 268 void __iomem *ipfs_base; 271 269 void __iomem *fpci_base; ··· 317 313 bool suspended; 318 314 struct tegra_xusb_context context; 319 315 u8 lp0_utmi_pad_mask; 316 + int num_wakes; 320 317 }; 321 318 322 319 static struct hc_driver __read_mostly tegra_xhci_hc_driver; ··· 1542 1537 otg_set_host(tegra->usbphy[i]->otg, NULL); 1543 1538 } 1544 1539 1540 + static int tegra_xusb_setup_wakeup(struct platform_device *pdev, struct tegra_xusb *tegra) 1541 + { 1542 + unsigned int i; 1543 + 1544 + if (tegra->soc->max_num_wakes == 0) 1545 + return 0; 1546 + 1547 + tegra->wake_irqs = devm_kcalloc(tegra->dev, 1548 + tegra->soc->max_num_wakes, 1549 + sizeof(*tegra->wake_irqs), GFP_KERNEL); 1550 + if (!tegra->wake_irqs) 1551 + return -ENOMEM; 1552 + 1553 + /* 1554 + * USB wake events are independent of each other, so it is not necessary for a platform 1555 + * to utilize all wake-up events supported for a given device. The USB host can operate 1556 + * even if wake-up events are not defined or fail to be configured. Therefore, we only 1557 + * return critical errors, such as -ENOMEM. 1558 + */ 1559 + for (i = 0; i < tegra->soc->max_num_wakes; i++) { 1560 + struct irq_data *data; 1561 + 1562 + tegra->wake_irqs[i] = platform_get_irq(pdev, i + WAKE_IRQ_START_INDEX); 1563 + if (tegra->wake_irqs[i] < 0) 1564 + break; 1565 + 1566 + data = irq_get_irq_data(tegra->wake_irqs[i]); 1567 + if (!data) { 1568 + dev_warn(tegra->dev, "get wake event %d irq data fail\n", i); 1569 + irq_dispose_mapping(tegra->wake_irqs[i]); 1570 + break; 1571 + } 1572 + 1573 + irq_set_irq_type(tegra->wake_irqs[i], irqd_get_trigger_type(data)); 1574 + } 1575 + 1576 + tegra->num_wakes = i; 1577 + dev_dbg(tegra->dev, "setup %d wake events\n", tegra->num_wakes); 1578 + 1579 + return 0; 1580 + } 1581 + 1582 + static void tegra_xusb_dispose_wake(struct tegra_xusb *tegra) 1583 + { 1584 + unsigned int i; 1585 + 1586 + for (i = 0; i < tegra->num_wakes; i++) 1587 + irq_dispose_mapping(tegra->wake_irqs[i]); 1588 + 1589 + tegra->num_wakes = 0; 1590 + } 1591 + 1545 1592 static int tegra_xusb_probe(struct platform_device *pdev) 1546 1593 { 1547 1594 struct tegra_xusb *tegra; ··· 1644 1587 if (tegra->mbox_irq < 0) 1645 1588 return tegra->mbox_irq; 1646 1589 1590 + err = tegra_xusb_setup_wakeup(pdev, tegra); 1591 + if (err) 1592 + return err; 1593 + 1647 1594 tegra->padctl = tegra_xusb_padctl_get(&pdev->dev); 1648 - if (IS_ERR(tegra->padctl)) 1649 - return PTR_ERR(tegra->padctl); 1595 + if (IS_ERR(tegra->padctl)) { 1596 + err = PTR_ERR(tegra->padctl); 1597 + goto dispose_wake; 1598 + } 1650 1599 1651 1600 np = of_parse_phandle(pdev->dev.of_node, "nvidia,xusb-padctl", 0); 1652 1601 if (!np) { ··· 1976 1913 put_padctl: 1977 1914 of_node_put(np); 1978 1915 tegra_xusb_padctl_put(tegra->padctl); 1916 + dispose_wake: 1917 + tegra_xusb_dispose_wake(tegra); 1979 1918 return err; 1980 1919 } 1981 1920 ··· 2009 1944 2010 1945 if (tegra->padctl_irq) 2011 1946 pm_runtime_disable(&pdev->dev); 1947 + 1948 + tegra_xusb_dispose_wake(tegra); 2012 1949 2013 1950 pm_runtime_put(&pdev->dev); 2014 1951 ··· 2422 2355 pm_runtime_disable(dev); 2423 2356 2424 2357 if (device_may_wakeup(dev)) { 2358 + unsigned int i; 2359 + 2425 2360 if (enable_irq_wake(tegra->padctl_irq)) 2426 2361 dev_err(dev, "failed to enable padctl wakes\n"); 2362 + 2363 + for (i = 0; i < tegra->num_wakes; i++) 2364 + enable_irq_wake(tegra->wake_irqs[i]); 2427 2365 } 2428 2366 } 2429 2367 ··· 2456 2384 } 2457 2385 2458 2386 if (device_may_wakeup(dev)) { 2387 + unsigned int i; 2388 + 2459 2389 if (disable_irq_wake(tegra->padctl_irq)) 2460 2390 dev_err(dev, "failed to disable padctl wakes\n"); 2391 + 2392 + for (i = 0; i < tegra->num_wakes; i++) 2393 + disable_irq_wake(tegra->wake_irqs[i]); 2461 2394 } 2462 2395 tegra->suspended = false; 2463 2396 mutex_unlock(&tegra->lock); ··· 2713 2636 .num_supplies = ARRAY_SIZE(tegra194_supply_names), 2714 2637 .phy_types = tegra194_phy_types, 2715 2638 .num_types = ARRAY_SIZE(tegra194_phy_types), 2639 + .max_num_wakes = 7, 2716 2640 .context = &tegra186_xusb_context, 2717 2641 .ports = { 2718 2642 .usb3 = { .offset = 0, .count = 4, },