tests: drivers: clock_control: Add test suite
Added test suite for clock control driver. It covers latest API update for starting clock asynchronously and getting status. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
6700f2f194
commit
488d74f125
5 changed files with 336 additions and 0 deletions
|
@ -0,0 +1,9 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13.1)
|
||||||
|
|
||||||
|
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
||||||
|
project(NONE)
|
||||||
|
|
||||||
|
FILE(GLOB app_sources src/*.c)
|
||||||
|
target_sources(app PRIVATE ${app_sources})
|
|
@ -0,0 +1,2 @@
|
||||||
|
CONFIG_ZTEST=y
|
||||||
|
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
|
1
tests/drivers/clock_control/clock_control_api/prj.conf
Normal file
1
tests/drivers/clock_control/clock_control_api/prj.conf
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CONFIG_ZTEST=y
|
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <ztest.h>
|
||||||
|
#include <clock_control.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(test);
|
||||||
|
|
||||||
|
#ifdef DT_INST_0_NORDIC_NRF_CLOCK_LABEL
|
||||||
|
#include <drivers/clock_control/nrf_clock_control.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct device_data {
|
||||||
|
const char *name;
|
||||||
|
u32_t startup_us;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct device_data devices[] = {
|
||||||
|
#ifdef DT_INST_0_NORDIC_NRF_CLOCK_LABEL
|
||||||
|
{
|
||||||
|
.name = DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_16M",
|
||||||
|
.startup_us = IS_ENABLED(CONFIG_SOC_SERIES_NRF91X) ? 3000 : 400
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_32K",
|
||||||
|
.startup_us = (CLOCK_CONTROL_NRF_K32SRC == NRF_CLOCK_LFCLK_RC) ?
|
||||||
|
1000 : 300000
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*test_func_t)(const char *dev_name, u32_t startup_us);
|
||||||
|
|
||||||
|
typedef bool (*test_capability_check_t)(const char *dev_name);
|
||||||
|
|
||||||
|
static void setup_instance(const char *dev_name)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
k_busy_wait(1000);
|
||||||
|
do {
|
||||||
|
err = clock_control_off(dev, 0);
|
||||||
|
} while (err == 0);
|
||||||
|
LOG_INF("setup done");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tear_down_instance(const char *dev_name)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
|
||||||
|
clock_control_on(dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_all_instances(test_func_t func,
|
||||||
|
test_capability_check_t capability_check)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(devices); i++) {
|
||||||
|
if ((capability_check == NULL) ||
|
||||||
|
capability_check(devices[i].name)) {
|
||||||
|
setup_instance(devices[i].name);
|
||||||
|
func(devices[i].name, devices[i].startup_us);
|
||||||
|
tear_down_instance(devices[i].name);
|
||||||
|
/* Allow logs to be printed. */
|
||||||
|
k_sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic test for checking correctness of getting clock status.
|
||||||
|
*/
|
||||||
|
static void test_on_off_status_instance(const char *dev_name, u32_t startup_us)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
enum clock_control_status status;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
zassert_true(dev != NULL, "%s: Unknown device", dev_name);
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
|
||||||
|
err = clock_control_on(dev, NULL);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_true((status == CLOCK_CONTROL_STATUS_STARTING) ||
|
||||||
|
(status == CLOCK_CONTROL_STATUS_ON),
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
k_busy_wait(startup_us);
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_ON, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
err = clock_control_off(dev, 0);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_on_off_status(void)
|
||||||
|
{
|
||||||
|
test_all_instances(test_on_off_status_instance, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test validates that if number of enabling requests matches disabling requests
|
||||||
|
* then clock is disabled.
|
||||||
|
*/
|
||||||
|
static void test_multiple_users_instance(const char *dev_name, u32_t startup_us)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
enum clock_control_status status;
|
||||||
|
int users = 5;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
for (int i = 0; i < users; i++) {
|
||||||
|
err = clock_control_on(dev, NULL);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_true((status == CLOCK_CONTROL_STATUS_STARTING) ||
|
||||||
|
(status == CLOCK_CONTROL_STATUS_ON),
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
for (int i = 0; i < users; i++) {
|
||||||
|
err = clock_control_off(dev, 0);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_true(status == CLOCK_CONTROL_STATUS_OFF,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
err = clock_control_off(dev, 0);
|
||||||
|
zassert_equal(-EALREADY, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_multiple_users(void)
|
||||||
|
{
|
||||||
|
test_all_instances(test_multiple_users_instance, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool async_capable(const char *dev_name)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
|
||||||
|
if (clock_control_async_on(dev, 0, NULL) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_control_off(dev, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test checks that callbacks are called after clock is started.
|
||||||
|
*/
|
||||||
|
static void clock_on_callback(struct device *dev, void *user_data)
|
||||||
|
{
|
||||||
|
bool *executed = (bool *)user_data;
|
||||||
|
|
||||||
|
*executed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_async_on_instance(const char *dev_name, u32_t startup_us)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
enum clock_control_status status;
|
||||||
|
int err;
|
||||||
|
bool executed1 = false;
|
||||||
|
bool executed2 = false;
|
||||||
|
struct clock_control_async_data data1 = {
|
||||||
|
.cb = clock_on_callback,
|
||||||
|
.user_data = &executed1
|
||||||
|
};
|
||||||
|
struct clock_control_async_data data2 = {
|
||||||
|
.cb = clock_on_callback,
|
||||||
|
.user_data = &executed2
|
||||||
|
};
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
err = clock_control_async_on(dev, 0, &data1);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
err = clock_control_async_on(dev, 0, &data2);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
/* wait for clock started. */
|
||||||
|
k_busy_wait(startup_us);
|
||||||
|
|
||||||
|
zassert_true(executed1, "%s: Expected flag to be true", dev_name);
|
||||||
|
zassert_true(executed2, "%s: Expected flag to be true", dev_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_async_on(void)
|
||||||
|
{
|
||||||
|
test_all_instances(test_async_on_instance, async_capable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test checks that when asynchronous clock enabling is scheduled but clock
|
||||||
|
* is disabled before being started then callback is never called.
|
||||||
|
*/
|
||||||
|
static void test_async_on_stopped_on_instance(const char *dev_name,
|
||||||
|
u32_t startup_us)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
enum clock_control_status status;
|
||||||
|
int err;
|
||||||
|
int key;
|
||||||
|
bool executed1 = false;
|
||||||
|
struct clock_control_async_data data1 = {
|
||||||
|
.cb = clock_on_callback,
|
||||||
|
.user_data = &executed1
|
||||||
|
};
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
/* lock to prevent clock interrupt for fast starting clocks.*/
|
||||||
|
key = irq_lock();
|
||||||
|
err = clock_control_async_on(dev, 0, &data1);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
err = clock_control_off(dev, 0);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
k_busy_wait(10000);
|
||||||
|
|
||||||
|
zassert_false(executed1, "%s: Expected flag to be false", dev_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_async_on_stopped(void)
|
||||||
|
{
|
||||||
|
test_all_instances(test_async_on_stopped_on_instance, async_capable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test checks that when asynchronous clock enabling is called when clock is
|
||||||
|
* running then callback is immediate.
|
||||||
|
*/
|
||||||
|
static void test_immediate_cb_when_clock_on_on_instance(const char *dev_name,
|
||||||
|
u32_t startup_us)
|
||||||
|
{
|
||||||
|
struct device *dev = device_get_binding(dev_name);
|
||||||
|
enum clock_control_status status;
|
||||||
|
int err;
|
||||||
|
bool executed1 = false;
|
||||||
|
struct clock_control_async_data data1 = {
|
||||||
|
.cb = clock_on_callback,
|
||||||
|
.user_data = &executed1
|
||||||
|
};
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_OFF, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
err = clock_control_on(dev, NULL);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
/* wait for clock started. */
|
||||||
|
k_busy_wait(startup_us);
|
||||||
|
|
||||||
|
status = clock_control_get_status(dev, NULL);
|
||||||
|
zassert_equal(CLOCK_CONTROL_STATUS_ON, status,
|
||||||
|
"%s: Unexpected status (%d)", dev_name, status);
|
||||||
|
|
||||||
|
err = clock_control_async_on(dev, 0, &data1);
|
||||||
|
zassert_equal(0, err, "%s: Unexpected err (%d)", dev_name, err);
|
||||||
|
|
||||||
|
zassert_true(executed1, "%s: Expected flag to be false", dev_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_immediate_cb_when_clock_on(void)
|
||||||
|
{
|
||||||
|
test_all_instances(test_immediate_cb_when_clock_on_on_instance,
|
||||||
|
async_capable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_main(void)
|
||||||
|
{
|
||||||
|
ztest_test_suite(test_clock_control,
|
||||||
|
ztest_unit_test(test_on_off_status),
|
||||||
|
ztest_unit_test(test_multiple_users),
|
||||||
|
ztest_unit_test(test_async_on),
|
||||||
|
ztest_unit_test(test_async_on_stopped),
|
||||||
|
ztest_unit_test(test_immediate_cb_when_clock_on)
|
||||||
|
);
|
||||||
|
ztest_run_test_suite(test_clock_control);
|
||||||
|
}
|
10
tests/drivers/clock_control/clock_control_api/testcase.yaml
Normal file
10
tests/drivers/clock_control/clock_control_api/testcase.yaml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
tests:
|
||||||
|
peripheral.clock_control_nrf5:
|
||||||
|
tags: drivers
|
||||||
|
platform_whitelist: nrf51_pca10028 nrf52_pca10040 nrf52840_pca10056
|
||||||
|
nrf9160_pca10090
|
||||||
|
peripheral.clock_control_nrf5_lfclk_rc:
|
||||||
|
tags: drivers
|
||||||
|
platform_whitelist: nrf51_pca10028 nrf52_pca10040 nrf52840_pca10056
|
||||||
|
extra_args: CONF_FILE="nrf_lfclk_rc.conf"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue