aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmanuele Ghidoli <[email protected]>2024-09-05 08:53:28 +0200
committerGreg Kroah-Hartman <[email protected]>2024-09-11 15:35:11 +0200
commit77e85107a7717ecb755cf77a2752a2aadd28c4e3 (patch)
tree772cb3ffa7be822d2a95dad6fde3b5bb7e5f8a69
parent7793472be315c5bddbb5cabb55e61ea9a7dca755 (diff)
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 <[email protected]> Signed-off-by: Parth Pancholi <[email protected]> Reviewed-by: Heikki Krogerus <[email protected]> Reviewed-by: Francesco Dolcini <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index a2651a2a7f2e..ed32583829be 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -707,10 +707,13 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
{
u16 status;
int ret;
+ int irq_ret;
unsigned int raw;
tcpci_read16(tcpci, TCPC_ALERT, &status);
+ irq_ret = status & tcpci->alert_mask;
+process_status:
/*
* Clear alert status for everything except RX_STATUS, which shouldn't
* be cleared until we have successfully retrieved message.
@@ -783,7 +786,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
else if (status & TCPC_ALERT_TX_FAILED)
tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED);
- return IRQ_RETVAL(status & tcpci->alert_mask);
+ tcpci_read16(tcpci, TCPC_ALERT, &status);
+
+ if (status & tcpci->alert_mask)
+ goto process_status;
+
+ return IRQ_RETVAL(irq_ret);
}
EXPORT_SYMBOL_GPL(tcpci_irq);
@@ -915,20 +923,22 @@ static int tcpci_probe(struct i2c_client *client)
chip->data.set_orientation = err;
- chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
- if (IS_ERR(chip->tcpci))
- return PTR_ERR(chip->tcpci);
-
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
_tcpci_irq,
- IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ IRQF_SHARED | IRQF_ONESHOT,
dev_name(&client->dev), chip);
- if (err < 0) {
- tcpci_unregister_port(chip->tcpci);
+ if (err < 0)
return err;
- }
- return 0;
+ /*
+ * Disable irq while registering port. If irq is configured as an edge
+ * irq this allow to keep track and process the irq as soon as it is enabled.
+ */
+ disable_irq(client->irq);
+ chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
+ enable_irq(client->irq);
+
+ return PTR_ERR_OR_ZERO(chip->tcpci);
}
static void tcpci_remove(struct i2c_client *client)