Skip to content

Commit 74f3b7f

Browse files
decsnykartben
authored andcommitted
tests: spi_loopback: Add CS testing
Add test code to ensure CS is behaving properly in many different scenarios. Also add a test case for the SPI_HOLD_ON_CS flag in the API. Signed-off-by: Declan Snyder <[email protected]>
1 parent a627399 commit 74f3b7f

File tree

1 file changed

+126
-0
lines changed
  • tests/drivers/spi/spi_loopback/src

1 file changed

+126
-0
lines changed

tests/drivers/spi/spi_loopback/src/spi.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ static int spec_idx;
5656
*/
5757
struct spi_dt_spec spec_copies[5];
5858

59+
60+
5961
/*
6062
********************
6163
* SPI test buffers *
@@ -125,6 +127,64 @@ static void to_display_format(const uint8_t *src, size_t size, char *dst)
125127
}
126128
}
127129

130+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cs_loopback_gpios)
131+
132+
static const struct gpio_dt_spec cs_loopback_gpio =
133+
GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), cs_loopback_gpios, {0});
134+
static struct gpio_callback cs_cb_data;
135+
static K_SEM_DEFINE(cs_sem, 0, UINT_MAX);
136+
137+
static void spi_loopback_gpio_cs_loopback_prepare(void)
138+
{
139+
k_sem_reset(&cs_sem);
140+
}
141+
142+
static int spi_loopback_gpio_cs_loopback_check(int expected_triggers)
143+
{
144+
return k_sem_count_get(&cs_sem) != expected_triggers;
145+
}
146+
147+
static void cs_callback(const struct device *port,
148+
struct gpio_callback *cb,
149+
gpio_port_pins_t pins)
150+
{
151+
ARG_UNUSED(port);
152+
ARG_UNUSED(cb);
153+
ARG_UNUSED(pins);
154+
155+
/* Give semaphore to indicate CS triggered */
156+
k_sem_give(&cs_sem);
157+
}
158+
159+
static int spi_loopback_gpio_cs_loopback_init(void)
160+
{
161+
const struct gpio_dt_spec *gpio = &cs_loopback_gpio;
162+
int ret;
163+
164+
if (!gpio_is_ready_dt(gpio)) {
165+
return -ENODEV;
166+
}
167+
168+
ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
169+
if (ret) {
170+
return ret;
171+
}
172+
173+
ret = gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_EDGE_BOTH);
174+
if (ret) {
175+
return ret;
176+
}
177+
178+
gpio_init_callback(&cs_cb_data, cs_callback, BIT(gpio->pin));
179+
180+
return gpio_add_callback(gpio->port, &cs_cb_data);
181+
}
182+
#else
183+
#define spi_loopback_gpio_cs_loopback_init(...) (0)
184+
#define spi_loopback_gpio_cs_loopback_prepare(...)
185+
#define spi_loopback_gpio_cs_loopback_check(...) (0)
186+
#endif
187+
128188
/* just a wrapper of the driver transceive call with ztest error assert */
129189
static void spi_loopback_transceive(struct spi_dt_spec *const spec,
130190
const struct spi_buf_set *const tx,
@@ -133,12 +193,15 @@ static void spi_loopback_transceive(struct spi_dt_spec *const spec,
133193
int ret;
134194

135195
zassert_ok(pm_device_runtime_get(spec->bus));
196+
spi_loopback_gpio_cs_loopback_prepare();
136197
ret = spi_transceive_dt(spec, tx, rx);
137198
if (ret == -EINVAL || ret == -ENOTSUP) {
138199
TC_PRINT("Spi config invalid for this controller - skip\n");
139200
goto out;
140201
}
141202
zassert_ok(ret, "SPI transceive failed, code %d", ret);
203+
/* There should be two CS triggers during the transaction, start and end */
204+
zassert_false(spi_loopback_gpio_cs_loopback_check(2));
142205
out:
143206
zassert_ok(pm_device_runtime_put(spec->bus));
144207
}
@@ -820,6 +883,66 @@ ZTEST(spi_extra_api_features, test_spi_lock_release)
820883
lock_spec->config.operation &= ~SPI_LOCK_ON;
821884
}
822885

