[PATCH v5 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk

Vincent Mailhol mailhol at kernel.org
Tue Jun 9 12:51:13 PDT 2026


On 09/06/2026 at 16:29, Ciprian Costea wrote:
> From: Ciprian Marian Costea <ciprianmarian.costea at oss.nxp.com>
> 
> Introduce FLEXCAN_QUIRK_IRQ_BERR quirk to handle hardware integration
> where the FlexCAN module has a dedicated interrupt line for signaling
> bus errors and device state changes.
> 
> This adds the flexcan_irq_esr() handler which composes
> flexcan_do_state() and flexcan_do_berr() to handle platforms where
> these events share a single IRQ line.
> 
> Also extend flexcan_chip_interrupts_enable() to disable/enable the
> new IRQ line during IMASK register writes.
> 
> This is required for NXP S32N79 SoC support.
> 
> Co-developed-by: Larisa Grigore <larisa.grigore at nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore at nxp.com>
> Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea at oss.nxp.com>
> Reviewed-and-tested-by: Haibo Chen <haibo.chen at nxp.com>
> Tested-by: Enric Balletbo i Serra <eballetb at redhat.com>

Reviewed-by: Vincent Mailhol <mailhol at kernel.org>

> ---
>  drivers/net/can/flexcan/flexcan-core.c | 54 +++++++++++++++++++++-----
>  drivers/net/can/flexcan/flexcan.h      |  2 +
>  2 files changed, 47 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> index 0ed838f0719a..adf3af57fb0a 100644
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
> @@ -1300,6 +1300,22 @@ static irqreturn_t flexcan_irq_boff(int irq, void *dev_id)
>  	return handled;
>  }
>  
> +/* Combined bus error and state change IRQ handler */
> +static irqreturn_t flexcan_irq_esr(int irq, void *dev_id)
> +{
> +	struct net_device *dev = dev_id;
> +	struct flexcan_priv *priv = netdev_priv(dev);
> +	irqreturn_t handled;
> +
> +	handled = flexcan_do_state(dev);
> +	handled |= flexcan_do_berr(dev);
> +
> +	if (handled)
> +		can_rx_offload_irq_finish(&priv->offload);
> +
> +	return handled;
> +}
> +
>  static void flexcan_set_bittiming_ctrl(const struct net_device *dev)
>  {
>  	const struct flexcan_priv *priv = netdev_priv(dev);
> @@ -1540,10 +1556,10 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
>  	u64 reg_imask;
>  
>  	disable_irq(dev->irq);
> -	if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
> +	if (quirks & FLEXCAN_QUIRK_NR_IRQ_3)
>  		disable_irq(priv->irq_boff);
> +	if (quirks & (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
>  		disable_irq(priv->irq_err);
> -	}
>  	if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
>  		disable_irq(priv->irq_secondary_mb);
>  
> @@ -1554,10 +1570,10 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
>  	enable_irq(dev->irq);
>  	if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
>  		enable_irq(priv->irq_secondary_mb);
> -	if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
> -		enable_irq(priv->irq_boff);
> +	if (quirks & (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
>  		enable_irq(priv->irq_err);
> -	}
> +	if (quirks & FLEXCAN_QUIRK_NR_IRQ_3)
> +		enable_irq(priv->irq_boff);
>  }
>  
>  static void flexcan_chip_interrupts_disable(const struct net_device *dev)
> @@ -1881,7 +1897,8 @@ static int flexcan_open(struct net_device *dev)
>  
>  	can_rx_offload_enable(&priv->offload);
>  
> -	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
> +	if (priv->devtype_data.quirks &
> +			(FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
>  		err = request_irq(dev->irq, flexcan_irq_mb,
>  				  IRQF_SHARED, dev->name, dev);
>  	else
> @@ -1902,6 +1919,13 @@ static int flexcan_open(struct net_device *dev)
>  			goto out_free_irq_boff;
>  	}
>  
> +	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
> +		err = request_irq(priv->irq_err,
> +				  flexcan_irq_esr, IRQF_SHARED, dev->name, dev);
> +		if (err)
> +			goto out_free_irq_boff;
> +	}
> +
>  	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
>  		err = request_irq(priv->irq_secondary_mb,
>  				  flexcan_irq_mb, IRQF_SHARED, dev->name, dev);
> @@ -1916,7 +1940,8 @@ static int flexcan_open(struct net_device *dev)
>  	return 0;
>  
>   out_free_irq_err:
> -	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
> +	if (priv->devtype_data.quirks &
> +			(FLEXCAN_QUIRK_IRQ_BERR | FLEXCAN_QUIRK_NR_IRQ_3))
>  		free_irq(priv->irq_err, dev);
>   out_free_irq_boff:
>  	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
> @@ -1948,10 +1973,12 @@ static int flexcan_close(struct net_device *dev)
>  	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
>  		free_irq(priv->irq_secondary_mb, dev);
>  
> -	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
> +	if (priv->devtype_data.quirks &
> +			(FLEXCAN_QUIRK_IRQ_BERR | FLEXCAN_QUIRK_NR_IRQ_3))
>  		free_irq(priv->irq_err, dev);
> +
> +	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
>  		free_irq(priv->irq_boff, dev);
> -	}
>  
>  	free_irq(dev->irq, dev);
>  	can_rx_offload_disable(&priv->offload);
> @@ -2338,12 +2365,21 @@ static int flexcan_probe(struct platform_device *pdev)
>  	if (transceiver)
>  		priv->can.bitrate_max = transceiver->attrs.max_link_rate;
>  
> +	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
> +		priv->irq_err = platform_get_irq_byname(pdev, "berr");
> +		if (priv->irq_err < 0) {
> +			err = priv->irq_err;
> +			goto failed_platform_get_irq;
> +		}
> +	}
> +
>  	if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
>  		priv->irq_boff = platform_get_irq(pdev, 1);
>  		if (priv->irq_boff < 0) {
>  			err = priv->irq_boff;
>  			goto failed_platform_get_irq;
>  		}
> +

Nitpick: you shouldn't have unrelated changes, like this newline
addition, in you patches.

@Marc, do you mind removing this while applying?

>  		priv->irq_err = platform_get_irq(pdev, 2);
>  		if (priv->irq_err < 0) {
>  			err = priv->irq_err;
> diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
> index 16692a2502eb..bbb1a8dd4777 100644
> --- a/drivers/net/can/flexcan/flexcan.h
> +++ b/drivers/net/can/flexcan/flexcan.h
> @@ -74,6 +74,8 @@
>   * both need to have an interrupt handler registered.
>   */
>  #define FLEXCAN_QUIRK_SECONDARY_MB_IRQ	BIT(18)
> +/* Setup dedicated bus error and state change IRQ */
> +#define FLEXCAN_QUIRK_IRQ_BERR	BIT(19)
>  
>  struct flexcan_devtype_data {
>  	u32 quirks;		/* quirks needed for different IP cores */


Yours sincerely,
Vincent Mailhol




More information about the linux-arm-kernel mailing list