| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| |
| #include "test_gpio.h" |
| |
| static struct drv_data data; |
| static int cb_cnt; |
| |
| static void callback(const struct device *dev, |
| struct gpio_callback *gpio_cb, uint32_t pins) |
| { |
| const struct drv_data *dd = CONTAINER_OF(gpio_cb, |
| struct drv_data, gpio_cb); |
| |
| /*= checkpoint: pins should be marked with correct pin number bit =*/ |
| zassert_equal(pins, BIT(PIN_IN), |
| "unexpected pins %x", pins); |
| ++cb_cnt; |
| TC_PRINT("callback triggered: %d\n", cb_cnt); |
| if ((cb_cnt == 1) |
| && (dd->mode == GPIO_INT_EDGE_BOTH)) { |
| gpio_pin_toggle(dev, PIN_OUT); |
| } |
| if (cb_cnt >= MAX_INT_CNT) { |
| gpio_pin_set(dev, PIN_OUT, 0); |
| gpio_pin_interrupt_configure(dev, PIN_IN, GPIO_INT_DISABLE); |
| } |
| } |
| |
| static int test_callback(int mode) |
| { |
| const struct device *const dev = DEVICE_DT_GET(DEV); |
| struct drv_data *drv_data = &data; |
| |
| gpio_pin_interrupt_configure(dev, PIN_IN, GPIO_INT_DISABLE); |
| gpio_pin_interrupt_configure(dev, PIN_OUT, GPIO_INT_DISABLE); |
| |
| /* 1. set PIN_OUT to logical initial state inactive */ |
| uint32_t out_flags = GPIO_OUTPUT_LOW; |
| |
| if ((mode & GPIO_INT_LOW_0) != 0) { |
| out_flags = GPIO_OUTPUT_HIGH | GPIO_ACTIVE_LOW; |
| } |
| |
| int rc = gpio_pin_configure(dev, PIN_OUT, out_flags); |
| |
| if (rc != 0) { |
| TC_ERROR("PIN_OUT config fail: %d", rc); |
| return TC_FAIL; |
| } |
| |
| /* 2. configure PIN_IN callback and trigger condition */ |
| rc = gpio_pin_configure(dev, PIN_IN, GPIO_INPUT); |
| if (rc != 0) { |
| TC_ERROR("config PIN_IN fail: %d\n", rc); |
| goto err_exit; |
| } |
| |
| drv_data->mode = mode; |
| gpio_init_callback(&drv_data->gpio_cb, callback, BIT(PIN_IN)); |
| rc = gpio_add_callback(dev, &drv_data->gpio_cb); |
| if (rc == -ENOTSUP) { |
| TC_PRINT("interrupts not supported\n"); |
| return TC_PASS; |
| } else if (rc != 0) { |
| TC_ERROR("set PIN_IN callback fail: %d\n", rc); |
| return TC_FAIL; |
| } |
| |
| /* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */ |
| cb_cnt = 0; |
| rc = gpio_pin_interrupt_configure(dev, PIN_IN, mode); |
| if (rc == -ENOTSUP) { |
| TC_PRINT("Mode %x not supported\n", mode); |
| goto pass_exit; |
| } else if (rc != 0) { |
| TC_ERROR("config PIN_IN interrupt fail: %d\n", rc); |
| goto err_exit; |
| } |
| k_sleep(K_MSEC(100)); |
| gpio_pin_set(dev, PIN_OUT, 1); |
| k_sleep(K_MSEC(1000)); |
| (void)gpio_pin_interrupt_configure(dev, PIN_IN, GPIO_INT_DISABLE); |
| |
| /*= checkpoint: check callback is triggered =*/ |
| TC_PRINT("OUT init %x, IN cfg %x, cnt %d\n", out_flags, mode, cb_cnt); |
| if (mode == GPIO_INT_EDGE_BOTH) { |
| if (cb_cnt != 2) { |
| TC_ERROR("double edge not detected\n"); |
| goto err_exit; |
| } |
| goto pass_exit; |
| } |
| if ((mode & GPIO_INT_EDGE) == GPIO_INT_EDGE) { |
| if (cb_cnt != 1) { |
| TC_ERROR("edge not trigger callback correctly\n"); |
| goto err_exit; |
| } |
| goto pass_exit; |
| } else { |
| if (cb_cnt != MAX_INT_CNT) { |
| TC_ERROR("level not trigger callback correctly\n"); |
| goto err_exit; |
| } |
| } |
| |
| pass_exit: |
| gpio_remove_callback(dev, &drv_data->gpio_cb); |
| return TC_PASS; |
| |
| err_exit: |
| gpio_remove_callback(dev, &drv_data->gpio_cb); |
| return TC_FAIL; |
| } |
| |
| /* export test cases */ |
| ZTEST(gpio_port_cb_vari, test_gpio_callback_variants) |
| { |
| zassert_equal(test_callback(GPIO_INT_EDGE_FALLING), TC_PASS, |
| "falling edge failed"); |
| zassert_equal(test_callback(GPIO_INT_EDGE_RISING), TC_PASS, |
| "rising edge failed"); |
| zassert_equal(test_callback(GPIO_INT_EDGE_TO_ACTIVE), TC_PASS, |
| "edge active failed"); |
| zassert_equal(test_callback(GPIO_INT_EDGE_TO_INACTIVE), TC_PASS, |
| "edge inactive failed"); |
| zassert_equal(test_callback(GPIO_INT_LEVEL_HIGH), TC_PASS, |
| "level high failed"); |
| zassert_equal(test_callback(GPIO_INT_LEVEL_LOW), TC_PASS, |
| "level low failed"); |
| zassert_equal(test_callback(GPIO_INT_LEVEL_ACTIVE), TC_PASS, |
| "level active failed"); |
| zassert_equal(test_callback(GPIO_INT_LEVEL_INACTIVE), TC_PASS, |
| "level inactive failed"); |
| zassert_equal(test_callback(GPIO_INT_EDGE_BOTH), TC_PASS, |
| "edge both failed"); |
| } |