@@ -56,6 +56,8 @@ static int spec_idx;
56
56
*/
57
57
struct spi_dt_spec spec_copies [5 ];
58
58
59
+
60
+
59
61
/*
60
62
********************
61
63
* SPI test buffers *
@@ -125,6 +127,64 @@ static void to_display_format(const uint8_t *src, size_t size, char *dst)
125
127
}
126
128
}
127
129
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
+
128
188
/* just a wrapper of the driver transceive call with ztest error assert */
129
189
static void spi_loopback_transceive (struct spi_dt_spec * const spec ,
130
190
const struct spi_buf_set * const tx ,
@@ -133,12 +193,15 @@ static void spi_loopback_transceive(struct spi_dt_spec *const spec,
133
193
int ret ;
134
194
135
195
zassert_ok (pm_device_runtime_get (spec -> bus ));
196
+ spi_loopback_gpio_cs_loopback_prepare ();
136
197
ret = spi_transceive_dt (spec , tx , rx );
137
198
if (ret == - EINVAL || ret == - ENOTSUP ) {
138
199
TC_PRINT ("Spi config invalid for this controller - skip\n" );
139
200
goto out ;
140
201
}
141
202
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 ));
142
205
out :
143
206
zassert_ok (pm_device_runtime_put (spec -> bus ));
144
207
}
@@ -820,6 +883,66 @@ ZTEST(spi_extra_api_features, test_spi_lock_release)
820
883
lock_spec -> config .operation &= ~SPI_LOCK_ON ;
821
884
}
822
885
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
+
823
946
/*
824
947
*************************
825
948
* Test suite definition *
@@ -859,6 +982,7 @@ static void run_after_lock(void *unused)
859
982
spi_release_dt (& spi_slow );
860
983
spi_slow .config .operation &= ~SPI_LOCK_ON ;
861
984
spi_fast .config .operation &= ~SPI_LOCK_ON ;
985
+ spi_slow .config .operation &= ~SPI_HOLD_ON_CS ;
862
986
}
863
987
864
988
ZTEST_SUITE (spi_loopback , NULL , spi_loopback_setup , NULL , NULL , run_after_suite );
@@ -891,6 +1015,8 @@ void test_main(void)
891
1015
K_PRIO_COOP (7 ), 0 , K_NO_WAIT );
892
1016
#endif
893
1017
1018
+ zassert_false (spi_loopback_gpio_cs_loopback_init ());
1019
+
894
1020
ztest_run_all (NULL , false, ARRAY_SIZE (loopback_specs ), 1 );
895
1021
896
1022
#if (CONFIG_SPI_ASYNC )
0 commit comments