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

usb: typec: tcpci: support edge irq

TCPCI USB PHY - PTN5110 could be used with SOCs that only support
the edge-triggered GPIO interrupts such as TI's K3 device AM69.
Move the interrupt configuration to the firmware which would
allow to accommodate edge triggered interrupts for such SOCs.
In order to support the edge interrupts, register irq line in advance
and keep track of occurrence during port registering.

When the edge interrupts are used, it is observed that some of the
interrupts are missed when tcpci_irq() is serving the current
interrupt. Therefore, check the status register at the end of
tcpci_irq() and re-run the function if the status is not clear
i.e. pending interrupt.

Signed-off-by: Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
Signed-off-by: Parth Pancholi <parth.pancholi@toradex.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>
Link: https://lore.kernel.org/r/20240905065328.7116-1-parth105105@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Emanuele Ghidoli and committed by
Greg Kroah-Hartman
77e85107 7793472b

+20 -10
+20 -10
drivers/usb/typec/tcpm/tcpci.c
··· 707 707 { 708 708 u16 status; 709 709 int ret; 710 + int irq_ret; 710 711 unsigned int raw; 711 712 712 713 tcpci_read16(tcpci, TCPC_ALERT, &status); 714 + irq_ret = status & tcpci->alert_mask; 713 715 716 + process_status: 714 717 /* 715 718 * Clear alert status for everything except RX_STATUS, which shouldn't 716 719 * be cleared until we have successfully retrieved message. ··· 786 783 else if (status & TCPC_ALERT_TX_FAILED) 787 784 tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED); 788 785 789 - return IRQ_RETVAL(status & tcpci->alert_mask); 786 + tcpci_read16(tcpci, TCPC_ALERT, &status); 787 + 788 + if (status & tcpci->alert_mask) 789 + goto process_status; 790 + 791 + return IRQ_RETVAL(irq_ret); 790 792 } 791 793 EXPORT_SYMBOL_GPL(tcpci_irq); 792 794 ··· 923 915 924 916 chip->data.set_orientation = err; 925 917 926 - chip->tcpci = tcpci_register_port(&client->dev, &chip->data); 927 - if (IS_ERR(chip->tcpci)) 928 - return PTR_ERR(chip->tcpci); 929 - 930 918 err = devm_request_threaded_irq(&client->dev, client->irq, NULL, 931 919 _tcpci_irq, 932 - IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, 920 + IRQF_SHARED | IRQF_ONESHOT, 933 921 dev_name(&client->dev), chip); 934 - if (err < 0) { 935 - tcpci_unregister_port(chip->tcpci); 922 + if (err < 0) 936 923 return err; 937 - } 938 924 939 - return 0; 925 + /* 926 + * Disable irq while registering port. If irq is configured as an edge 927 + * irq this allow to keep track and process the irq as soon as it is enabled. 928 + */ 929 + disable_irq(client->irq); 930 + chip->tcpci = tcpci_register_port(&client->dev, &chip->data); 931 + enable_irq(client->irq); 932 + 933 + return PTR_ERR_OR_ZERO(chip->tcpci); 940 934 } 941 935 942 936 static void tcpci_remove(struct i2c_client *client)