1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6#define pr_fmt(fmt) "tlmm-test: " fmt
7
8#include <kunit/test.h>
9#include <linux/delay.h>
10#include <linux/gpio/consumer.h>
11#include <linux/interrupt.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/of_irq.h>
17#include <linux/pinctrl/consumer.h>
18#include <linux/platform_device.h>
19#include <linux/slab.h>
20
21/*
22 * This TLMM test module serves the purpose of validating that the TLMM driver
23 * (pinctrl-msm) delivers expected number of interrupts in response to changing
24 * GPIO state.
25 *
26 * To achieve this without external equipment the test takes a module parameter
27 * "gpio", which the tester is expected to specify an unused and non-connected
28 * pin. The GPIO state is then driven by adjusting the bias of the pin, at
29 * suitable times through the different test cases.
30 *
31 * Upon execution, the test initialization will find the TLMM node (subject to
32 * tlmm_of_match[] allow listing) and create the necessary references
33 * dynamically, rather then relying on e.g. Devicetree and phandles.
34 */
35
36#define MSM_PULL_MASK GENMASK(2, 0)
37#define MSM_PULL_DOWN 1
38#define MSM_PULL_UP 3
39#define TLMM_REG_SIZE 0x1000
40
41static int tlmm_test_gpio = -1;
42static char *tlmm_reg_name = "default_region";
43
44module_param_named(gpio, tlmm_test_gpio, int, 0600);
45module_param_named(name, tlmm_reg_name, charp, 0600);
46
47static struct {
48 void __iomem *base;
49 void __iomem *reg;
50 int irq;
51
52 u32 low_val;
53 u32 high_val;
54} tlmm_suite;
55
56/**
57 * struct tlmm_test_priv - Per-test context
58 * @intr_count: number of times hard handler was hit with TLMM_TEST_COUNT op set
59 * @thread_count: number of times thread handler was hit with TLMM_TEST_COUNT op set
60 * @intr_op: operations to be performed by the hard IRQ handler
61 * @intr_op_remain: number of times the TLMM_TEST_THEN_* operations should be
62 * performed by the hard IRQ handler
63 * @thread_op: operations to be performed by the threaded IRQ handler
64 * @thread_op_remain: number of times the TLMM_TEST_THEN_* operations should
65 * be performed by the threaded IRQ handler
66 */
67struct tlmm_test_priv {
68 atomic_t intr_count;
69 atomic_t thread_count;
70
71 unsigned int intr_op;
72 atomic_t intr_op_remain;
73
74 unsigned int thread_op;
75 atomic_t thread_op_remain;
76};
77
78/* Operation masks for @intr_op and @thread_op */
79#define TLMM_TEST_COUNT BIT(0)
80#define TLMM_TEST_OUTPUT_LOW BIT(1)
81#define TLMM_TEST_OUTPUT_HIGH BIT(2)
82#define TLMM_TEST_THEN_HIGH BIT(3)
83#define TLMM_TEST_THEN_LOW BIT(4)
84#define TLMM_TEST_WAKE_THREAD BIT(5)
85
86static void tlmm_output_low(void)
87{
88 writel(val: tlmm_suite.low_val, addr: tlmm_suite.reg);
89 readl(addr: tlmm_suite.reg);
90}
91
92static void tlmm_output_high(void)
93{
94 writel(val: tlmm_suite.high_val, addr: tlmm_suite.reg);
95 readl(addr: tlmm_suite.reg);
96}
97
98static irqreturn_t tlmm_test_intr_fn(int irq, void *dev_id)
99{
100 struct tlmm_test_priv *priv = dev_id;
101
102 if (priv->intr_op & TLMM_TEST_COUNT)
103 atomic_inc(v: &priv->intr_count);
104
105 if (priv->intr_op & TLMM_TEST_OUTPUT_LOW)
106 tlmm_output_low();
107 if (priv->intr_op & TLMM_TEST_OUTPUT_HIGH)
108 tlmm_output_high();
109
110 if (atomic_dec_if_positive(v: &priv->intr_op_remain) > 0) {
111 udelay(usec: 1);
112
113 if (priv->intr_op & TLMM_TEST_THEN_LOW)
114 tlmm_output_low();
115 if (priv->intr_op & TLMM_TEST_THEN_HIGH)
116 tlmm_output_high();
117 }
118
119 return priv->intr_op & TLMM_TEST_WAKE_THREAD ? IRQ_WAKE_THREAD : IRQ_HANDLED;
120}
121
122static irqreturn_t tlmm_test_intr_thread_fn(int irq, void *dev_id)
123{
124 struct tlmm_test_priv *priv = dev_id;
125
126 if (priv->thread_op & TLMM_TEST_COUNT)
127 atomic_inc(v: &priv->thread_count);
128
129 if (priv->thread_op & TLMM_TEST_OUTPUT_LOW)
130 tlmm_output_low();
131 if (priv->thread_op & TLMM_TEST_OUTPUT_HIGH)
132 tlmm_output_high();
133
134 if (atomic_dec_if_positive(v: &priv->thread_op_remain) > 0) {
135 udelay(usec: 1);
136 if (priv->thread_op & TLMM_TEST_THEN_LOW)
137 tlmm_output_low();
138 if (priv->thread_op & TLMM_TEST_THEN_HIGH)
139 tlmm_output_high();
140 }
141
142 return IRQ_HANDLED;
143}
144
145static void tlmm_test_request_hard_irq(struct kunit *test, unsigned long irqflags)
146{
147 struct tlmm_test_priv *priv = test->priv;
148 int ret;
149
150 ret = request_irq(irq: tlmm_suite.irq, handler: tlmm_test_intr_fn, flags: irqflags, name: test->name, dev: priv);
151 KUNIT_EXPECT_EQ(test, ret, 0);
152}
153
154static void tlmm_test_request_threaded_irq(struct kunit *test, unsigned long irqflags)
155{
156 struct tlmm_test_priv *priv = test->priv;
157 int ret;
158
159 ret = request_threaded_irq(irq: tlmm_suite.irq,
160 handler: tlmm_test_intr_fn, thread_fn: tlmm_test_intr_thread_fn,
161 flags: irqflags, name: test->name, dev: priv);
162
163 KUNIT_EXPECT_EQ(test, ret, 0);
164}
165
166static void tlmm_test_silent(struct kunit *test, unsigned long irqflags)
167{
168 struct tlmm_test_priv *priv = test->priv;
169
170 priv->intr_op = TLMM_TEST_COUNT;
171
172 /* GPIO line at non-triggering level */
173 if (irqflags == IRQF_TRIGGER_LOW || irqflags == IRQF_TRIGGER_FALLING)
174 tlmm_output_high();
175 else
176 tlmm_output_low();
177
178 tlmm_test_request_hard_irq(test, irqflags);
179 msleep(msecs: 100);
180 free_irq(tlmm_suite.irq, priv);
181
182 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 0);
183}
184
185/*
186 * Test that no RISING interrupts are triggered on a silent pin
187 */
188static void tlmm_test_silent_rising(struct kunit *test)
189{
190 tlmm_test_silent(test, IRQF_TRIGGER_RISING);
191}
192
193/*
194 * Test that no FALLING interrupts are triggered on a silent pin
195 */
196static void tlmm_test_silent_falling(struct kunit *test)
197{
198 tlmm_test_silent(test, IRQF_TRIGGER_FALLING);
199}
200
201/*
202 * Test that no LOW interrupts are triggered on a silent pin
203 */
204static void tlmm_test_silent_low(struct kunit *test)
205{
206 tlmm_test_silent(test, IRQF_TRIGGER_LOW);
207}
208
209/*
210 * Test that no HIGH interrupts are triggered on a silent pin
211 */
212static void tlmm_test_silent_high(struct kunit *test)
213{
214 tlmm_test_silent(test, IRQF_TRIGGER_HIGH);
215}
216
217/*
218 * Square wave with 10 high pulses, assert that we get 10 rising interrupts
219 */
220static void tlmm_test_rising(struct kunit *test)
221{
222 struct tlmm_test_priv *priv = test->priv;
223 int i;
224
225 priv->intr_op = TLMM_TEST_COUNT;
226
227 tlmm_output_low();
228
229 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING);
230 for (i = 0; i < 10; i++) {
231 tlmm_output_low();
232 msleep(msecs: 20);
233 tlmm_output_high();
234 msleep(msecs: 20);
235 }
236
237 free_irq(tlmm_suite.irq, priv);
238
239 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
240}
241
242/*
243 * Square wave with 10 low pulses, assert that we get 10 falling interrupts
244 */
245static void tlmm_test_falling(struct kunit *test)
246{
247 struct tlmm_test_priv *priv = test->priv;
248 int i;
249
250 priv->intr_op = TLMM_TEST_COUNT;
251
252 tlmm_output_high();
253
254 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_FALLING);
255 for (i = 0; i < 10; i++) {
256 tlmm_output_high();
257 msleep(msecs: 20);
258 tlmm_output_low();
259 msleep(msecs: 20);
260 }
261 free_irq(tlmm_suite.irq, priv);
262
263 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
264}
265
266/*
267 * Drive line low 10 times, handler drives it high to "clear the interrupt
268 * source", assert we get 10 interrupts
269 */
270static void tlmm_test_low(struct kunit *test)
271{
272 struct tlmm_test_priv *priv = test->priv;
273 int i;
274
275 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH;
276 atomic_set(v: &priv->intr_op_remain, i: 9);
277
278 tlmm_output_high();
279
280 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_LOW);
281 for (i = 0; i < 10; i++) {
282 msleep(msecs: 20);
283 tlmm_output_low();
284 }
285 msleep(msecs: 100);
286 free_irq(tlmm_suite.irq, priv);
287
288 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
289}
290
291/*
292 * Drive line high 10 times, handler drives it low to "clear the interrupt
293 * source", assert we get 10 interrupts
294 */
295static void tlmm_test_high(struct kunit *test)
296{
297 struct tlmm_test_priv *priv = test->priv;
298 int i;
299
300 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW;
301 atomic_set(v: &priv->intr_op_remain, i: 9);
302
303 tlmm_output_low();
304
305 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_HIGH);
306 for (i = 0; i < 10; i++) {
307 msleep(msecs: 20);
308 tlmm_output_high();
309 }
310 msleep(msecs: 100);
311 free_irq(tlmm_suite.irq, priv);
312
313 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
314}
315
316/*
317 * Handler drives GPIO high to "clear the interrupt source", then low to
318 * simulate a new interrupt, repeated 10 times, assert we get 10 interrupts
319 */
320static void tlmm_test_falling_in_handler(struct kunit *test)
321{
322 struct tlmm_test_priv *priv = test->priv;
323
324 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH | TLMM_TEST_THEN_LOW;
325 atomic_set(v: &priv->intr_op_remain, i: 10);
326
327 tlmm_output_high();
328
329 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_FALLING);
330 msleep(msecs: 20);
331 tlmm_output_low();
332 msleep(msecs: 100);
333 free_irq(tlmm_suite.irq, priv);
334
335 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
336}
337
338/*
339 * Handler drives GPIO low to "clear the interrupt source", then high to
340 * simulate a new interrupt, repeated 10 times, assert we get 10 interrupts
341 */
342static void tlmm_test_rising_in_handler(struct kunit *test)
343{
344 struct tlmm_test_priv *priv = test->priv;
345
346 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW | TLMM_TEST_THEN_HIGH;
347 atomic_set(v: &priv->intr_op_remain, i: 10);
348
349 tlmm_output_low();
350
351 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING);
352 msleep(msecs: 20);
353 tlmm_output_high();
354 msleep(msecs: 100);
355 free_irq(tlmm_suite.irq, priv);
356
357 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
358}
359
360/*
361 * Square wave with 10 high pulses, assert that we get 10 rising hard and
362 * 10 threaded interrupts
363 */
364static void tlmm_test_thread_rising(struct kunit *test)
365{
366 struct tlmm_test_priv *priv = test->priv;
367 int i;
368
369 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD;
370 priv->thread_op = TLMM_TEST_COUNT;
371
372 tlmm_output_low();
373
374 tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_RISING);
375 for (i = 0; i < 10; i++) {
376 tlmm_output_low();
377 msleep(msecs: 20);
378 tlmm_output_high();
379 msleep(msecs: 20);
380 }
381 free_irq(tlmm_suite.irq, priv);
382
383 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
384 KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10);
385}
386
387/*
388 * Square wave with 10 low pulses, assert that we get 10 falling interrupts
389 */
390static void tlmm_test_thread_falling(struct kunit *test)
391{
392 struct tlmm_test_priv *priv = test->priv;
393 int i;
394
395 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD;
396 priv->thread_op = TLMM_TEST_COUNT;
397
398 tlmm_output_high();
399
400 tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_FALLING);
401 for (i = 0; i < 10; i++) {
402 tlmm_output_high();
403 msleep(msecs: 20);
404 tlmm_output_low();
405 msleep(msecs: 20);
406 }
407 free_irq(tlmm_suite.irq, priv);
408
409 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
410 KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10);
411}
412
413/*
414 * Drive line high 10 times, threaded handler drives it low to "clear the
415 * interrupt source", assert we get 10 interrupts
416 */
417static void tlmm_test_thread_high(struct kunit *test)
418{
419 struct tlmm_test_priv *priv = test->priv;
420 int i;
421
422 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD;
423 priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW;
424
425 tlmm_output_low();
426
427 tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_HIGH | IRQF_ONESHOT);
428 for (i = 0; i < 10; i++) {
429 tlmm_output_high();
430 msleep(msecs: 20);
431 }
432 free_irq(tlmm_suite.irq, priv);
433
434 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
435 KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10);
436}
437
438/*
439 * Drive line low 10 times, threaded handler drives it high to "clear the
440 * interrupt source", assert we get 10 interrupts
441 */
442static void tlmm_test_thread_low(struct kunit *test)
443{
444 struct tlmm_test_priv *priv = test->priv;
445 int i;
446
447 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD;
448 priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH;
449
450 tlmm_output_high();
451
452 tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_LOW | IRQF_ONESHOT);
453 for (i = 0; i < 10; i++) {
454 tlmm_output_low();
455 msleep(msecs: 20);
456 }
457 free_irq(tlmm_suite.irq, priv);
458
459 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
460 KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10);
461}
462
463/*
464 * Handler drives GPIO low to "clear the interrupt source", then high in the
465 * threaded handler to simulate a new interrupt, repeated 10 times, assert we
466 * get 10 interrupts
467 */
468static void tlmm_test_thread_rising_in_handler(struct kunit *test)
469{
470 struct tlmm_test_priv *priv = test->priv;
471
472 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW | TLMM_TEST_WAKE_THREAD;
473 priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_THEN_HIGH;
474 atomic_set(v: &priv->thread_op_remain, i: 10);
475
476 tlmm_output_low();
477
478 tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_RISING);
479 msleep(msecs: 20);
480 tlmm_output_high();
481 msleep(msecs: 100);
482 free_irq(tlmm_suite.irq, priv);
483
484 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
485 KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10);
486}
487
488/*
489 * Handler drives GPIO high to "clear the interrupt source", then low in the
490 * threaded handler to simulate a new interrupt, repeated 10 times, assert we
491 * get 10 interrupts
492 */
493static void tlmm_test_thread_falling_in_handler(struct kunit *test)
494{
495 struct tlmm_test_priv *priv = test->priv;
496
497 priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH | TLMM_TEST_WAKE_THREAD;
498 priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_THEN_LOW;
499 atomic_set(v: &priv->thread_op_remain, i: 10);
500
501 tlmm_output_high();
502
503 tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_FALLING);
504 msleep(msecs: 20);
505 tlmm_output_low();
506 msleep(msecs: 100);
507 free_irq(tlmm_suite.irq, priv);
508
509 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10);
510 KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10);
511}
512
513/*
514 * Validate that edge interrupts occurring while irq is disabled is delivered
515 * once the interrupt is reenabled.
516 */
517static void tlmm_test_rising_while_disabled(struct kunit *test)
518{
519 struct tlmm_test_priv *priv = test->priv;
520 unsigned int after_edge;
521 unsigned int before_edge;
522
523 priv->intr_op = TLMM_TEST_COUNT;
524 atomic_set(v: &priv->thread_op_remain, i: 10);
525
526 tlmm_output_low();
527
528 tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING);
529 msleep(msecs: 20);
530
531 disable_irq(irq: tlmm_suite.irq);
532 before_edge = atomic_read(v: &priv->intr_count);
533
534 tlmm_output_high();
535 msleep(msecs: 20);
536 after_edge = atomic_read(v: &priv->intr_count);
537
538 msleep(msecs: 20);
539 enable_irq(irq: tlmm_suite.irq);
540 msleep(msecs: 20);
541
542 free_irq(tlmm_suite.irq, priv);
543
544 KUNIT_ASSERT_EQ(test, before_edge, 0);
545 KUNIT_ASSERT_EQ(test, after_edge, 0);
546 KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 1);
547}
548
549static int tlmm_test_init(struct kunit *test)
550{
551 struct tlmm_test_priv *priv;
552
553 priv = kunit_kzalloc(test, size: sizeof(*priv), GFP_KERNEL);
554 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
555
556 atomic_set(v: &priv->intr_count, i: 0);
557 atomic_set(v: &priv->thread_count, i: 0);
558
559 atomic_set(v: &priv->intr_op_remain, i: 0);
560 atomic_set(v: &priv->thread_op_remain, i: 0);
561
562 test->priv = priv;
563
564 return 0;
565}
566
567/*
568 * NOTE: When adding compatibles to this list, ensure that TLMM_REG_SIZE and
569 * pull configuration values are supported and correct.
570 */
571static const struct of_device_id tlmm_of_match[] = {
572 { .compatible = "qcom,sc8280xp-tlmm" },
573 { .compatible = "qcom,x1e80100-tlmm" },
574 {}
575};
576
577static int tlmm_reg_base(struct device_node *tlmm, struct resource *res)
578{
579 const char **reg_names;
580 int count;
581 int ret;
582 int i;
583
584 count = of_property_count_strings(np: tlmm, propname: "reg-names");
585 if (count <= 0) {
586 pr_err("failed to find tlmm reg name\n");
587 return count;
588 }
589
590 reg_names = kcalloc(count, sizeof(char *), GFP_KERNEL);
591 if (!reg_names)
592 return -ENOMEM;
593
594 ret = of_property_read_string_array(np: tlmm, propname: "reg-names", out_strs: reg_names, sz: count);
595 if (ret != count) {
596 kfree(objp: reg_names);
597 return -EINVAL;
598 }
599
600 if (!strcmp(tlmm_reg_name, "default_region")) {
601 ret = of_address_to_resource(dev: tlmm, index: 0, r: res);
602 } else {
603 for (i = 0; i < count; i++) {
604 if (!strcmp(reg_names[i], tlmm_reg_name)) {
605 ret = of_address_to_resource(dev: tlmm, index: i, r: res);
606 break;
607 }
608 }
609 if (i == count)
610 ret = -EINVAL;
611 }
612
613 kfree(objp: reg_names);
614
615 return ret;
616}
617
618static int tlmm_test_init_suite(struct kunit_suite *suite)
619{
620 struct of_phandle_args args = {};
621 struct resource res;
622 int ret;
623 u32 val;
624
625 if (tlmm_test_gpio < 0) {
626 pr_err("use the tlmm-test.gpio module parameter to specify which GPIO to use\n");
627 return -EINVAL;
628 }
629
630 struct device_node *tlmm __free(device_node) = of_find_matching_node(NULL, matches: tlmm_of_match);
631 if (!tlmm) {
632 pr_err("failed to find tlmm node\n");
633 return -EINVAL;
634 }
635
636 ret = tlmm_reg_base(tlmm, res: &res);
637 if (ret < 0)
638 return ret;
639
640 tlmm_suite.base = ioremap(offset: res.start, size: resource_size(res: &res));
641 if (!tlmm_suite.base)
642 return -ENOMEM;
643
644 args.np = tlmm;
645 args.args_count = 2;
646 args.args[0] = tlmm_test_gpio;
647 args.args[1] = 0;
648
649 tlmm_suite.irq = irq_create_of_mapping(irq_data: &args);
650 if (!tlmm_suite.irq) {
651 pr_err("failed to map TLMM irq %d\n", args.args[0]);
652 goto err_unmap;
653 }
654
655 tlmm_suite.reg = tlmm_suite.base + tlmm_test_gpio * TLMM_REG_SIZE;
656 val = readl(addr: tlmm_suite.reg) & ~MSM_PULL_MASK;
657 tlmm_suite.low_val = val | MSM_PULL_DOWN;
658 tlmm_suite.high_val = val | MSM_PULL_UP;
659
660 return 0;
661
662err_unmap:
663 iounmap(addr: tlmm_suite.base);
664 tlmm_suite.base = NULL;
665 return -EINVAL;
666}
667
668static void tlmm_test_exit_suite(struct kunit_suite *suite)
669{
670 irq_dispose_mapping(virq: tlmm_suite.irq);
671 iounmap(addr: tlmm_suite.base);
672
673 tlmm_suite.base = NULL;
674 tlmm_suite.irq = -1;
675}
676
677static struct kunit_case tlmm_test_cases[] = {
678 KUNIT_CASE(tlmm_test_silent_rising),
679 KUNIT_CASE(tlmm_test_silent_falling),
680 KUNIT_CASE(tlmm_test_silent_low),
681 KUNIT_CASE(tlmm_test_silent_high),
682 KUNIT_CASE(tlmm_test_rising),
683 KUNIT_CASE(tlmm_test_falling),
684 KUNIT_CASE(tlmm_test_high),
685 KUNIT_CASE(tlmm_test_low),
686 KUNIT_CASE(tlmm_test_rising_in_handler),
687 KUNIT_CASE(tlmm_test_falling_in_handler),
688 KUNIT_CASE(tlmm_test_thread_rising),
689 KUNIT_CASE(tlmm_test_thread_falling),
690 KUNIT_CASE(tlmm_test_thread_high),
691 KUNIT_CASE(tlmm_test_thread_low),
692 KUNIT_CASE(tlmm_test_thread_rising_in_handler),
693 KUNIT_CASE(tlmm_test_thread_falling_in_handler),
694 KUNIT_CASE(tlmm_test_rising_while_disabled),
695 {}
696};
697
698static struct kunit_suite tlmm_test_suite = {
699 .name = "tlmm-test",
700 .init = tlmm_test_init,
701 .suite_init = tlmm_test_init_suite,
702 .suite_exit = tlmm_test_exit_suite,
703 .test_cases = tlmm_test_cases,
704};
705
706kunit_test_suites(&tlmm_test_suite);
707
708MODULE_DESCRIPTION("Qualcomm TLMM test");
709MODULE_LICENSE("GPL");
710

source code of linux/drivers/pinctrl/qcom/tlmm-test.c