i.MX8 PWM interrupt

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX8 PWM interrupt

Jump to solution
255 Views
andrej_valek
Contributor IV

Dear community!

I would like to ask you a question whether is possible to use PWM interrupt on i.MX8mp. I wanted to create a custom driver and be notified when PWM output is going down (FALLING_EDGE). Is it even possible to be achieve it, or not just by design?

In the DTB

// imx8mp.dtsi
pwm1: pwm@30660000 {
	compatible = "fsl,imx8mp-pwm", "fsl,imx27-pwm";
	reg = <0x30660000 0x10000>;
	interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clk IMX8MP_CLK_PWM1_ROOT>,
		 <&clk IMX8MP_CLK_PWM1_ROOT>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
	status = "disabled";
};

// imx8mp-my-device.dts
cam_trigger: cam-trigger {
	compatible = "company,cam-trigger";
	pwms = <&pwm1 0 8333333 0>;
	interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
	status = "okay";
};

&iomuxc {
	pinctrl-names = "default";

	pinctrl_pwm1: pwm1grp {
		fsl,pins = <
			MX8MP_IOMUXC_GPIO1_IO01__PWM1_OUT	0x116
		>;
	};
};

&pwm1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pwm1>;
	status = "okay";
};

is a <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH> entry. So I registered to this interrupt via devm_request_irq and verified it in /proc/interrupt, that registration was successful. (Even if I wanted to have a falling edge, I used just something.) But the interrupt didn't happen.

After deeper analysis I realized, that i.MX8 has an PWMIR register, but the handling is missing in pwm-imx27 driver. I guess that would be the reason why... .

Now the questions are:

  • Is my meaning true?
    • How hard is to implement such a mechanism into driver.
      • According to DS, just a capture should be enough
  • What the GIC_SPI 81 is meaning then? Does it mean that is it there just "for fun" ?
  • Is there an another way how to be notified when interrupt happens?
    • HW modifications like routing the output pin to other input GPIO are not possible

Many thanks for any inputs.
Andy

Tags (2)
0 Kudos
1 Solution
99 Views
andrej_valek
Contributor IV

Ok, I will answer it by myself. Here are the modifications which I had to do to make the interrupts working.

#define MX3_PWMIR			0x08    /* PWM Interrupt Register */

#define MX3_PWMIR_CIE	BIT(2)
#define MX3_PWMIR_RIE	BIT(1)
#define MX3_PWMIR_FIE	BIT(0)

struct pwm_imx27_chip {
...
	int irq;

if (state->enabled) {
	cr |= MX3_PWMCR_EN;
	/* enable interrupts */
	writel(MX3_PWMIR_CIE | MX3_PWMIR_RIE, imx->mmio_base + MX3_PWMIR);
	} else {
	/* disable interrupts */
	writel(0, imx->mmio_base + MX3_PWMIR);
}


static irqreturn_t imx_pwm_interrupt(int irq, void *data)
{
	struct pwm_imx27_chip *imx = data;
	unsigned long flags;
	u32 pwmsr;

	spin_lock_irqsave(&imx->lock, flags);

	pwmsr = readl(imx->mmio_base + MX3_PWMSR);

	/* handle flags separately, while multiple of them could happen */
	if (pwmsr && (~MX3_PWMSR_CMP)) pwmsr |= MX3_PWMSR_CMP;
	if (pwmsr && (~MX3_PWMSR_ROV)) pwmsr |= MX3_PWMSR_ROV;

	/* ack interrupt flags */
	writel(pwmsr, imx->mmio_base + MX3_PWMSR);
	
	spin_unlock_irqrestore(&imx->lock, flags);

	return IRQ_HANDLED;
}

// probe...
	imx->irq = platform_get_irq(pdev, 0);
	if (imx->irq < 0) {
		dev_err(&pdev->dev, "Failed to get IRQ\n");
		return imx->irq;
	}

	ret = devm_request_irq(&pdev->dev, imx->irq, imx_pwm_interrupt, IRQF_TRIGGER_HIGH,
			       pdev->name, imx);
	if (ret < 0) {
		dev_err(&pdev->dev, "Failed to request IRQ\n");
		return ret;
	}