886+
ZTEST(spi_extra_api_features, test_spi_hold_on_cs)
887+
{
888+
const struct spi_buf_set tx = spi_loopback_setup_xfer(tx_bufs_pool, 1,
889+
buffer_tx, BUF_SIZE);
890+
const struct spi_buf_set rx = spi_loopback_setup_xfer(rx_bufs_pool, 1,
891+
NULL, BUF_SIZE);
892+
struct spi_dt_spec *hold_spec = &spi_slow;
893+
int ret = 0;
894+
895+
hold_spec->config.operation |= SPI_HOLD_ON_CS;
896+
897+
spi_loopback_gpio_cs_loopback_prepare();
898+
ret = spi_transceive_dt(hold_spec, &tx, &rx);
899+
if (ret == -ENOTSUP || ret == -EINVAL) {
900+
TC_PRINT("SPI hold on CS not supported");
901+
ret = 0;
902+
goto early_exit;
903+
} else if (ret) {
904+
goto early_exit;
905+
}
906+
/* Should get start assertion is 1 CS edge but no end */
907+
if (spi_loopback_gpio_cs_loopback_check(1)) {
908+
ret = -EIO;
909+
goto early_exit;
910+
}
911+
912+
spi_loopback_gpio_cs_loopback_prepare();
913+
ret = spi_transceive_dt(hold_spec, &tx, &rx);
914+
if (ret) {
915+
goto early_exit;
916+
}
917+
/* CS is already asserted, and we still have hold on, so no edges */
918+
if (spi_loopback_gpio_cs_loopback_check(0)) {
919+
ret = -EIO;
920+
goto early_exit;
921+
}
922+
923+
hold_spec->config.operation &= ~SPI_HOLD_ON_CS;
924+
925+
spi_loopback_gpio_cs_loopback_prepare();
926+
ret = spi_transceive_dt(hold_spec, &tx, &rx);
927+
if (ret) {
928+
goto early_exit;
929+
}
930+
/* This time we don't have hold flag but it starts held, so only end trigger */
931+
if (spi_loopback_gpio_cs_loopback_check(1)) {
932+
ret = -EIO;
933+
goto early_exit;
934+
}
935+
936+
/* now just do a normal transfer to make sure there was no leftover effects */
937+
spi_loopback_transceive(hold_spec, &tx, &rx);
938+
939+
return;
940+
941+
early_exit:
942+
hold_spec->config.operation &= ~SPI_HOLD_ON_CS;
943+
zassert_false(ret, "SPI transceive failed, code %d", ret);
944+
}
945+
823946
/*
824947
*************************
825948
* Test suite definition *
@@ -859,6 +982,7 @@ static void run_after_lock(void *unused)
859982
spi_release_dt(&spi_slow);
860983
spi_slow.config.operation &= ~SPI_LOCK_ON;
861984
spi_fast.config.operation &= ~SPI_LOCK_ON;
985+
spi_slow.config.operation &= ~SPI_HOLD_ON_CS;
862986
}
863987

864988
ZTEST_SUITE(spi_loopback, NULL, spi_loopback_setup, NULL, NULL, run_after_suite);
@@ -891,6 +1015,8 @@ void test_main(void)
8911015
K_PRIO_COOP(7), 0, K_NO_WAIT);
8921016
#endif
8931017

1018+
zassert_false(spi_loopback_gpio_cs_loopback_init());
1019+
8941020
ztest_run_all(NULL, false, ARRAY_SIZE(loopback_specs), 1);
8951021

8961022
#if (CONFIG_SPI_ASYNC)

0 commit comments

Comments
 (0)