|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Nordic Semiconductor ASA |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/kernel.h> |
| 8 | +#include <zephyr/drivers/spi.h> |
| 9 | +#include <zephyr/linker/devicetree_regions.h> |
| 10 | +#include <zephyr/devicetree/clocks.h> |
| 11 | +#include <zephyr/drivers/clock_control/nrf_clock_control.h> |
| 12 | +#include <zephyr/ztest.h> |
| 13 | + |
| 14 | +/* SPI MODE 0 */ |
| 15 | +#define SPI_MODE (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_LINES_SINGLE | SPI_TRANSFER_MSB) |
| 16 | + |
| 17 | +#define DUT_SPI_NODE DT_NODELABEL(dut_spi) |
| 18 | +#define TEST_BUFFER_SIZE 512 |
| 19 | +#define REQUEST_SERVING_WAIT_TIME_US 10000 |
| 20 | + |
| 21 | +static struct spi_dt_spec spim_spec = SPI_DT_SPEC_GET(DT_NODELABEL(dut_spi_dt), SPI_MODE, 0); |
| 22 | +const struct device *const fll16m_dev = DEVICE_DT_GET(DT_NODELABEL(fll16m)); |
| 23 | + |
| 24 | +#define MEMORY_SECTION(node) \ |
| 25 | + COND_CODE_1(DT_NODE_HAS_PROP(node, memory_regions), \ |
| 26 | + (__attribute__((__section__( \ |
| 27 | + LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(node, memory_regions)))))), \ |
| 28 | + ()) |
| 29 | + |
| 30 | +static uint8_t tx_buffer[TEST_BUFFER_SIZE] MEMORY_SECTION(DT_BUS(DT_NODELABEL(dut_spi_dt))); |
| 31 | +static uint8_t rx_buffer[TEST_BUFFER_SIZE] MEMORY_SECTION(DT_BUS(DT_NODELABEL(dut_spi_dt))); |
| 32 | + |
| 33 | +const struct nrf_clock_spec fll16m_open_loop_mode = { |
| 34 | + .frequency = MHZ(16), |
| 35 | + .accuracy = NRF_CLOCK_CONTROL_ACCURACY_PPM(20000), |
| 36 | + .precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, |
| 37 | +}; |
| 38 | + |
| 39 | +const struct nrf_clock_spec fll16m_bypass_mode = { |
| 40 | + .frequency = MHZ(16), |
| 41 | + .accuracy = NRF_CLOCK_CONTROL_ACCURACY_PPM(30), |
| 42 | + .precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, |
| 43 | +}; |
| 44 | + |
| 45 | +static void request_clock_spec(const struct device *clk_dev, const struct nrf_clock_spec *clk_spec) |
| 46 | +{ |
| 47 | + int ret = 0; |
| 48 | + int res = 0; |
| 49 | + struct onoff_client cli; |
| 50 | + uint32_t rate; |
| 51 | + |
| 52 | + TC_PRINT("Clock: %s, requesting frequency=%d, accuracy=%d, precision=%d\n", clk_dev->name, |
| 53 | + clk_spec->frequency, clk_spec->accuracy, clk_spec->precision); |
| 54 | + sys_notify_init_spinwait(&cli.notify); |
| 55 | + ret = nrf_clock_control_request(clk_dev, clk_spec, &cli); |
| 56 | + zassert_true((ret >= 0 && ret <= 2), |
| 57 | + "Clock control request response outside of range, ret = %d\n", ret); |
| 58 | + do { |
| 59 | + ret = sys_notify_fetch_result(&cli.notify, &res); |
| 60 | + k_yield(); |
| 61 | + } while (ret == -EAGAIN); |
| 62 | + zassert_ok(ret, "ret != 0, ret = %d\n", ret); |
| 63 | + zassert_ok(res, "ret != 0, ret = %d\n", res); |
| 64 | + ret = clock_control_get_rate(clk_dev, NULL, &rate); |
| 65 | + if (ret != -ENOSYS) { |
| 66 | + zassert_ok(ret, "ret != 0, ret = %d\n", ret); |
| 67 | + zassert_equal(rate, clk_spec->frequency, |
| 68 | + "Clock frequency != requested frequnecy\n"); |
| 69 | + k_busy_wait(REQUEST_SERVING_WAIT_TIME_US); |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +static void *test_setup(void) |
| 74 | +{ |
| 75 | + zassert_true(spi_is_ready_dt(&spim_spec), "SPIM device is not ready"); |
| 76 | + |
| 77 | + return NULL; |
| 78 | +} |
| 79 | + |
| 80 | +static void set_buffers(void) |
| 81 | +{ |
| 82 | + memset(tx_buffer, 0x8B, TEST_BUFFER_SIZE); |
| 83 | + memset(rx_buffer, 0xFF, TEST_BUFFER_SIZE); |
| 84 | +} |
| 85 | + |
| 86 | +static void test_spim_with_clock_control(void) |
| 87 | +{ |
| 88 | + int err; |
| 89 | + |
| 90 | + struct spi_buf tx_spi_buf = {.buf = tx_buffer, .len = TEST_BUFFER_SIZE}; |
| 91 | + struct spi_buf_set tx_spi_buf_set = {.buffers = &tx_spi_buf, .count = 1}; |
| 92 | + |
| 93 | + struct spi_buf rx_spi_buf = {.buf = rx_buffer, .len = TEST_BUFFER_SIZE}; |
| 94 | + struct spi_buf_set rx_spi_buf_set = {.buffers = &rx_spi_buf, .count = 1}; |
| 95 | + |
| 96 | + set_buffers(); |
| 97 | + |
| 98 | + err = spi_transceive_dt(&spim_spec, &tx_spi_buf_set, &rx_spi_buf_set); |
| 99 | + zassert_ok(err, "SPI transceive failed: %d\n", err); |
| 100 | + |
| 101 | + zassert_mem_equal(tx_buffer, rx_buffer, TEST_BUFFER_SIZE, "TX buffer != RX buffer\n"); |
| 102 | +} |
| 103 | + |
| 104 | +ZTEST(spim_clock_control, test_spim_with_clock_control_active_fll16m_open_loop) |
| 105 | +{ |
| 106 | + request_clock_spec(fll16m_dev, &fll16m_open_loop_mode); |
| 107 | + test_spim_with_clock_control(); |
| 108 | +} |
| 109 | + |
| 110 | +ZTEST(spim_clock_control, test_spim_with_clock_control_active_fll16m_bypass) |
| 111 | +{ |
| 112 | + request_clock_spec(fll16m_dev, &fll16m_bypass_mode); |
| 113 | + test_spim_with_clock_control(); |
| 114 | +} |
| 115 | + |
| 116 | +ZTEST_SUITE(spim_clock_control, NULL, test_setup, NULL, NULL, NULL); |
0 commit comments