 Maybe it will help to someone else too.

Regards,
Andy

View solution in original post

0 Kudos
5 Replies
234 Views
Alejandro_Salas
NXP TechSupport
NXP TechSupport

Hello @andrej_valek 

 

The IRQ 81 is Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line for PWM1.

 

Maybe for your use case you can get the PWM signal to any GPIO and config the Falling Edge to get the interruption.

 

Best reagrds,

Salas.

0 Kudos
216 Views
andrej_valek
Contributor IV

Hello @Alejandro_Salas 

The IRQ 81 is Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line for PWM1.

Yes, but are you sure, that will it work even if there is no PWMIR register handling? Or is it reading the bits done somehow differently?

you can get the PWM signal to any GPIO

How can I do that without modifying the HW? Is there a way to register for GPIO interrupt even if the pin is set to MX8MP_IOMUXC_GPIO1_IO01__PWM1_OUT which not a GPIO, but routed as a PWM. So does it mean, it will be handled somehow internally? If yes, could you please write me an example how to do it?

Thank you,
Andy

0 Kudos
201 Views
Alejandro_Salas
NXP TechSupport
NXP TechSupport

Hello,

The PWMx_PWMIR register only supports Compare Interrupt, Roll-over Interrupt and FIFO Empty Interrupt.

 

For GPIO you need to do a hardware modifications.

 

Best regards,

Salas.

0 Kudos
197 Views
andrej_valek
Contributor IV

Hello again,

The PWMx_PWMIR register only supports Compare Interrupt, Roll-over Interrupt and FIFO Empty Interrupt.

I know that :). But then how to enable the notification for "Compare interrupt"? Does it mean, that I have to just set the CIE bit in PWMx_PWMIR register? Will be the interrupt on line 81 called automatically? How/when will be CMP bit cleared?

Regards,
Andy

0 Kudos
100 Views
andrej_valek
Contributor IV

Ok, I will answer it by myself. Here are the modifications which I had to do to make the interrupts working.

#define MX3_PWMIR			0x08    /* PWM Interrupt Register */

#define MX3_PWMIR_CIE	BIT(2)
#define MX3_PWMIR_RIE	BIT(1)
#define MX3_PWMIR_FIE	BIT(0)

struct pwm_imx27_chip {
...
	int irq;

if (state->enabled) {
	cr |= MX3_PWMCR_EN;
	/* enable interrupts */
	writel(MX3_PWMIR_CIE | MX3_PWMIR_RIE, imx->mmio_base + MX3_PWMIR);
	} else {
	/* disable interrupts */
	writel(0, imx->mmio_base + MX3_PWMIR);
}


static irqreturn_t imx_pwm_interrupt(int irq, void *data)
{
	struct pwm_imx27_chip *imx = data;
	unsigned long flags;
	u32 pwmsr;

	spin_lock_irqsave(&imx->lock, flags);

	pwmsr = readl(imx->mmio_base + MX3_PWMSR);

	/* handle flags separately, while multiple of them could happen */
	if (pwmsr && (~MX3_PWMSR_CMP)) pwmsr |= MX3_PWMSR_CMP;
	if (pwmsr && (~MX3_PWMSR_ROV)) pwmsr |= MX3_PWMSR_ROV;

	/* ack interrupt flags */
	writel(pwmsr, imx->mmio_base + MX3_PWMSR);
	
	spin_unlock_irqrestore(&imx->lock, flags);

	return IRQ_HANDLED;
}

// probe...
	imx->irq = platform_get_irq(pdev, 0);
	if (imx->irq < 0) {
		dev_err(&pdev->dev, "Failed to get IRQ\n");
		return imx->irq;
	}

	ret = devm_request_irq(&pdev->dev, imx->irq, imx_pwm_interrupt, IRQF_TRIGGER_HIGH,
			       pdev->name, imx);
	if (ret < 0) {
		dev_err(&pdev->dev, "Failed to request IRQ\n");
		return ret;
	}

 Maybe it will help to someone else too.

Regards,
Andy

0 Kudos