blob: 1f6f479e4f0bf8b8057d0501279aac23b4b982c9 [file] [log] [blame]
Eric Holmberg6275b602012-11-19 13:05:04 -07001/* arch/arm/mach-msm/smp2p_gpio_test.c
2 *
3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/of_gpio.h>
17#include <linux/of_irq.h>
18#include <linux/gpio.h>
19#include <linux/debugfs.h>
20#include <linux/completion.h>
21#include <linux/irq.h>
22#include <linux/bitmap.h>
23#include "smp2p_private.h"
24#include "smp2p_test_common.h"
25
26/* Interrupt callback data */
27struct gpio_info {
28 int gpio_base_id;
29 int irq_base_id;
30
31 bool initialized;
32 struct completion cb_completion;
33 int cb_count;
34 DECLARE_BITMAP(triggered_irqs, SMP2P_BITS_PER_ENTRY);
35};
36
37/* GPIO Inbound/Outbound callback info */
38struct gpio_inout {
39 struct gpio_info in;
40 struct gpio_info out;
41};
42
43static struct gpio_inout gpio_info[SMP2P_NUM_PROCS];
44
45/**
46 * Init/reset the callback data.
47 *
48 * @info: Pointer to callback data
49 */
50static void cb_data_reset(struct gpio_info *info)
51{
52 int n;
53
54 if (!info)
55 return;
56
57 if (!info->initialized) {
58 init_completion(&info->cb_completion);
59 info->initialized = true;
60 }
61 info->cb_count = 0;
62
63 for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n)
64 clear_bit(n, info->triggered_irqs);
65
66 INIT_COMPLETION(info->cb_completion);
67}
68
69static int __devinit smp2p_gpio_test_probe(struct platform_device *pdev)
70{
71 int id;
72 int cnt;
73 struct device_node *node = pdev->dev.of_node;
74 struct gpio_info *gpio_info_ptr = NULL;
75
76 /*
77 * NOTE: This does a string-lookup of the GPIO pin name and doesn't
78 * actually directly link to the SMP2P GPIO driver since all
79 * GPIO/Interrupt access must be through standard
80 * Linux GPIO / Interrupt APIs.
81 */
82 if (strcmp("qcom,smp2pgpio_test_smp2p_1_in", node->name) == 0) {
83 gpio_info_ptr = &gpio_info[SMP2P_MODEM_PROC].in;
84 } else if (strcmp("qcom,smp2pgpio_test_smp2p_1_out", node->name) == 0) {
85 gpio_info_ptr = &gpio_info[SMP2P_MODEM_PROC].out;
86 } else if (strcmp("qcom,smp2pgpio_test_smp2p_2_in", node->name) == 0) {
87 gpio_info_ptr = &gpio_info[SMP2P_AUDIO_PROC].in;
88 } else if (strcmp("qcom,smp2pgpio_test_smp2p_2_out", node->name) == 0) {
89 gpio_info_ptr = &gpio_info[SMP2P_AUDIO_PROC].out;
90 } else if (strcmp("qcom,smp2pgpio_test_smp2p_4_in", node->name) == 0) {
91 gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].in;
92 } else if (strcmp("qcom,smp2pgpio_test_smp2p_4_out", node->name) == 0) {
93 gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].out;
94 } else if (strcmp("qcom,smp2pgpio_test_smp2p_7_in", node->name) == 0) {
95 gpio_info_ptr = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
96 } else if (strcmp("qcom,smp2pgpio_test_smp2p_7_out", node->name) == 0) {
97 gpio_info_ptr = &gpio_info[SMP2P_REMOTE_MOCK_PROC].out;
98 } else {
99 pr_err("%s: unable to match device type '%s'\n",
100 __func__, node->name);
101 return -ENODEV;
102 }
103
104 /* retrieve the GPIO and interrupt ID's */
105 cnt = of_gpio_count(node);
106 if (cnt && gpio_info_ptr) {
107 /*
108 * Instead of looping through all 32-bits, we can just get the
109 * first pin to get the base IDs. This saves on the verbosity
110 * of the device tree nodes as well.
111 */
112 id = of_get_gpio(node, 0);
113 gpio_info_ptr->gpio_base_id = id;
114 gpio_info_ptr->irq_base_id = gpio_to_irq(id);
115 }
116 return 0;
117}
118
119/*
120 * NOTE: Instead of match table and device driver, you may be able to just
121 * call of_find_compatible_node() in your init function.
122 */
123static struct of_device_id msm_smp2p_match_table[] __devinitdata = {
124 /* modem */
125 {.compatible = "qcom,smp2pgpio_test_smp2p_1_out", },
126 {.compatible = "qcom,smp2pgpio_test_smp2p_1_in", },
127
128 /* audio (adsp) */
129 {.compatible = "qcom,smp2pgpio_test_smp2p_2_out", },
130 {.compatible = "qcom,smp2pgpio_test_smp2p_2_in", },
131
132 /* wcnss */
133 {.compatible = "qcom,smp2pgpio_test_smp2p_4_out", },
134 {.compatible = "qcom,smp2pgpio_test_smp2p_4_in", },
135
136 /* mock loopback */
137 {.compatible = "qcom,smp2pgpio_test_smp2p_7_out", },
138 {.compatible = "qcom,smp2pgpio_test_smp2p_7_in", },
139 {},
140};
141
142static struct platform_driver smp2p_gpio_driver = {
143 .probe = smp2p_gpio_test_probe,
144 .driver = {
145 .name = "smp2pgpio_test",
146 .owner = THIS_MODULE,
147 .of_match_table = msm_smp2p_match_table,
148 },
149};
150
151/**
152 * smp2p_ut_local_gpio_out - Verify outbound functionality.
153 *
154 * @s: pointer to output file
155 */
156static void smp2p_ut_local_gpio_out(struct seq_file *s)
157{
158 int failed = 0;
159 struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].out;
160 int ret;
161 int id;
162 struct msm_smp2p_remote_mock *mock;
163
164 seq_printf(s, "Running %s\n", __func__);
165 do {
166 /* initialize mock edge */
167 ret = smp2p_reset_mock_edge();
168 UT_ASSERT_INT(ret, ==, 0);
169
170 mock = msm_smp2p_get_remote_mock();
171 UT_ASSERT_PTR(mock, !=, NULL);
172
173 mock->rx_interrupt_count = 0;
174 memset(&mock->remote_item, 0,
175 sizeof(struct smp2p_smem_item));
176 smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
177 SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
178 0, 1);
179 strlcpy(mock->remote_item.entries[0].name, "smp2p",
180 SMP2P_MAX_ENTRY_NAME);
181 SMP2P_SET_ENT_VALID(
182 mock->remote_item.header.valid_total_ent, 1);
183 msm_smp2p_set_remote_mock_exists(true);
184 mock->tx_interrupt();
185
186 /* open GPIO entry */
187 smp2p_gpio_open_test_entry("smp2p",
188 SMP2P_REMOTE_MOCK_PROC, true);
189
190 /* verify set/get functions */
191 UT_ASSERT_INT(0, <, cb_info->gpio_base_id);
192 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
193 int pin = cb_info->gpio_base_id + id;
194
195 mock->rx_interrupt_count = 0;
196 gpio_set_value(pin, 1);
197 UT_ASSERT_INT(1, ==, mock->rx_interrupt_count);
198 UT_ASSERT_INT(1, ==, gpio_get_value(pin));
199
200 gpio_set_value(pin, 0);
201 UT_ASSERT_INT(2, ==, mock->rx_interrupt_count);
202 UT_ASSERT_INT(0, ==, gpio_get_value(pin));
203 }
204 if (failed)
205 break;
206
207 seq_printf(s, "\tOK\n");
208 } while (0);
209
210 if (failed) {
211 pr_err("%s: Failed\n", __func__);
212 seq_printf(s, "\tFailed\n");
213 }
214
215 smp2p_gpio_open_test_entry("smp2p",
216 SMP2P_REMOTE_MOCK_PROC, false);
217}
218
219/**
220 * smp2p_gpio_irq - Interrupt handler for inbound entries.
221 *
222 * @irq: Virtual IRQ being triggered
223 * @data: Cookie data (struct gpio_info * in this case)
224 * @returns: Number of bytes written
225 */
226static irqreturn_t smp2p_gpio_irq(int irq, void *data)
227{
228 struct gpio_info *gpio_ptr = (struct gpio_info *)data;
229 int offset;
230
231 if (!gpio_ptr) {
232 pr_err("%s: gpio_ptr is NULL for irq %d\n", __func__, irq);
233 return IRQ_HANDLED;
234 }
235
236 offset = irq - gpio_ptr->irq_base_id;
237 if (offset >= 0 && offset < SMP2P_BITS_PER_ENTRY)
238 set_bit(offset, gpio_ptr->triggered_irqs);
239 else
240 pr_err("%s: invalid irq offset base %d; irq %d\n",
241 __func__, gpio_ptr->irq_base_id, irq);
242
243 ++gpio_ptr->cb_count;
244 complete(&gpio_ptr->cb_completion);
245 return IRQ_HANDLED;
246}
247
248/**
249 * smp2p_ut_local_gpio_in - Verify inbound functionality.
250 *
251 * @s: pointer to output file
252 */
253static void smp2p_ut_local_gpio_in(struct seq_file *s)
254{
255 int failed = 0;
256 struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
257 int id;
258 int ret;
259 int virq;
260 struct msm_smp2p_remote_mock *mock;
261
262 seq_printf(s, "Running %s\n", __func__);
263
264 cb_data_reset(cb_info);
265 do {
266 /* initialize mock edge */
267 ret = smp2p_reset_mock_edge();
268 UT_ASSERT_INT(ret, ==, 0);
269
270 mock = msm_smp2p_get_remote_mock();
271 UT_ASSERT_PTR(mock, !=, NULL);
272
273 mock->rx_interrupt_count = 0;
274 memset(&mock->remote_item, 0,
275 sizeof(struct smp2p_smem_item));
276 smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
277 SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
278 0, 1);
279 strlcpy(mock->remote_item.entries[0].name, "smp2p",
280 SMP2P_MAX_ENTRY_NAME);
281 SMP2P_SET_ENT_VALID(
282 mock->remote_item.header.valid_total_ent, 1);
283 msm_smp2p_set_remote_mock_exists(true);
284 mock->tx_interrupt();
285
286 smp2p_gpio_open_test_entry("smp2p",
287 SMP2P_REMOTE_MOCK_PROC, true);
288
289 /* verify set/get functions locally */
290 UT_ASSERT_INT(0, <, cb_info->gpio_base_id);
291 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
292 int pin;
293 int current_value;
294
295 /* verify pin value cannot be set */
296 pin = cb_info->gpio_base_id + id;
297 current_value = gpio_get_value(pin);
298
299 gpio_set_value(pin, 0);
300 UT_ASSERT_INT(current_value, ==, gpio_get_value(pin));
301 gpio_set_value(pin, 1);
302 UT_ASSERT_INT(current_value, ==, gpio_get_value(pin));
303
304 /* verify no interrupts */
305 UT_ASSERT_INT(0, ==, cb_info->cb_count);
306 }
307 if (failed)
308 break;
309
310 /* register for interrupts */
311 UT_ASSERT_INT(0, <, cb_info->irq_base_id);
312 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
313 virq = cb_info->irq_base_id + id;
314 UT_ASSERT_INT(0, >, (unsigned int)irq_to_desc(virq));
315 ret = request_irq(virq,
316 smp2p_gpio_irq, IRQF_TRIGGER_RISING,
317 "smp2p_test", cb_info);
318 UT_ASSERT_INT(0, ==, ret);
319 }
320 if (failed)
321 break;
322
323 /* verify both rising and falling edge interrupts */
324 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
325 virq = cb_info->irq_base_id + id;
326 irq_set_irq_type(virq, IRQ_TYPE_EDGE_BOTH);
327 cb_data_reset(cb_info);
328
329 /* verify rising-edge interrupt */
330 mock->remote_item.entries[0].entry = 1 << id;
331 mock->tx_interrupt();
332 UT_ASSERT_INT(cb_info->cb_count, ==, 1);
333 UT_ASSERT_INT(0, <,
334 test_bit(id, cb_info->triggered_irqs));
335 test_bit(id, cb_info->triggered_irqs);
336
337 /* verify falling-edge interrupt */
338 mock->remote_item.entries[0].entry = 0;
339 mock->tx_interrupt();
340 UT_ASSERT_INT(cb_info->cb_count, ==, 2);
341 UT_ASSERT_INT(0, <,
342 test_bit(id, cb_info->triggered_irqs));
343 }
344 if (failed)
345 break;
346
347 /* verify rising-edge interrupts */
348 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
349 virq = cb_info->irq_base_id + id;
350 irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
351 cb_data_reset(cb_info);
352
353 /* verify only rising-edge interrupt is triggered */
354 mock->remote_item.entries[0].entry = 1 << id;
355 mock->tx_interrupt();
356 UT_ASSERT_INT(cb_info->cb_count, ==, 1);
357 UT_ASSERT_INT(0, <,
358 test_bit(id, cb_info->triggered_irqs));
359 test_bit(id, cb_info->triggered_irqs);
360
361 mock->remote_item.entries[0].entry = 0;
362 mock->tx_interrupt();
363 UT_ASSERT_INT(cb_info->cb_count, ==, 1);
364 UT_ASSERT_INT(0, <,
365 test_bit(id, cb_info->triggered_irqs));
366 }
367 if (failed)
368 break;
369
370 /* verify falling-edge interrupts */
371 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
372 virq = cb_info->irq_base_id + id;
373 irq_set_irq_type(virq, IRQ_TYPE_EDGE_FALLING);
374 cb_data_reset(cb_info);
375
376 /* verify only rising-edge interrupt is triggered */
377 mock->remote_item.entries[0].entry = 1 << id;
378 mock->tx_interrupt();
379 UT_ASSERT_INT(cb_info->cb_count, ==, 0);
380 UT_ASSERT_INT(0, ==,
381 test_bit(id, cb_info->triggered_irqs));
382
383 mock->remote_item.entries[0].entry = 0;
384 mock->tx_interrupt();
385 UT_ASSERT_INT(cb_info->cb_count, ==, 1);
386 UT_ASSERT_INT(0, <,
387 test_bit(id, cb_info->triggered_irqs));
388 }
389 if (failed)
390 break;
391
392 seq_printf(s, "\tOK\n");
393 } while (0);
394
395 if (failed) {
396 pr_err("%s: Failed\n", __func__);
397 seq_printf(s, "\tFailed\n");
398 }
399
400 /* unregister for interrupts */
401 if (cb_info->irq_base_id) {
402 for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
403 free_irq(cb_info->irq_base_id + id, cb_info);
404 }
405
406 smp2p_gpio_open_test_entry("smp2p",
407 SMP2P_REMOTE_MOCK_PROC, false);
408}
409
410/**
Eric Holmberg5b6219b2013-01-24 19:17:45 -0700411 * smp2p_ut_local_gpio_in_update_open - Verify combined open/update.
412 *
413 * @s: pointer to output file
414 *
415 * If the remote side updates the SMP2P bits and sends before negotiation is
416 * complete, then the UPDATE event will have to be delayed until negotiation is
417 * complete. This should result in both the OPEN and UPDATE events coming in
418 * right after each other and the behavior should be transparent to the clients
419 * of SMP2P GPIO.
420 */
421static void smp2p_ut_local_gpio_in_update_open(struct seq_file *s)
422{
423 int failed = 0;
424 struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
425 int id;
426 int ret;
427 int virq;
428 struct msm_smp2p_remote_mock *mock;
429
430 seq_printf(s, "Running %s\n", __func__);
431
432 cb_data_reset(cb_info);
433 do {
434 /* initialize mock edge */
435 ret = smp2p_reset_mock_edge();
436 UT_ASSERT_INT(ret, ==, 0);
437
438 mock = msm_smp2p_get_remote_mock();
439 UT_ASSERT_PTR(mock, !=, NULL);
440
441 mock->rx_interrupt_count = 0;
442 memset(&mock->remote_item, 0,
443 sizeof(struct smp2p_smem_item));
444 smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
445 SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
446 0, 1);
447 strlcpy(mock->remote_item.entries[0].name, "smp2p",
448 SMP2P_MAX_ENTRY_NAME);
449 SMP2P_SET_ENT_VALID(
450 mock->remote_item.header.valid_total_ent, 1);
451
452 /* register for interrupts */
453 smp2p_gpio_open_test_entry("smp2p",
454 SMP2P_REMOTE_MOCK_PROC, true);
455
456 UT_ASSERT_INT(0, <, cb_info->irq_base_id);
457 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
458 virq = cb_info->irq_base_id + id;
459 UT_ASSERT_INT(0, >, (unsigned int)irq_to_desc(virq));
460 ret = request_irq(virq,
461 smp2p_gpio_irq, IRQ_TYPE_EDGE_BOTH,
462 "smp2p_test", cb_info);
463 UT_ASSERT_INT(0, ==, ret);
464 }
465 if (failed)
466 break;
467
468 /* update the state value and complete negotiation */
469 mock->remote_item.entries[0].entry = 0xDEADDEAD;
470 msm_smp2p_set_remote_mock_exists(true);
471 mock->tx_interrupt();
472
473 /* verify delayed state updates were processed */
474 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
475 virq = cb_info->irq_base_id + id;
476
477 UT_ASSERT_INT(cb_info->cb_count, >, 0);
478 if (0x1 & (0xDEADDEAD >> id)) {
479 /* rising edge should have been triggered */
480 if (!test_bit(id, cb_info->triggered_irqs)) {
481 seq_printf(s,
482 "%s:%d bit %d clear, expected set\n",
483 __func__, __LINE__, id);
484 failed = 1;
485 break;
486 }
487 } else {
488 /* edge should not have been triggered */
489 if (test_bit(id, cb_info->triggered_irqs)) {
490 seq_printf(s,
491 "%s:%d bit %d set, expected clear\n",
492 __func__, __LINE__, id);
493 failed = 1;
494 break;
495 }
496 }
497 }
498 if (failed)
499 break;
500
501 seq_printf(s, "\tOK\n");
502 } while (0);
503
504 if (failed) {
505 pr_err("%s: Failed\n", __func__);
506 seq_printf(s, "\tFailed\n");
507 }
508
509 /* unregister for interrupts */
510 if (cb_info->irq_base_id) {
511 for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
512 free_irq(cb_info->irq_base_id + id, cb_info);
513 }
514
515 smp2p_gpio_open_test_entry("smp2p",
516 SMP2P_REMOTE_MOCK_PROC, false);
517}
518
519/**
Eric Holmberg6275b602012-11-19 13:05:04 -0700520 * smp2p_gpio_write_bits - writes value to each GPIO pin specified in mask.
521 *
522 * @gpio: gpio test structure
523 * @mask: 1 = write gpio_value to this GPIO pin
524 * @gpio_value: value to write to GPIO pin
525 */
526static void smp2p_gpio_write_bits(struct gpio_info *gpio, uint32_t mask,
527 int gpio_value)
528{
529 int n;
530
531 for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n) {
532 if (mask & 0x1)
533 gpio_set_value(gpio->gpio_base_id + n, gpio_value);
534 mask >>= 1;
535 }
536}
537
538static void smp2p_gpio_set_bits(struct gpio_info *gpio, uint32_t mask)
539{
540 smp2p_gpio_write_bits(gpio, mask, 1);
541}
542
543static void smp2p_gpio_clr_bits(struct gpio_info *gpio, uint32_t mask)
544{
545 smp2p_gpio_write_bits(gpio, mask, 0);
546}
547
548/**
549 * smp2p_gpio_get_value - reads entire 32-bits of GPIO
550 *
551 * @gpio: gpio structure
552 * @returns: 32 bit value of GPIO pins
553 */
554static uint32_t smp2p_gpio_get_value(struct gpio_info *gpio)
555{
556 int n;
557 uint32_t value = 0;
558
559 for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n) {
560 if (gpio_get_value(gpio->gpio_base_id + n))
561 value |= 1 << n;
562 }
563 return value;
564}
565
566/**
567 * smp2p_ut_remote_inout_core - Verify inbound/outbound functionality.
568 *
569 * @s: pointer to output file
570 * @remote_pid: Remote processor to test
571 * @name: Name of the test for reporting
572 *
573 * This test verifies inbound/outbound functionality for the remote processor.
574 */
575static void smp2p_ut_remote_inout_core(struct seq_file *s, int remote_pid,
576 const char *name)
577{
578 int failed = 0;
579 uint32_t request;
580 uint32_t response;
581 struct gpio_info *cb_in;
582 struct gpio_info *cb_out;
583 int id;
584 int ret;
585
586 seq_printf(s, "Running %s for '%s' remote pid %d\n",
587 __func__, smp2p_pid_to_name(remote_pid), remote_pid);
588
589 cb_in = &gpio_info[remote_pid].in;
590 cb_out = &gpio_info[remote_pid].out;
591 cb_data_reset(cb_in);
592 cb_data_reset(cb_out);
593 do {
594 /* open test entries */
595 msm_smp2p_deinit_rmt_lpb_proc(remote_pid);
596 smp2p_gpio_open_test_entry("smp2p", remote_pid, true);
597
598 /* register for interrupts */
599 UT_ASSERT_INT(0, <, cb_in->gpio_base_id);
600 UT_ASSERT_INT(0, <, cb_in->irq_base_id);
601 for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
602 int virq = cb_in->irq_base_id + id;
603 UT_ASSERT_INT(0, >, (unsigned int)irq_to_desc(virq));
604 ret = request_irq(virq,
605 smp2p_gpio_irq,
606 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
607 "smp2p_test", cb_in);
608 UT_ASSERT_INT(0, ==, ret);
609 }
610 if (failed)
611 break;
612
613 /* write echo of data value 0 */
614 UT_ASSERT_INT(0, <, cb_out->gpio_base_id);
615 request = 0x0;
616 SMP2P_SET_RMT_CMD_TYPE(request, 1);
617 SMP2P_SET_RMT_CMD(request, SMP2P_LB_CMD_ECHO);
618 SMP2P_SET_RMT_DATA(request, 0x0);
619
620 smp2p_gpio_set_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
621 smp2p_gpio_clr_bits(cb_out, ~SMP2P_RMT_IGNORE_MASK);
622 smp2p_gpio_set_bits(cb_out, request);
623
624 UT_ASSERT_INT(cb_in->cb_count, ==, 0);
625 smp2p_gpio_clr_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
626
627 /* verify response */
628 do {
629 /* wait for up to 32 changes */
630 if (wait_for_completion_timeout(
631 &cb_in->cb_completion, HZ / 2) == 0)
632 break;
633 INIT_COMPLETION(cb_in->cb_completion);
634 } while (cb_in->cb_count < 32);
635 UT_ASSERT_INT(cb_in->cb_count, >, 0);
636 response = smp2p_gpio_get_value(cb_in);
637 SMP2P_SET_RMT_CMD_TYPE(request, 0);
638 UT_ASSERT_HEX(request, ==, response);
639
640 /* write echo of data value of all 1's */
641 request = 0x0;
642 SMP2P_SET_RMT_CMD_TYPE(request, 1);
643 SMP2P_SET_RMT_CMD(request, SMP2P_LB_CMD_ECHO);
644 SMP2P_SET_RMT_DATA(request, ~0);
645
646 smp2p_gpio_set_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
647 cb_data_reset(cb_in);
648 smp2p_gpio_clr_bits(cb_out, ~SMP2P_RMT_IGNORE_MASK);
649 smp2p_gpio_set_bits(cb_out, request);
650
651 UT_ASSERT_INT(cb_in->cb_count, ==, 0);
652 smp2p_gpio_clr_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
653
654 /* verify response including 24 interrupts */
655 do {
656 UT_ASSERT_INT(
657 (int)wait_for_completion_timeout(
658 &cb_in->cb_completion, HZ / 2),
659 >, 0);
660 INIT_COMPLETION(cb_in->cb_completion);
661 } while (cb_in->cb_count < 24);
662 response = smp2p_gpio_get_value(cb_in);
663 SMP2P_SET_RMT_CMD_TYPE(request, 0);
664 UT_ASSERT_HEX(request, ==, response);
665 UT_ASSERT_INT(24, ==, cb_in->cb_count);
666
667 seq_printf(s, "\tOK\n");
668 } while (0);
669
670 if (failed) {
671 pr_err("%s: Failed\n", name);
672 seq_printf(s, "\tFailed\n");
673 }
674
675 /* unregister for interrupts */
676 if (cb_in->irq_base_id) {
677 for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
678 free_irq(cb_in->irq_base_id + id, cb_in);
679 }
680
681 smp2p_gpio_open_test_entry("smp2p", remote_pid, false);
682 msm_smp2p_init_rmt_lpb_proc(remote_pid);
683}
684
685/**
686 * smp2p_ut_remote_inout - Verify inbound/outbound functionality for all.
687 *
688 * @s: pointer to output file
689 *
690 * This test verifies inbound and outbound functionality for all
691 * configured remote processor.
692 */
693static void smp2p_ut_remote_inout(struct seq_file *s)
694{
695 struct smp2p_interrupt_config *int_cfg;
696 int pid;
697
698 int_cfg = smp2p_get_interrupt_config();
699 if (!int_cfg) {
700 seq_printf(s, "Remote processor config unavailable\n");
701 return;
702 }
703
704 for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
705 if (!int_cfg[pid].is_configured)
706 continue;
707
708 smp2p_ut_remote_inout_core(s, pid, __func__);
709 }
710}
711
712static int __init smp2p_debugfs_init(void)
713{
714 /* register GPIO pins */
715 (void)platform_driver_register(&smp2p_gpio_driver);
716
717 /*
718 * Add Unit Test entries.
719 *
720 * The idea with unit tests is that you can run all of them
721 * from ADB shell by doing:
722 * adb shell
723 * cat ut*
724 *
725 * And if particular tests fail, you can then repeatedly run the
726 * failing tests as you debug and resolve the failing test.
727 */
728 smp2p_debug_create("ut_local_gpio_out", smp2p_ut_local_gpio_out);
729 smp2p_debug_create("ut_local_gpio_in", smp2p_ut_local_gpio_in);
Eric Holmberg5b6219b2013-01-24 19:17:45 -0700730 smp2p_debug_create("ut_local_gpio_in_update_open",
731 smp2p_ut_local_gpio_in_update_open);
Eric Holmberg6275b602012-11-19 13:05:04 -0700732 smp2p_debug_create("ut_remote_gpio_inout", smp2p_ut_remote_inout);
733 return 0;
734}
735late_initcall(smp2p_debugfs_init);