xref: /openbmc/qemu/tests/qtest/npcm7xx_pwm-test.c (revision 6c187695)
1 /*
2  * QTests for Nuvoton NPCM7xx PWM Modules.
3  *
4  * Copyright 2020 Google LLC
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  */
16 
17 #include "qemu/osdep.h"
18 #include "qemu/bitops.h"
19 #include "libqtest.h"
20 #include "qapi/qmp/qdict.h"
21 #include "qapi/qmp/qnum.h"
22 
23 #define REF_HZ          25000000
24 
25 /* Register field definitions. */
26 #define CH_EN           BIT(0)
27 #define CH_INV          BIT(2)
28 #define CH_MOD          BIT(3)
29 
30 /* Registers shared between all PWMs in a module */
31 #define PPR             0x00
32 #define CSR             0x04
33 #define PCR             0x08
34 #define PIER            0x3c
35 #define PIIR            0x40
36 
37 /* CLK module related */
38 #define CLK_BA          0xf0801000
39 #define CLKSEL          0x04
40 #define CLKDIV1         0x08
41 #define CLKDIV2         0x2c
42 #define PLLCON0         0x0c
43 #define PLLCON1         0x10
44 #define PLL_INDV(rv)    extract32((rv), 0, 6)
45 #define PLL_FBDV(rv)    extract32((rv), 16, 12)
46 #define PLL_OTDV1(rv)   extract32((rv), 8, 3)
47 #define PLL_OTDV2(rv)   extract32((rv), 13, 3)
48 #define APB4CKDIV(rv)   extract32((rv), 30, 2)
49 #define APB3CKDIV(rv)   extract32((rv), 28, 2)
50 #define CLK2CKDIV(rv)   extract32((rv), 0, 1)
51 #define CLK4CKDIV(rv)   extract32((rv), 26, 2)
52 #define CPUCKSEL(rv)    extract32((rv), 0, 2)
53 
54 #define MAX_DUTY        1000000
55 
56 /* MFT (PWM fan) related */
57 #define MFT_BA(n)       (0xf0180000 + ((n) * 0x1000))
58 #define MFT_IRQ(n)      (96 + (n))
59 #define MFT_CNT1        0x00
60 #define MFT_CRA         0x02
61 #define MFT_CRB         0x04
62 #define MFT_CNT2        0x06
63 #define MFT_PRSC        0x08
64 #define MFT_CKC         0x0a
65 #define MFT_MCTRL       0x0c
66 #define MFT_ICTRL       0x0e
67 #define MFT_ICLR        0x10
68 #define MFT_IEN         0x12
69 #define MFT_CPA         0x14
70 #define MFT_CPB         0x16
71 #define MFT_CPCFG       0x18
72 #define MFT_INASEL      0x1a
73 #define MFT_INBSEL      0x1c
74 
75 #define MFT_MCTRL_ALL   0x64
76 #define MFT_ICLR_ALL    0x3f
77 #define MFT_IEN_ALL     0x3f
78 #define MFT_CPCFG_EQ_MODE 0x44
79 
80 #define MFT_CKC_C2CSEL  BIT(3)
81 #define MFT_CKC_C1CSEL  BIT(0)
82 
83 #define MFT_ICTRL_TFPND BIT(5)
84 #define MFT_ICTRL_TEPND BIT(4)
85 #define MFT_ICTRL_TDPND BIT(3)
86 #define MFT_ICTRL_TCPND BIT(2)
87 #define MFT_ICTRL_TBPND BIT(1)
88 #define MFT_ICTRL_TAPND BIT(0)
89 
90 #define MFT_MAX_CNT     0xffff
91 #define MFT_TIMEOUT     0x5000
92 
93 #define DEFAULT_RPM     19800
94 #define DEFAULT_PRSC    255
95 #define MFT_PULSE_PER_REVOLUTION 2
96 
97 #define MAX_ERROR       1
98 
99 typedef struct PWMModule {
100     int irq;
101     uint64_t base_addr;
102 } PWMModule;
103 
104 typedef struct PWM {
105     uint32_t cnr_offset;
106     uint32_t cmr_offset;
107     uint32_t pdr_offset;
108     uint32_t pwdr_offset;
109 } PWM;
110 
111 typedef struct TestData {
112     const PWMModule *module;
113     const PWM *pwm;
114 } TestData;
115 
116 static const PWMModule pwm_module_list[] = {
117     {
118         .irq        = 93,
119         .base_addr  = 0xf0103000
120     },
121     {
122         .irq        = 94,
123         .base_addr  = 0xf0104000
124     }
125 };
126 
127 static const PWM pwm_list[] = {
128     {
129         .cnr_offset     = 0x0c,
130         .cmr_offset     = 0x10,
131         .pdr_offset     = 0x14,
132         .pwdr_offset    = 0x44,
133     },
134     {
135         .cnr_offset     = 0x18,
136         .cmr_offset     = 0x1c,
137         .pdr_offset     = 0x20,
138         .pwdr_offset    = 0x48,
139     },
140     {
141         .cnr_offset     = 0x24,
142         .cmr_offset     = 0x28,
143         .pdr_offset     = 0x2c,
144         .pwdr_offset    = 0x4c,
145     },
146     {
147         .cnr_offset     = 0x30,
148         .cmr_offset     = 0x34,
149         .pdr_offset     = 0x38,
150         .pwdr_offset    = 0x50,
151     },
152 };
153 
154 static const int ppr_base[] = { 0, 0, 8, 8 };
155 static const int csr_base[] = { 0, 4, 8, 12 };
156 static const int pcr_base[] = { 0, 8, 12, 16 };
157 
158 static const uint32_t ppr_list[] = {
159     0,
160     1,
161     10,
162     100,
163     255, /* Max possible value. */
164 };
165 
166 static const uint32_t csr_list[] = {
167     0,
168     1,
169     2,
170     3,
171     4, /* Max possible value. */
172 };
173 
174 static const uint32_t cnr_list[] = {
175     0,
176     1,
177     50,
178     100,
179     150,
180     200,
181     1000,
182     10000,
183     65535, /* Max possible value. */
184 };
185 
186 static const uint32_t cmr_list[] = {
187     0,
188     1,
189     10,
190     50,
191     100,
192     150,
193     200,
194     1000,
195     10000,
196     65535, /* Max possible value. */
197 };
198 
199 /* Returns the index of the PWM module. */
200 static int pwm_module_index(const PWMModule *module)
201 {
202     ptrdiff_t diff = module - pwm_module_list;
203 
204     g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
205 
206     return diff;
207 }
208 
209 /* Returns the index of the PWM entry. */
210 static int pwm_index(const PWM *pwm)
211 {
212     ptrdiff_t diff = pwm - pwm_list;
213 
214     g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
215 
216     return diff;
217 }
218 
219 static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name)
220 {
221     QDict *response;
222     uint64_t val;
223 
224     g_test_message("Getting properties %s from %s", name, path);
225     response = qtest_qmp(qts, "{ 'execute': 'qom-get',"
226             " 'arguments': { 'path': %s, 'property': %s}}",
227             path, name);
228     /* The qom set message returns successfully. */
229     g_assert_true(qdict_haskey(response, "return"));
230     val = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
231     qobject_unref(response);
232     return val;
233 }
234 
235 static uint64_t pwm_get_freq(QTestState *qts, int module_index, int pwm_index)
236 {
237     char path[100];
238     char name[100];
239 
240     sprintf(path, "/machine/soc/pwm[%d]", module_index);
241     sprintf(name, "freq[%d]", pwm_index);
242 
243     return pwm_qom_get(qts, path, name);
244 }
245 
246 static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
247 {
248     char path[100];
249     char name[100];
250 
251     sprintf(path, "/machine/soc/pwm[%d]", module_index);
252     sprintf(name, "duty[%d]", pwm_index);
253 
254     return pwm_qom_get(qts, path, name);
255 }
256 
257 static void mft_qom_set(QTestState *qts, int index, const char *name,
258                         uint32_t value)
259 {
260     QDict *response;
261     char *path = g_strdup_printf("/machine/soc/mft[%d]", index);
262 
263     g_test_message("Setting properties %s of mft[%d] with value %u",
264                    name, index, value);
265     response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
266             " 'arguments': { 'path': %s, "
267             " 'property': %s, 'value': %u}}",
268             path, name, value);
269     /* The qom set message returns successfully. */
270     g_assert_true(qdict_haskey(response, "return"));
271 
272     qobject_unref(response);
273     g_free(path);
274 }
275 
276 static uint32_t get_pll(uint32_t con)
277 {
278     return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
279             * PLL_OTDV2(con));
280 }
281 
282 static uint64_t read_pclk(QTestState *qts, bool mft)
283 {
284     uint64_t freq = REF_HZ;
285     uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
286     uint32_t pllcon;
287     uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
288     uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
289     uint32_t apbdiv = mft ? APB4CKDIV(clkdiv2) : APB3CKDIV(clkdiv2);
290 
291     switch (CPUCKSEL(clksel)) {
292     case 0:
293         pllcon = qtest_readl(qts, CLK_BA + PLLCON0);
294         freq = get_pll(pllcon);
295         break;
296     case 1:
297         pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
298         freq = get_pll(pllcon);
299         break;
300     case 2:
301         break;
302     case 3:
303         break;
304     default:
305         g_assert_not_reached();
306     }
307 
308     freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + apbdiv);
309 
310     return freq;
311 }
312 
313 static uint32_t pwm_selector(uint32_t csr)
314 {
315     switch (csr) {
316     case 0:
317         return 2;
318     case 1:
319         return 4;
320     case 2:
321         return 8;
322     case 3:
323         return 16;
324     case 4:
325         return 1;
326     default:
327         g_assert_not_reached();
328     }
329 }
330 
331 static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
332         uint32_t cnr)
333 {
334     return read_pclk(qts, false) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
335 }
336 
337 static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
338 {
339     uint32_t duty;
340 
341     if (cnr == 0) {
342         /* PWM is stopped. */
343         duty = 0;
344     } else if (cmr >= cnr) {
345         duty = MAX_DUTY;
346     } else {
347         duty = (uint64_t)MAX_DUTY * (cmr + 1) / (cnr + 1);
348     }
349 
350     if (inverted) {
351         duty = MAX_DUTY - duty;
352     }
353 
354     return duty;
355 }
356 
357 static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
358 {
359     return qtest_readl(qts, td->module->base_addr + offset);
360 }
361 
362 static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
363         uint32_t value)
364 {
365     qtest_writel(qts, td->module->base_addr + offset, value);
366 }
367 
368 static uint8_t mft_readb(QTestState *qts, int index, unsigned offset)
369 {
370     return qtest_readb(qts, MFT_BA(index) + offset);
371 }
372 
373 static uint16_t mft_readw(QTestState *qts, int index, unsigned offset)
374 {
375     return qtest_readw(qts, MFT_BA(index) + offset);
376 }
377 
378 static void mft_writeb(QTestState *qts, int index, unsigned offset,
379                         uint8_t value)
380 {
381     qtest_writeb(qts, MFT_BA(index) + offset, value);
382 }
383 
384 static void mft_writew(QTestState *qts, int index, unsigned offset,
385                         uint16_t value)
386 {
387     return qtest_writew(qts, MFT_BA(index) + offset, value);
388 }
389 
390 static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
391 {
392     return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
393 }
394 
395 static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
396 {
397     pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
398 }
399 
400 static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
401 {
402     return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
403 }
404 
405 static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
406 {
407     pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
408 }
409 
410 static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
411 {
412     return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
413 }
414 
415 static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
416 {
417     pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
418 }
419 
420 static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
421 {
422     return pwm_read(qts, td, td->pwm->cnr_offset);
423 }
424 
425 static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
426 {
427     pwm_write(qts, td, td->pwm->cnr_offset, value);
428 }
429 
430 static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
431 {
432     return pwm_read(qts, td, td->pwm->cmr_offset);
433 }
434 
435 static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
436 {
437     pwm_write(qts, td, td->pwm->cmr_offset, value);
438 }
439 
440 static int mft_compute_index(const TestData *td)
441 {
442     int index = pwm_module_index(td->module) * ARRAY_SIZE(pwm_list) +
443                 pwm_index(td->pwm);
444 
445     g_assert_cmpint(index, <,
446                     ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list));
447 
448     return index;
449 }
450 
451 static void mft_reset_counters(QTestState *qts, int index)
452 {
453     mft_writew(qts, index, MFT_CNT1, MFT_MAX_CNT);
454     mft_writew(qts, index, MFT_CNT2, MFT_MAX_CNT);
455     mft_writew(qts, index, MFT_CRA, MFT_MAX_CNT);
456     mft_writew(qts, index, MFT_CRB, MFT_MAX_CNT);
457     mft_writew(qts, index, MFT_CPA, MFT_MAX_CNT - MFT_TIMEOUT);
458     mft_writew(qts, index, MFT_CPB, MFT_MAX_CNT - MFT_TIMEOUT);
459 }
460 
461 static void mft_init(QTestState *qts, const TestData *td)
462 {
463     int index = mft_compute_index(td);
464 
465     /* Enable everything */
466     mft_writeb(qts, index, MFT_CKC, 0);
467     mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
468     mft_writeb(qts, index, MFT_MCTRL, MFT_MCTRL_ALL);
469     mft_writeb(qts, index, MFT_IEN, MFT_IEN_ALL);
470     mft_writeb(qts, index, MFT_INASEL, 0);
471     mft_writeb(qts, index, MFT_INBSEL, 0);
472 
473     /* Set cpcfg to use EQ mode, same as kernel driver */
474     mft_writeb(qts, index, MFT_CPCFG, MFT_CPCFG_EQ_MODE);
475 
476     /* Write default counters, timeout and prescaler */
477     mft_reset_counters(qts, index);
478     mft_writeb(qts, index, MFT_PRSC, DEFAULT_PRSC);
479 
480     /* Write default max rpm via QMP */
481     mft_qom_set(qts, index, "max_rpm[0]", DEFAULT_RPM);
482     mft_qom_set(qts, index, "max_rpm[1]", DEFAULT_RPM);
483 }
484 
485 static int32_t mft_compute_cnt(uint32_t rpm, uint64_t clk)
486 {
487     uint64_t cnt;
488 
489     if (rpm == 0) {
490         return -1;
491     }
492 
493     cnt = clk * 60 / ((DEFAULT_PRSC + 1) * rpm * MFT_PULSE_PER_REVOLUTION);
494     if (cnt >= MFT_TIMEOUT) {
495         return -1;
496     }
497     return MFT_MAX_CNT - cnt;
498 }
499 
500 static void mft_verify_rpm(QTestState *qts, const TestData *td, uint64_t duty)
501 {
502     int index = mft_compute_index(td);
503     uint16_t cnt, cr;
504     uint32_t rpm = DEFAULT_RPM * duty / MAX_DUTY;
505     uint64_t clk = read_pclk(qts, true);
506     int32_t expected_cnt = mft_compute_cnt(rpm, clk);
507 
508     qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
509     g_test_message(
510         "verifying rpm for mft[%d]: clk: %" PRIu64 ", duty: %" PRIu64 ", rpm: %u, cnt: %d",
511         index, clk, duty, rpm, expected_cnt);
512 
513     /* Verify rpm for fan A */
514     /* Stop capture */
515     mft_writeb(qts, index, MFT_CKC, 0);
516     mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
517     mft_reset_counters(qts, index);
518     g_assert_cmphex(mft_readw(qts, index, MFT_CNT1), ==, MFT_MAX_CNT);
519     g_assert_cmphex(mft_readw(qts, index, MFT_CRA), ==, MFT_MAX_CNT);
520     g_assert_cmphex(mft_readw(qts, index, MFT_CPA), ==,
521                     MFT_MAX_CNT - MFT_TIMEOUT);
522     /* Start capture */
523     mft_writeb(qts, index, MFT_CKC, MFT_CKC_C1CSEL);
524     g_assert_true(qtest_get_irq(qts, MFT_IRQ(index)));
525     if (expected_cnt == -1) {
526         g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TEPND);
527     } else {
528         g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TAPND);
529         cnt = mft_readw(qts, index, MFT_CNT1);
530         /*
531          * Due to error in clock measurement and rounding, we might have a small
532          * error in measuring RPM.
533          */
534         g_assert_cmphex(cnt + MAX_ERROR, >=, expected_cnt);
535         g_assert_cmphex(cnt, <=, expected_cnt + MAX_ERROR);
536         cr = mft_readw(qts, index, MFT_CRA);
537         g_assert_cmphex(cnt, ==, cr);
538     }
539 
540     /* Verify rpm for fan B */
541 
542     qtest_irq_intercept_out(qts, "/machine/soc/a9mpcore/gic");
543 }
544 
545 /* Check pwm registers can be reset to default value */
546 static void test_init(gconstpointer test_data)
547 {
548     const TestData *td = test_data;
549     QTestState *qts = qtest_init("-machine npcm750-evb");
550     int module = pwm_module_index(td->module);
551     int pwm = pwm_index(td->pwm);
552 
553     g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
554     g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
555 
556     qtest_quit(qts);
557 }
558 
559 /* One-shot mode should not change frequency and duty cycle. */
560 static void test_oneshot(gconstpointer test_data)
561 {
562     const TestData *td = test_data;
563     QTestState *qts = qtest_init("-machine npcm750-evb");
564     int module = pwm_module_index(td->module);
565     int pwm = pwm_index(td->pwm);
566     uint32_t ppr, csr, pcr;
567     int i, j;
568 
569     pcr = CH_EN;
570     for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
571         ppr = ppr_list[i];
572         pwm_write_ppr(qts, td, ppr);
573 
574         for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
575             csr = csr_list[j];
576             pwm_write_csr(qts, td, csr);
577             pwm_write_pcr(qts, td, pcr);
578 
579             g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
580             g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
581             g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
582             g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
583             g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
584         }
585     }
586 
587     qtest_quit(qts);
588 }
589 
590 /* In toggle mode, the PWM generates correct outputs. */
591 static void test_toggle(gconstpointer test_data)
592 {
593     const TestData *td = test_data;
594     QTestState *qts = qtest_init("-machine npcm750-evb");
595     int module = pwm_module_index(td->module);
596     int pwm = pwm_index(td->pwm);
597     uint32_t ppr, csr, pcr, cnr, cmr;
598     int i, j, k, l;
599     uint64_t expected_freq, expected_duty;
600 
601     mft_init(qts, td);
602 
603     pcr = CH_EN | CH_MOD;
604     for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
605         ppr = ppr_list[i];
606         pwm_write_ppr(qts, td, ppr);
607 
608         for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
609             csr = csr_list[j];
610             pwm_write_csr(qts, td, csr);
611 
612             for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
613                 cnr = cnr_list[k];
614                 pwm_write_cnr(qts, td, cnr);
615 
616                 for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
617                     cmr = cmr_list[l];
618                     pwm_write_cmr(qts, td, cmr);
619                     expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
620                     expected_duty = pwm_compute_duty(cnr, cmr, false);
621 
622                     pwm_write_pcr(qts, td, pcr);
623                     g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
624                     g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
625                     g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
626                     g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
627                     g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
628                     g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
629                             ==, expected_duty);
630                     if (expected_duty != 0 && expected_duty != 100) {
631                         /* Duty cycle with 0 or 100 doesn't need frequency. */
632                         g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
633                                 ==, expected_freq);
634                     }
635 
636                     /* Test MFT's RPM is correct. */
637                     mft_verify_rpm(qts, td, expected_duty);
638 
639                     /* Test inverted mode */
640                     expected_duty = pwm_compute_duty(cnr, cmr, true);
641                     pwm_write_pcr(qts, td, pcr | CH_INV);
642                     g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
643                     g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
644                             ==, expected_duty);
645                     if (expected_duty != 0 && expected_duty != 100) {
646                         /* Duty cycle with 0 or 100 doesn't need frequency. */
647                         g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
648                                 ==, expected_freq);
649                     }
650 
651                 }
652             }
653         }
654     }
655 
656     qtest_quit(qts);
657 }
658 
659 static void pwm_add_test(const char *name, const TestData* td,
660         GTestDataFunc fn)
661 {
662     g_autofree char *full_name = g_strdup_printf(
663             "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
664             pwm_index(td->pwm), name);
665     qtest_add_data_func(full_name, td, fn);
666 }
667 #define add_test(name, td) pwm_add_test(#name, td, test_##name)
668 
669 int main(int argc, char **argv)
670 {
671     TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
672 
673     g_test_init(&argc, &argv, NULL);
674 
675     for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
676         for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
677             TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
678 
679             td->module = &pwm_module_list[i];
680             td->pwm = &pwm_list[j];
681 
682             add_test(init, td);
683             add_test(oneshot, td);
684             add_test(toggle, td);
685         }
686     }
687 
688     return g_test_run();
689 }
690