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:
Many thanks for any inputs.
Andy
已解决! 转到解答。
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
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.
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
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
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