123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- /* drivers/gpio/gpio-msm-smp2p-test.c
- *
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/of_gpio.h>
- #include <linux/of_irq.h>
- #include <linux/gpio.h>
- #include <linux/debugfs.h>
- #include <linux/completion.h>
- #include <linux/interrupt.h>
- #include <linux/bitmap.h>
- #include "../soc/qcom/smp2p_private.h"
- #include "../soc/qcom/smp2p_test_common.h"
- /* Interrupt callback data */
- struct gpio_info {
- int gpio_base_id;
- int irq_base_id;
- bool initialized;
- struct completion cb_completion;
- int cb_count;
- DECLARE_BITMAP(triggered_irqs, SMP2P_BITS_PER_ENTRY);
- };
- /* GPIO Inbound/Outbound callback info */
- struct gpio_inout {
- struct gpio_info in;
- struct gpio_info out;
- };
- static struct gpio_inout gpio_info[SMP2P_NUM_PROCS];
- /**
- * Init/reset the callback data.
- *
- * @info: Pointer to callback data
- */
- static void cb_data_reset(struct gpio_info *info)
- {
- int n;
- if (!info)
- return;
- if (!info->initialized) {
- init_completion(&info->cb_completion);
- info->initialized = true;
- }
- info->cb_count = 0;
- for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n)
- clear_bit(n, info->triggered_irqs);
- reinit_completion(&info->cb_completion);
- }
- static int smp2p_gpio_test_probe(struct platform_device *pdev)
- {
- int id;
- int cnt;
- struct device_node *node = pdev->dev.of_node;
- struct gpio_info *gpio_info_ptr = NULL;
- /*
- * NOTE: This does a string-lookup of the GPIO pin name and doesn't
- * actually directly link to the SMP2P GPIO driver since all
- * GPIO/Interrupt access must be through standard
- * Linux GPIO / Interrupt APIs.
- */
- if (strcmp("qcom,smp2pgpio_test_smp2p_1_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_MODEM_PROC].in;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_1_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_MODEM_PROC].out;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_2_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_AUDIO_PROC].in;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_2_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_AUDIO_PROC].out;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_3_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_SENSOR_PROC].in;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_3_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_SENSOR_PROC].out;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_4_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].in;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_4_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].out;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_5_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].in;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_5_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].out;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_7_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_TZ_PROC].in;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_7_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_TZ_PROC].out;
- } else if (strcmp("qcom,smp2pgpio_test_smp2p_15_in", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
- } else if (
- strcmp("qcom,smp2pgpio_test_smp2p_15_out", node->name) == 0) {
- gpio_info_ptr = &gpio_info[SMP2P_REMOTE_MOCK_PROC].out;
- } else {
- pr_err("%s: unable to match device type '%s'\n",
- __func__, node->name);
- return -ENODEV;
- }
- /* retrieve the GPIO and interrupt ID's */
- cnt = of_gpio_count(node);
- if (cnt && gpio_info_ptr) {
- /*
- * Instead of looping through all 32-bits, we can just get the
- * first pin to get the base IDs. This saves on the verbosity
- * of the device tree nodes as well.
- */
- id = of_get_gpio(node, 0);
- if (id == -EPROBE_DEFER)
- return id;
- gpio_info_ptr->gpio_base_id = id;
- gpio_info_ptr->irq_base_id = gpio_to_irq(id);
- }
- return 0;
- }
- /*
- * NOTE: Instead of match table and device driver, you may be able to just
- * call of_find_compatible_node() in your init function.
- */
- static const struct of_device_id msm_smp2p_match_table[] = {
- /* modem */
- {.compatible = "qcom,smp2pgpio_test_smp2p_1_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_1_in", },
- /* audio (adsp) */
- {.compatible = "qcom,smp2pgpio_test_smp2p_2_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_2_in", },
- /* sensor */
- {.compatible = "qcom,smp2pgpio_test_smp2p_3_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_3_in", },
- /* wcnss */
- {.compatible = "qcom,smp2pgpio_test_smp2p_4_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_4_in", },
- /* CDSP */
- {.compatible = "qcom,smp2pgpio_test_smp2p_5_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_5_in", },
- /* TZ */
- {.compatible = "qcom,smp2pgpio_test_smp2p_7_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_7_in", },
- /* mock loopback */
- {.compatible = "qcom,smp2pgpio_test_smp2p_15_out", },
- {.compatible = "qcom,smp2pgpio_test_smp2p_15_in", },
- {},
- };
- static struct platform_driver smp2p_gpio_driver = {
- .probe = smp2p_gpio_test_probe,
- .driver = {
- .name = "smp2pgpio_test",
- .owner = THIS_MODULE,
- .of_match_table = msm_smp2p_match_table,
- },
- };
- /**
- * smp2p_ut_local_gpio_out - Verify outbound functionality.
- *
- * @s: pointer to output file
- */
- static void smp2p_ut_local_gpio_out(struct seq_file *s)
- {
- int failed = 0;
- struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].out;
- int ret;
- int id;
- struct msm_smp2p_remote_mock *mock;
- seq_printf(s, "Running %s\n", __func__);
- do {
- /* initialize mock edge */
- ret = smp2p_reset_mock_edge();
- UT_ASSERT_INT(ret, ==, 0);
- mock = msm_smp2p_get_remote_mock();
- UT_ASSERT_PTR(mock, !=, NULL);
- mock->rx_interrupt_count = 0;
- memset(&mock->remote_item, 0,
- sizeof(struct smp2p_smem_item));
- smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
- SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
- 0, 1);
- strlcpy(mock->remote_item.entries[0].name, "smp2p",
- SMP2P_MAX_ENTRY_NAME);
- SMP2P_SET_ENT_VALID(
- &mock->remote_item.header, valid_total_ent, 1);
- msm_smp2p_set_remote_mock_exists(true);
- mock->tx_interrupt();
- /* open GPIO entry */
- smp2p_gpio_open_test_entry("smp2p",
- SMP2P_REMOTE_MOCK_PROC, true);
- /* verify set/get functions */
- UT_ASSERT_INT(0, <, cb_info->gpio_base_id);
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- int pin = cb_info->gpio_base_id + id;
- mock->rx_interrupt_count = 0;
- gpio_set_value(pin, 1);
- UT_ASSERT_INT(1, ==, mock->rx_interrupt_count);
- UT_ASSERT_INT(1, ==, gpio_get_value(pin));
- gpio_set_value(pin, 0);
- UT_ASSERT_INT(2, ==, mock->rx_interrupt_count);
- UT_ASSERT_INT(0, ==, gpio_get_value(pin));
- }
- if (failed)
- break;
- seq_puts(s, "\tOK\n");
- } while (0);
- if (failed) {
- pr_err("%s: Failed\n", __func__);
- seq_puts(s, "\tFailed\n");
- }
- smp2p_gpio_open_test_entry("smp2p",
- SMP2P_REMOTE_MOCK_PROC, false);
- }
- /**
- * smp2p_gpio_irq - Interrupt handler for inbound entries.
- *
- * @irq: Virtual IRQ being triggered
- * @data: Cookie data (struct gpio_info * in this case)
- * @returns: Number of bytes written
- */
- static irqreturn_t smp2p_gpio_irq(int irq, void *data)
- {
- struct gpio_info *gpio_ptr = (struct gpio_info *)data;
- int offset;
- if (!gpio_ptr) {
- pr_err("%s: gpio_ptr is NULL for irq %d\n", __func__, irq);
- return IRQ_HANDLED;
- }
- offset = irq - gpio_ptr->irq_base_id;
- if (offset >= 0 && offset < SMP2P_BITS_PER_ENTRY)
- set_bit(offset, gpio_ptr->triggered_irqs);
- else
- pr_err("%s: invalid irq offset base %d; irq %d\n",
- __func__, gpio_ptr->irq_base_id, irq);
- ++gpio_ptr->cb_count;
- complete(&gpio_ptr->cb_completion);
- return IRQ_HANDLED;
- }
- /**
- * smp2p_ut_local_gpio_in - Verify inbound functionality.
- *
- * @s: pointer to output file
- */
- static void smp2p_ut_local_gpio_in(struct seq_file *s)
- {
- int failed = 0;
- struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
- int id;
- int ret;
- int virq;
- struct msm_smp2p_remote_mock *mock;
- seq_printf(s, "Running %s\n", __func__);
- cb_data_reset(cb_info);
- do {
- /* initialize mock edge */
- ret = smp2p_reset_mock_edge();
- UT_ASSERT_INT(ret, ==, 0);
- mock = msm_smp2p_get_remote_mock();
- UT_ASSERT_PTR(mock, !=, NULL);
- mock->rx_interrupt_count = 0;
- memset(&mock->remote_item, 0,
- sizeof(struct smp2p_smem_item));
- smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
- SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
- 0, 1);
- strlcpy(mock->remote_item.entries[0].name, "smp2p",
- SMP2P_MAX_ENTRY_NAME);
- SMP2P_SET_ENT_VALID(
- &mock->remote_item.header, valid_total_ent, 1);
- msm_smp2p_set_remote_mock_exists(true);
- mock->tx_interrupt();
- smp2p_gpio_open_test_entry("smp2p",
- SMP2P_REMOTE_MOCK_PROC, true);
- /* verify set/get functions locally */
- UT_ASSERT_INT(0, <, cb_info->gpio_base_id);
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- int pin;
- int current_value;
- /* verify pin value cannot be set */
- pin = cb_info->gpio_base_id + id;
- current_value = gpio_get_value(pin);
- gpio_set_value(pin, 0);
- UT_ASSERT_INT(current_value, ==, gpio_get_value(pin));
- gpio_set_value(pin, 1);
- UT_ASSERT_INT(current_value, ==, gpio_get_value(pin));
- /* verify no interrupts */
- UT_ASSERT_INT(0, ==, cb_info->cb_count);
- }
- if (failed)
- break;
- /* register for interrupts */
- UT_ASSERT_INT(0, <, cb_info->irq_base_id);
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- virq = cb_info->irq_base_id + id;
- UT_ASSERT_PTR(NULL, !=, irq_to_desc(virq));
- ret = request_irq(virq,
- smp2p_gpio_irq, IRQF_TRIGGER_RISING,
- "smp2p_test", cb_info);
- UT_ASSERT_INT(0, ==, ret);
- }
- if (failed)
- break;
- /* verify both rising and falling edge interrupts */
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- virq = cb_info->irq_base_id + id;
- irq_set_irq_type(virq, IRQ_TYPE_EDGE_BOTH);
- cb_data_reset(cb_info);
- /* verify rising-edge interrupt */
- mock->remote_item.entries[0].entry = 1 << id;
- mock->tx_interrupt();
- UT_ASSERT_INT(cb_info->cb_count, ==, 1);
- UT_ASSERT_INT(0, <,
- test_bit(id, cb_info->triggered_irqs));
- test_bit(id, cb_info->triggered_irqs);
- /* verify falling-edge interrupt */
- mock->remote_item.entries[0].entry = 0;
- mock->tx_interrupt();
- UT_ASSERT_INT(cb_info->cb_count, ==, 2);
- UT_ASSERT_INT(0, <,
- test_bit(id, cb_info->triggered_irqs));
- }
- if (failed)
- break;
- /* verify rising-edge interrupts */
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- virq = cb_info->irq_base_id + id;
- irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
- cb_data_reset(cb_info);
- /* verify only rising-edge interrupt is triggered */
- mock->remote_item.entries[0].entry = 1 << id;
- mock->tx_interrupt();
- UT_ASSERT_INT(cb_info->cb_count, ==, 1);
- UT_ASSERT_INT(0, <,
- test_bit(id, cb_info->triggered_irqs));
- test_bit(id, cb_info->triggered_irqs);
- mock->remote_item.entries[0].entry = 0;
- mock->tx_interrupt();
- UT_ASSERT_INT(cb_info->cb_count, ==, 1);
- UT_ASSERT_INT(0, <,
- test_bit(id, cb_info->triggered_irqs));
- }
- if (failed)
- break;
- /* verify falling-edge interrupts */
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- virq = cb_info->irq_base_id + id;
- irq_set_irq_type(virq, IRQ_TYPE_EDGE_FALLING);
- cb_data_reset(cb_info);
- /* verify only rising-edge interrupt is triggered */
- mock->remote_item.entries[0].entry = 1 << id;
- mock->tx_interrupt();
- UT_ASSERT_INT(cb_info->cb_count, ==, 0);
- UT_ASSERT_INT(0, ==,
- test_bit(id, cb_info->triggered_irqs));
- mock->remote_item.entries[0].entry = 0;
- mock->tx_interrupt();
- UT_ASSERT_INT(cb_info->cb_count, ==, 1);
- UT_ASSERT_INT(0, <,
- test_bit(id, cb_info->triggered_irqs));
- }
- if (failed)
- break;
- seq_puts(s, "\tOK\n");
- } while (0);
- if (failed) {
- pr_err("%s: Failed\n", __func__);
- seq_puts(s, "\tFailed\n");
- }
- /* unregister for interrupts */
- if (cb_info->irq_base_id) {
- for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
- free_irq(cb_info->irq_base_id + id, cb_info);
- }
- smp2p_gpio_open_test_entry("smp2p",
- SMP2P_REMOTE_MOCK_PROC, false);
- }
- /**
- * smp2p_ut_local_gpio_in_update_open - Verify combined open/update.
- *
- * @s: pointer to output file
- *
- * If the remote side updates the SMP2P bits and sends before negotiation is
- * complete, then the UPDATE event will have to be delayed until negotiation is
- * complete. This should result in both the OPEN and UPDATE events coming in
- * right after each other and the behavior should be transparent to the clients
- * of SMP2P GPIO.
- */
- static void smp2p_ut_local_gpio_in_update_open(struct seq_file *s)
- {
- int failed = 0;
- struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
- int id;
- int ret;
- int virq;
- struct msm_smp2p_remote_mock *mock;
- seq_printf(s, "Running %s\n", __func__);
- cb_data_reset(cb_info);
- do {
- /* initialize mock edge */
- ret = smp2p_reset_mock_edge();
- UT_ASSERT_INT(ret, ==, 0);
- mock = msm_smp2p_get_remote_mock();
- UT_ASSERT_PTR(mock, !=, NULL);
- mock->rx_interrupt_count = 0;
- memset(&mock->remote_item, 0,
- sizeof(struct smp2p_smem_item));
- smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
- SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
- 0, 1);
- strlcpy(mock->remote_item.entries[0].name, "smp2p",
- SMP2P_MAX_ENTRY_NAME);
- SMP2P_SET_ENT_VALID(
- &mock->remote_item.header, valid_total_ent, 1);
- /* register for interrupts */
- smp2p_gpio_open_test_entry("smp2p",
- SMP2P_REMOTE_MOCK_PROC, true);
- UT_ASSERT_INT(0, <, cb_info->irq_base_id);
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- virq = cb_info->irq_base_id + id;
- UT_ASSERT_PTR(NULL, !=, irq_to_desc(virq));
- ret = request_irq(virq,
- smp2p_gpio_irq, IRQ_TYPE_EDGE_BOTH,
- "smp2p_test", cb_info);
- UT_ASSERT_INT(0, ==, ret);
- }
- if (failed)
- break;
- /* update the state value and complete negotiation */
- mock->remote_item.entries[0].entry = 0xDEADDEAD;
- msm_smp2p_set_remote_mock_exists(true);
- mock->tx_interrupt();
- /* verify delayed state updates were processed */
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- virq = cb_info->irq_base_id + id;
- UT_ASSERT_INT(cb_info->cb_count, >, 0);
- if (0x1 & (0xDEADDEAD >> id)) {
- /* rising edge should have been triggered */
- if (!test_bit(id, cb_info->triggered_irqs)) {
- seq_printf(s, "%s:%d bit %d clear, ",
- __func__, __LINE__, id);
- seq_puts(s, "expected set\n");
- failed = 1;
- break;
- }
- } else {
- /* edge should not have been triggered */
- if (test_bit(id, cb_info->triggered_irqs)) {
- seq_printf(s, "%s:%d bit %d set, ",
- __func__, __LINE__, id);
- seq_puts(s, "expected clear\n");
- failed = 1;
- break;
- }
- }
- }
- if (failed)
- break;
- seq_puts(s, "\tOK\n");
- } while (0);
- if (failed) {
- pr_err("%s: Failed\n", __func__);
- seq_puts(s, "\tFailed\n");
- }
- /* unregister for interrupts */
- if (cb_info->irq_base_id) {
- for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
- free_irq(cb_info->irq_base_id + id, cb_info);
- }
- smp2p_gpio_open_test_entry("smp2p",
- SMP2P_REMOTE_MOCK_PROC, false);
- }
- /**
- * smp2p_gpio_write_bits - writes value to each GPIO pin specified in mask.
- *
- * @gpio: gpio test structure
- * @mask: 1 = write gpio_value to this GPIO pin
- * @gpio_value: value to write to GPIO pin
- */
- static void smp2p_gpio_write_bits(struct gpio_info *gpio, uint32_t mask,
- int gpio_value)
- {
- int n;
- for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n) {
- if (mask & 0x1)
- gpio_set_value(gpio->gpio_base_id + n, gpio_value);
- mask >>= 1;
- }
- }
- static void smp2p_gpio_set_bits(struct gpio_info *gpio, uint32_t mask)
- {
- smp2p_gpio_write_bits(gpio, mask, 1);
- }
- static void smp2p_gpio_clr_bits(struct gpio_info *gpio, uint32_t mask)
- {
- smp2p_gpio_write_bits(gpio, mask, 0);
- }
- /**
- * smp2p_gpio_get_value - reads entire 32-bits of GPIO
- *
- * @gpio: gpio structure
- * @returns: 32 bit value of GPIO pins
- */
- static uint32_t smp2p_gpio_get_value(struct gpio_info *gpio)
- {
- int n;
- uint32_t value = 0;
- for (n = 0; n < SMP2P_BITS_PER_ENTRY; ++n) {
- if (gpio_get_value(gpio->gpio_base_id + n))
- value |= 1 << n;
- }
- return value;
- }
- /**
- * smp2p_ut_remote_inout_core - Verify inbound/outbound functionality.
- *
- * @s: pointer to output file
- * @remote_pid: Remote processor to test
- * @name: Name of the test for reporting
- *
- * This test verifies inbound/outbound functionality for the remote processor.
- */
- static void smp2p_ut_remote_inout_core(struct seq_file *s, int remote_pid,
- const char *name)
- {
- int failed = 0;
- uint32_t request;
- uint32_t response;
- struct gpio_info *cb_in;
- struct gpio_info *cb_out;
- int id;
- int ret;
- seq_printf(s, "Running %s for '%s' remote pid %d\n",
- __func__, smp2p_pid_to_name(remote_pid), remote_pid);
- cb_in = &gpio_info[remote_pid].in;
- cb_out = &gpio_info[remote_pid].out;
- cb_data_reset(cb_in);
- cb_data_reset(cb_out);
- do {
- /* open test entries */
- msm_smp2p_deinit_rmt_lpb_proc(remote_pid);
- smp2p_gpio_open_test_entry("smp2p", remote_pid, true);
- /* register for interrupts */
- UT_ASSERT_INT(0, <, cb_in->gpio_base_id);
- UT_ASSERT_INT(0, <, cb_in->irq_base_id);
- for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
- int virq = cb_in->irq_base_id + id;
- UT_ASSERT_PTR(NULL, !=, irq_to_desc(virq));
- ret = request_irq(virq,
- smp2p_gpio_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "smp2p_test", cb_in);
- UT_ASSERT_INT(0, ==, ret);
- }
- if (failed)
- break;
- /* write echo of data value 0 */
- UT_ASSERT_INT(0, <, cb_out->gpio_base_id);
- request = 0x0;
- SMP2P_SET_RMT_CMD_TYPE(request, 1);
- SMP2P_SET_RMT_CMD(request, SMP2P_LB_CMD_ECHO);
- SMP2P_SET_RMT_DATA(request, 0x0);
- smp2p_gpio_set_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
- smp2p_gpio_clr_bits(cb_out, ~SMP2P_RMT_IGNORE_MASK);
- smp2p_gpio_set_bits(cb_out, request);
- UT_ASSERT_INT(cb_in->cb_count, ==, 0);
- smp2p_gpio_clr_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
- /* verify response */
- do {
- /* wait for up to 32 changes */
- if (wait_for_completion_timeout(
- &cb_in->cb_completion, HZ / 2) == 0)
- break;
- reinit_completion(&cb_in->cb_completion);
- } while (cb_in->cb_count < 32);
- UT_ASSERT_INT(cb_in->cb_count, >, 0);
- response = smp2p_gpio_get_value(cb_in);
- SMP2P_SET_RMT_CMD_TYPE(request, 0);
- UT_ASSERT_HEX(request, ==, response);
- /* write echo of data value of all 1's */
- request = 0x0;
- SMP2P_SET_RMT_CMD_TYPE(request, 1);
- SMP2P_SET_RMT_CMD(request, SMP2P_LB_CMD_ECHO);
- SMP2P_SET_RMT_DATA(request, ~0);
- smp2p_gpio_set_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
- cb_data_reset(cb_in);
- smp2p_gpio_clr_bits(cb_out, ~SMP2P_RMT_IGNORE_MASK);
- smp2p_gpio_set_bits(cb_out, request);
- UT_ASSERT_INT(cb_in->cb_count, ==, 0);
- smp2p_gpio_clr_bits(cb_out, SMP2P_RMT_IGNORE_MASK);
- /* verify response including 24 interrupts */
- do {
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_in->cb_completion, HZ / 2),
- >, 0);
- reinit_completion(&cb_in->cb_completion);
- } while (cb_in->cb_count < 24);
- response = smp2p_gpio_get_value(cb_in);
- SMP2P_SET_RMT_CMD_TYPE(request, 0);
- UT_ASSERT_HEX(request, ==, response);
- UT_ASSERT_INT(24, ==, cb_in->cb_count);
- seq_puts(s, "\tOK\n");
- } while (0);
- if (failed) {
- pr_err("%s: Failed\n", name);
- seq_puts(s, "\tFailed\n");
- }
- /* unregister for interrupts */
- if (cb_in->irq_base_id) {
- for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
- free_irq(cb_in->irq_base_id + id, cb_in);
- }
- smp2p_gpio_open_test_entry("smp2p", remote_pid, false);
- msm_smp2p_init_rmt_lpb_proc(remote_pid);
- }
- /**
- * smp2p_ut_remote_inout - Verify inbound/outbound functionality for all.
- *
- * @s: pointer to output file
- *
- * This test verifies inbound and outbound functionality for all
- * configured remote processor.
- */
- static void smp2p_ut_remote_inout(struct seq_file *s)
- {
- struct smp2p_interrupt_config *int_cfg;
- int pid;
- int_cfg = smp2p_get_interrupt_config();
- if (!int_cfg) {
- seq_puts(s, "Remote processor config unavailable\n");
- return;
- }
- for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
- if (!int_cfg[pid].is_configured)
- continue;
- smp2p_ut_remote_inout_core(s, pid, __func__);
- }
- }
- static int __init smp2p_debugfs_init(void)
- {
- /* register GPIO pins */
- (void)platform_driver_register(&smp2p_gpio_driver);
- /*
- * Add Unit Test entries.
- *
- * The idea with unit tests is that you can run all of them
- * from ADB shell by doing:
- * adb shell
- * cat ut*
- *
- * And if particular tests fail, you can then repeatedly run the
- * failing tests as you debug and resolve the failing test.
- */
- smp2p_debug_create("ut_local_gpio_out", smp2p_ut_local_gpio_out);
- smp2p_debug_create("ut_local_gpio_in", smp2p_ut_local_gpio_in);
- smp2p_debug_create("ut_local_gpio_in_update_open",
- smp2p_ut_local_gpio_in_update_open);
- smp2p_debug_create("ut_remote_gpio_inout", smp2p_ut_remote_inout);
- return 0;
- }
- late_initcall(smp2p_debugfs_init);
|