On Tue, 16 Feb 2021 09:13:56 +0100 Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> wrote: > Add simple IRQ or GPIO base event counter. This device is used to measure > rotation speed of some agricultural devices, so no high frequency on the > counter pin is expected. > > The maximal measurement frequency depends on the CPU and system load. On > the idle iMX6S I was able to measure up to 20kHz without count drops. > > Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> > Reviewed-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> A FYI note inline. Driver looks good to me. Jonathan > --- > MAINTAINERS | 7 + > drivers/counter/Kconfig | 10 ++ > drivers/counter/Makefile | 1 + > drivers/counter/interrupt-cnt.c | 249 ++++++++++++++++++++++++++++++++ > 4 files changed, 267 insertions(+) > create mode 100644 drivers/counter/interrupt-cnt.c > ... > +static int interrupt_cnt_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct interrupt_cnt_priv *priv; > + int ret; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + priv->irq = platform_get_irq_optional(pdev, 0); > + if (priv->irq == -ENXIO) > + priv->irq = 0; > + else if (priv->irq < 0) > + return dev_err_probe(dev, priv->irq, "failed to get IRQ\n"); > + > + priv->gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_IN); > + if (IS_ERR(priv->gpio)) > + return dev_err_probe(dev, PTR_ERR(priv->gpio), "failed to get GPIO\n"); > + > + if (!priv->irq && !priv->gpio) { > + dev_err(dev, "IRQ and GPIO are not found. At least one source should be provided\n"); > + return -ENODEV; > + } > + > + if (!priv->irq) { > + int irq = gpiod_to_irq(priv->gpio); > + > + if (irq < 0) > + return dev_err_probe(dev, irq, "failed to get IRQ from GPIO\n"); > + > + priv->irq = irq; > + } > + > + priv->counter.priv = priv; > + priv->counter.name = dev_name(dev); > + priv->counter.parent = dev; > + priv->counter.ops = &interrupt_cnt_ops; > + priv->counter.counts = interrupt_cnts; > + priv->counter.num_counts = ARRAY_SIZE(interrupt_cnts); > + priv->counter.signals = interrupt_cnt_signals; > + priv->counter.num_signals = priv->gpio ? > + ARRAY_SIZE(interrupt_cnt_signals) : 0; > + > + irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); Just as a side note, there is a series that cleans up this case, though no idea if it will make the merge window or not. https://lore.kernel.org/linux-input/aefbe49321b845c98e505518314a93cc@xxxxxxxxxxxxx/ If it does we can tidy this up then. > + ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr, > + IRQF_TRIGGER_RISING | IRQF_NO_THREAD, > + INTERRUPT_CNT_NAME, priv); > + if (ret) > + return ret; > + > + return devm_counter_register(dev, &priv->counter); > +} > + ...