Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

counter: microchip-tcb-capture: Add IRQ handling

Add interrupt servicing to allow userspace to wait for the following:
* Change-of-state caused by external trigger
* Capture of timer value into RA/RB
* Compare to RC register
* Overflow

Signed-off-by: Bence Csókás <csokas.bence@prolan.hu>
Link: https://lore.kernel.org/r/20250306134441.582819-2-csokas.bence@prolan.hu
Signed-off-by: William Breathitt Gray <wbg@kernel.org>

authored by

Bence Csókás and committed by
William Breathitt Gray
e5d58139 c2a75666

+109
+1
MAINTAINERS
··· 15642 15642 L: linux-iio@vger.kernel.org 15643 15643 S: Maintained 15644 15644 F: drivers/counter/microchip-tcb-capture.c 15645 + F: include/uapi/linux/counter/microchip-tcb-capture.h 15645 15646 15646 15647 MICROCHIP USB251XB DRIVER 15647 15648 M: Richard Leitner <richard.leitner@skidata.com>
+74
drivers/counter/microchip-tcb-capture.c
··· 6 6 */ 7 7 #include <linux/clk.h> 8 8 #include <linux/counter.h> 9 + #include <linux/interrupt.h> 9 10 #include <linux/mfd/syscon.h> 10 11 #include <linux/module.h> 11 12 #include <linux/mutex.h> 12 13 #include <linux/of.h> 14 + #include <linux/of_irq.h> 13 15 #include <linux/platform_device.h> 14 16 #include <linux/regmap.h> 17 + #include <uapi/linux/counter/microchip-tcb-capture.h> 15 18 #include <soc/at91/atmel_tcb.h> 16 19 17 20 #define ATMEL_TC_CMR_MASK (ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \ 18 21 ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \ 19 22 ATMEL_TC_LDBSTOP) 23 + 24 + #define ATMEL_TC_DEF_IRQS (ATMEL_TC_ETRGS | ATMEL_TC_COVFS | \ 25 + ATMEL_TC_LDRAS | ATMEL_TC_LDRBS | ATMEL_TC_CPCS) 20 26 21 27 #define ATMEL_TC_QDEN BIT(8) 22 28 #define ATMEL_TC_POSEN BIT(9) ··· 300 294 { /* sentinel */ } 301 295 }; 302 296 297 + static irqreturn_t mchp_tc_isr(int irq, void *dev_id) 298 + { 299 + struct counter_device *const counter = dev_id; 300 + struct mchp_tc_data *const priv = counter_priv(counter); 301 + u32 sr, mask; 302 + 303 + regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], SR), &sr); 304 + regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], IMR), &mask); 305 + 306 + sr &= mask; 307 + if (!(sr & ATMEL_TC_ALL_IRQ)) 308 + return IRQ_NONE; 309 + 310 + if (sr & ATMEL_TC_ETRGS) 311 + counter_push_event(counter, COUNTER_EVENT_CHANGE_OF_STATE, 312 + COUNTER_MCHP_EVCHN_CV); 313 + if (sr & ATMEL_TC_LDRAS) 314 + counter_push_event(counter, COUNTER_EVENT_CAPTURE, 315 + COUNTER_MCHP_EVCHN_RA); 316 + if (sr & ATMEL_TC_LDRBS) 317 + counter_push_event(counter, COUNTER_EVENT_CAPTURE, 318 + COUNTER_MCHP_EVCHN_RB); 319 + if (sr & ATMEL_TC_CPCS) 320 + counter_push_event(counter, COUNTER_EVENT_THRESHOLD, 321 + COUNTER_MCHP_EVCHN_RC); 322 + if (sr & ATMEL_TC_COVFS) 323 + counter_push_event(counter, COUNTER_EVENT_OVERFLOW, 324 + COUNTER_MCHP_EVCHN_CV); 325 + 326 + return IRQ_HANDLED; 327 + } 328 + 329 + static void mchp_tc_irq_remove(void *ptr) 330 + { 331 + struct mchp_tc_data *priv = ptr; 332 + 333 + regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], IDR), ATMEL_TC_DEF_IRQS); 334 + } 335 + 336 + static int mchp_tc_irq_enable(struct counter_device *const counter, int irq) 337 + { 338 + struct mchp_tc_data *const priv = counter_priv(counter); 339 + int ret = devm_request_irq(counter->parent, irq, mchp_tc_isr, 0, 340 + dev_name(counter->parent), counter); 341 + 342 + if (ret < 0) 343 + return ret; 344 + 345 + ret = regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], IER), ATMEL_TC_DEF_IRQS); 346 + if (ret < 0) 347 + return ret; 348 + 349 + ret = devm_add_action_or_reset(counter->parent, mchp_tc_irq_remove, priv); 350 + if (ret < 0) 351 + return ret; 352 + 353 + return 0; 354 + } 355 + 303 356 static void mchp_tc_clk_remove(void *ptr) 304 357 { 305 358 clk_disable_unprepare((struct clk *)ptr); ··· 442 377 counter->counts = mchp_tc_counts; 443 378 counter->num_signals = ARRAY_SIZE(mchp_tc_count_signals); 444 379 counter->signals = mchp_tc_count_signals; 380 + 381 + i = of_irq_get(np->parent, 0); 382 + if (i == -EPROBE_DEFER) 383 + return -EPROBE_DEFER; 384 + if (i > 0) { 385 + ret = mchp_tc_irq_enable(counter, i); 386 + if (ret < 0) 387 + return dev_err_probe(&pdev->dev, ret, "Failed to set up IRQ"); 388 + } 445 389 446 390 ret = devm_counter_add(&pdev->dev, counter); 447 391 if (ret < 0)
+34
include/uapi/linux/counter/microchip-tcb-capture.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + /* 3 + * Channel numbers used by the microchip-tcb-capture driver 4 + * Copyright (C) 2025 Bence Csókás 5 + */ 6 + #ifndef _UAPI_COUNTER_MCHP_TCB_H_ 7 + #define _UAPI_COUNTER_MCHP_TCB_H_ 8 + 9 + /* 10 + * The driver defines the following components: 11 + * 12 + * Count 0 13 + * \__ Synapse 0 -- Signal 0 (Channel A, i.e. TIOA) 14 + * \__ Synapse 1 -- Signal 1 (Channel B, i.e. TIOB) 15 + * 16 + * It also supports the following events: 17 + * 18 + * Channel 0: 19 + * - CV register changed 20 + * - CV overflowed 21 + * - RA captured 22 + * Channel 1: 23 + * - RB captured 24 + * Channel 2: 25 + * - RC compare triggered 26 + */ 27 + 28 + /* Event channels */ 29 + #define COUNTER_MCHP_EVCHN_CV 0 30 + #define COUNTER_MCHP_EVCHN_RA 0 31 + #define COUNTER_MCHP_EVCHN_RB 1 32 + #define COUNTER_MCHP_EVCHN_RC 2 33 + 34 + #endif /* _UAPI_COUNTER_MCHP_TCB_H_ */