Message ID | 20240905065328.7116-1-parth105105@gmail.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 77e85107a7717ecb755cf77a2752a2aadd28c4e3 |
Headers | show |
Series | [v2] usb: typec: tcpci: support edge irq | expand |
On Thu, Sep 05, 2024 at 08:53:28AM +0200, Parth Pancholi wrote: > From: Emanuele Ghidoli <emanuele.ghidoli@toradex.com> > > 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> > --- > v2: Re-enable irq irrespective of tcpci_register_port() return status which was disabled before this call > --- > drivers/usb/typec/tcpm/tcpci.c | 30 ++++++++++++++++++++---------- > 1 file 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) > -- > 2.34.1
On Thu, Sep 05, 2024 at 08:53:28AM +0200, Parth Pancholi wrote: > From: Emanuele Ghidoli <emanuele.ghidoli@toradex.com> > > 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: Francesco Dolcini <francesco.dolcini@toradex.com>
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)